Microsoft Font Subsetting
Windows fonts are a file format that I find very diverse, since the kernel-mode count user-mode has a font processing component. P0 public talks about fuzzing fonts of windows [5] [6], all of them are very clear and quality. In the font-related errors that P0 finds, I pay attention to the fontsub.dll library.
Up to the time of P0 public bugs of this library, no one has previously tried fuzz into the fontsub.dll library.
The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D.
The DLL exports two API functions: CreateFontPackage [7] and MergeFontPackage [8].
unsigned long CreateFontPackage(
const unsigned char *puchSrcBuffer,
const unsigned long ulSrcBufferSize,
unsigned char
**ppuchFontPackageBuffer,
unsigned long
*pulFontPackageBufferSize,
unsigned long
*pulBytesWritten,
const unsigned short usFlag,
const unsigned short usTTCIndex,
const unsigned short usSubsetFormat,
const unsigned short usSubsetLanguage,
const unsigned short usSubsetPlatform,
const unsigned short usSubsetEncoding,
const unsigned short *pusSubsetKeepList,
const unsigned short usSubsetListCount,
CFP_ALLOCPROC
lpfnAllocate,
CFP_REALLOCPROC
lpfnReAllocate,
CFP_FREEPROC
lpfnFree,
void
*lpvReserved
); |
unsigned long MergeFontPackage(
const unsigned char *puchMergeFontBuffer,
const unsigned long ulMergeFontBufferSize,
const unsigned char *puchFontPackageBuffer,
const unsigned long ulFontPackageBufferSize,
unsigned char
**ppuchDestBuffer,
unsigned long
*pulDestBufferSize,
unsigned long
*pulBytesWritten,
const unsigned short usMode,
CFP_ALLOCPROC
lpfnAllocate,
CFP_REALLOCPROC
lpfnReAllocate,
CFP_FREEPROC
lpfnFree,
void
*lpvReserved
);
|
P0 also publishes the harness they built [9], it's very good, covers all the parameters passed to these two functions. I use that harness to fuzz.
In addition to harness, P0 has a public tool that supports TTF/OTF [10] mutate files, this is a tool that I think is the key to help P0 find many bugs with such fonts.
Based on these, I began to find and create copus:
1. Corpus from P0 public with previously published bugs + download on the internet
2. Mutate these corpus based on the tool of P0
3. Use winafl-cmin to reduce the number of corpus
4. Check coverage
5. Return to step 2
I do this task over and over again until the coverage I achieve with fontsub.dll is as follows:
With a test case, I can mutate 53.22% on DLL fontsub.dll, 81.08% for CreateFontPackage and 76.40% for MergeFontPackage. I think this is enough to start fuzz.
I used Winafl to run with 1 master and 7 slaves, after a few hours I started seeing the first crashes. After a few days, I went back and started checking for those crashes.
Most of them are stack overflow errors (0xc00000fd):
And there is also a crash which, in my opinion, is quite similar to an error that P0 report earlier that Microsoft has fixed [13].
According to the google timeline, the bug fix was fixed in August 2019, but I did fuzz it and the bug persisted until January 2020 (the moment I reported it to Microsoft).
I am not surprised that Microsoft has not completely fixed the bug, but this P0 public project has not been used by anyone to find bugs.
Conclusion
This bug is not hard to find, everything is available in front of you but no one jumped into it. You can see that the steps I showed are clearly presented in the previous article, all the basic knowledge that you do not have to use reverse much to write harness. Microsoft's documentation is very complete, please read it, learn it, and try it out. If I just stopped reading the blog then I think it will not bring much results.
Error when fuzz file format of windows appears less and less. Because this way is quite a lot of users, it requires you to spend a lot of time researching for new surface attacks, file formats that have not been studied in order to be able to spot bugs.
The following blog will talk about a file format bug that Microsoft rewarded me with max bounty in Windows Insider Preview Bounty. Maybe I'll publish it after Microsoft's T6/2020 patch is released or longer.
[1] https://googleprojectzero.blogspot.com/
[2] https://portal.msrc.microsoft.com/en-us/security-guidance/acknowledgments
[3] https://docs.microsoft.com/en-us/
[4] https://github.com/microsoft/Windows-classic-samples
[5] https://googleprojectzero.blogspot.com/2016/06/a-year-of-windows-kernel-font-fuzzing-1_27.html
[6] https://googleprojectzero.blogspot.com/2016/07/a-year-of-windows-kernel-font-fuzzing-2.html
[7] https://docs.microsoft.com/en-us/windows/win32/api/fontsub/nf-fontsub-createfontpackage
[8] https://docs.microsoft.com/en-us/windows/win32/api/fontsub/nf-fontsub-mergefontpackage
[9] https://github.com/googleprojectzero/BrokenType/tree/master/ttf-fontsub-loader
[10] https://github.com/googleprojectzero/BrokenType/tree/master/ttf-otf-mutator
[11] https://bugs.chromium.org/p/project-zero/issues/detail?id=1863
[12] https://bugs.chromium.org/p/project-zero/issues/detail?id=1866
[13] https://bugs.chromium.org/p/project-zero/issues/detail?id=1868
-------
Vietnamese version
Tiếp tục seri về fuzzing, phần này tôi sẽ chia sẻ cách tôi tìm kiếm
attack surface trên windows để fuzz. Trên windows xử lý rất nhiều định
dạng file, tìm hiểu và fuzz các định dạng file này là một hướng phổ biến
để tìm được bug trên windows hiện nay. Cách tiếp cận và fuzz hoàn toàn
giống như tìm lỗi ở Irfanview tôi đã trình bày ở phần trước.
Có lẽ sẽ có nhiều người tự nhủ làm thế nào mà có thể tìm được attack
surface? Đơn giản sẽ như thế này khi bạn nghiên cứu một cái gì đó đủ lâu,
đủ sâu bạn sẽ thấy được những hướng có thể tấn công vào nó. Nghe thì thật
khó khi đặt tình huống này vào phần lớn người mới bắt đầu vì không phải ai
cũng giỏi và xuất sắc như thế. Tuy nhiên có một điều thú vị ở đây là có
rất nhiều nhà nghiên cứu giỏi họ sẵn sàng chia sẻ mọi thứ mà họ nghiên cứu
cũng như bug họ tìm được cho cộng đồng. Google Project Zero (P0) [1] là
một ví dụ, tôi xem và theo dõi các bug được public trên đó (kể cả những
bug cách đây rất lâu). Từ đó tôi biết được các loại bug, các attack
surface, các thành phần thường gây ra lỗi trên các nền tảng khác nhau,…
Hoặc đơn giản hơn hàng tháng tôi vẫn theo dõi các bản vá từ Microsoft [2]
và xem các bug được vá có gì thú vị và phù hợp với hướng fuzzing của tôi
hay không.
Introduction
Quay trở lại nói về fuzz các định dạng file trên windows, như chúng ta
biết trên windows có rất nhiều dll, mỗi dll sẽ có một nhiệm vụ riêng biệt.
Đối với tôi, hiện tại tôi sẽ chỉ tập trung vào những DLL có nhiệm vụ xử lý
các định dạng file. Một số định dạng file phổ biến như media: audio,
video, ảnh,… hoặc một số định dạng file khác như XML, XPS, PDF, registry…
Các DLL này sẽ export ra các API cho các developer sử dụng để xây dựng các
ứng dụng trên windows, và các thành phần built in của Windows cũng sử dụng
những API này.
Bản thân Microsoft đã cung cấp cho chúng ta MSDN [3], đó là một kho tài
liệu để ta có thể đọc, tìm hiểu về cách sử dụng các API đó. Không những có
document về API mà Microsoft còn hào phóng cho chúng ta rất nhiều code
mẫu. Tôi thường tham khảo tại repo github của Microsoft [4]. Nó giúp chúng
ta rất nhiều trong việc xây dựng harness để fuzz các định dạng file trên
windows.
Microsoft Font Subsetting
Phông chữ của windows là một định dạng file tôi thấy rất đa dạng, từ
usermode đếm kernelmode đều có thành phần xử lý phông chữ. P0 public rất
nhiều bài nói về fuzzing phông chữ của windows [5] [6], những bài đó đều
rất rõ ràng và chất lượng. Trong các lỗi liên quan đến phông chữ mà P0 tìm
ra, tôi chú ý đến thư viện fontsub.dll.
Tính tới thời điểm P0 public các lỗi của thư viện này thì trước đó chưa
có ai thử fuzz vào thư viện fontsub.dll.
Fontub.dll là một thư viện tạo, gom nhóm các phông chữ TTF, nó có thể
chuyển đổi phông chữ thành các phiên bản nhỏ gọn hơn dựa trên các glyph và
được sử dụng trong các file tài liệu như docx, ppt, pdf,… có phông chữ
được nhúng. Nó cũng được Windows GDI và Direct2D sử dụng.
DLL export hai hàm API: CreateFontPackage [7] và MergeFontPackage [8].
unsigned long CreateFontPackage(
const unsigned char *puchSrcBuffer,
const unsigned long ulSrcBufferSize,
unsigned char
**ppuchFontPackageBuffer,
unsigned long
*pulFontPackageBufferSize,
unsigned long
*pulBytesWritten,
const unsigned short usFlag,
const unsigned short usTTCIndex,
const unsigned short usSubsetFormat,
const unsigned short usSubsetLanguage,
const unsigned short usSubsetPlatform,
const unsigned short usSubsetEncoding,
const unsigned short *pusSubsetKeepList,
const unsigned short usSubsetListCount,
CFP_ALLOCPROC
lpfnAllocate,
CFP_REALLOCPROC
lpfnReAllocate,
CFP_FREEPROC
lpfnFree,
void
*lpvReserved
); |
unsigned long MergeFontPackage(
const unsigned char *puchMergeFontBuffer,
const unsigned long ulMergeFontBufferSize,
const unsigned char *puchFontPackageBuffer,
const unsigned long ulFontPackageBufferSize,
unsigned char
**ppuchDestBuffer,
unsigned long
*pulDestBufferSize,
unsigned long
*pulBytesWritten,
const unsigned short usMode,
CFP_ALLOCPROC
lpfnAllocate,
CFP_REALLOCPROC
lpfnReAllocate,
CFP_FREEPROC
lpfnFree,
void
*lpvReserved
);
|
Ngoài harness, P0 còn public tool hỗ trợ mutate file TTF/OTF [10], đây là
một tool tôi nghĩ nó là chìa khóa giúp P0 có thể tìm được nhiều lỗi với
phông chữ như thế.
Dựa vào những thứ đó, tôi bắt đầu tìm và tạo copus:
1. Corpus từ P0 public kèm các lỗi đã public từ trước + download trên
internet
2. Mutate các corpus này dựa theo tool của P0
3. Dùng winafl-cmin để giảm số lượng corpus xuống
4. Kiểm tra coverage
5. Quay lại bước 2
Tôi làm công việc này lặp đi lặp lại đến khi coverage tôi đạt được với
fontsub.dll như say:
Với 1 testcase tôi mutate ra có thể đạt 53.22% trên DLL fontsub.dll,
81.08% đối với hàm CreateFontPackage và 76.40% đối với hàm
MergeFontPackage. Tôi nghĩ thế này là đủ để có thể bắt đầu fuzz.
Tôi sử dụng winafl chạy với 1 master và 7 slave, sau một vài tiếng tôi
bắt đầu thấy các crash đầu tiên. Sau một vài ngày tôi quay lại và bắt đầu
kiểm tra các crash đó.
Phần lớn đều là lỗi stack overflow (0xc00000fd):
Xuất hiện 2 lỗi mà P0 report trước đó mà Microsoft không fix
[11][12].
Và còn xuất hiện 1 crash mà theo tôi thấy thì khá giống với một lỗi mà P0 report trước đó mà Microsoft đã fix [13].
Tôi report và Microsoft đã chấp nhận sửa lỗi này. Có vẻ đây là một biến
thể với lỗi mà Microsoft đã fix trước đó. Lỗi được sửa trong bản vá
T4/2020 (CVE-2020-0687), đây là bài phân tích root cause của lỗi này tôi
viết, mọi người có thể đọc thử [14] (trong bài viết bạn chỉ nên chú ý phần
phân tích lỗi này, phần impact không phải do tôi tự viết, tất nhiên với
những lỗi như thế này trong thực tế không thể có 1 full exploit).
Theo timeline google đưa ra bug này đã được fix vào tháng 8/2019, tuy
nhiên tôi đã fuzz bản vá đó và lỗi đó vẫn tồn tại đến tận T1/2020 (thời
điểm tôi report cho Microsoft).
Tôi không bất ngờ về việc Microsoft fix không hết bug, mà P0 public
project này từ rất lâu rồi mà không hề có ai đó thử sử dụng để tìm
bug.
Conclusion
Bug này không phải là khó tìm, mọi thứ đều ở sẵn trước mặt nhưng lại
không có ai nhảy vào làm. Bạn có thể thấy các bước tôi làm đều trình bày
rõ ở trong bài viết trước, đều là các kiến thức cơ bản bạn chưa phải sử
dụng reverse nhiều để có thể viết được harness. Document của Microsoft rất
đầy đủ, hãy chịu khó đọc, tìm hiểu và bắt tay vào làm thử. Nếu chỉ dừng
lại ở việc đọc blog thì tôi nghĩ sẽ không mang lại nhiều kết quả.
Các lỗi khi fuzz định dạng file của windows xuất hiện càng ngày càng ít.
Do cách này khá nhiều người sử dụng, đòi hỏi bạn phải bỏ nhiều thời gian
để nghiên cứu tìm các attack surface mới, các định dạng file chưa ai
nghiên cứu thì mới có thể ra được bug.
Blog sau tôi sẽ nói về bug của một định dạng file mà Microsoft đã thưởng cho tôi max bounty ở Windows Insider Preview Bounty. Có lẽ tôi sẽ public nó sau khi bản vá T6/2020 của Microsoft được release hoặc lâu hơn nữa.
[1] https://googleprojectzero.blogspot.com/
[2] https://portal.msrc.microsoft.com/en-us/security-guidance/acknowledgments
[3] https://docs.microsoft.com/en-us/
[4] https://github.com/microsoft/Windows-classic-samples
[5] https://googleprojectzero.blogspot.com/2016/06/a-year-of-windows-kernel-font-fuzzing-1_27.html
[6] https://googleprojectzero.blogspot.com/2016/07/a-year-of-windows-kernel-font-fuzzing-2.html
[7] https://docs.microsoft.com/en-us/windows/win32/api/fontsub/nf-fontsub-createfontpackage
[8] https://docs.microsoft.com/en-us/windows/win32/api/fontsub/nf-fontsub-mergefontpackage
[9] https://github.com/googleprojectzero/BrokenType/tree/master/ttf-fontsub-loader
[10] https://github.com/googleprojectzero/BrokenType/tree/master/ttf-otf-mutator
[11] https://bugs.chromium.org/p/project-zero/issues/detail?id=1863
[12] https://bugs.chromium.org/p/project-zero/issues/detail?id=1866
[13] https://bugs.chromium.org/p/project-zero/issues/detail?id=1868