
1979 changes to exploits/shellcodes Couchdb 1.5.0 - 'uuids' Denial of Service Apache CouchDB 1.5.0 - 'uuids' Denial of Service Beyond Remote 2.2.5.3 - Denial of Service (PoC) udisks2 2.8.0 - Denial of Service (PoC) Termite 3.4 - Denial of Service (PoC) SoftX FTP Client 3.3 - Denial of Service (PoC) Silverstripe 2.3.5 - Cross-Site Request Forgery / Open redirection SilverStripe CMS 2.3.5 - Cross-Site Request Forgery / Open Redirection Silverstripe CMS 3.0.2 - Multiple Vulnerabilities SilverStripe CMS 3.0.2 - Multiple Vulnerabilities Silverstripe CMS 2.4 - File Renaming Security Bypass SilverStripe CMS 2.4 - File Renaming Security Bypass Silverstripe CMS 2.4.5 - Multiple Cross-Site Scripting Vulnerabilities SilverStripe CMS 2.4.5 - Multiple Cross-Site Scripting Vulnerabilities Silverstripe CMS 2.4.7 - 'install.php' PHP Code Injection SilverStripe CMS 2.4.7 - 'install.php' PHP Code Injection Silverstripe Pixlr Image Editor - 'upload.php' Arbitrary File Upload SilverStripe CMS Pixlr Image Editor - 'upload.php' Arbitrary File Upload Silverstripe CMS 2.4.x - 'BackURL' Open Redirection SilverStripe CMS 2.4.x - 'BackURL' Open Redirection Silverstripe CMS - 'MemberLoginForm.php' Information Disclosure SilverStripe CMS - 'MemberLoginForm.php' Information Disclosure Silverstripe CMS - Multiple HTML Injection Vulnerabilities SilverStripe CMS - Multiple HTML Injection Vulnerabilities Apache CouchDB 1.7.0 and 2.x before 2.1.1 - Remote Privilege Escalation Apache CouchDB 1.7.0 / 2.x < 2.1.1 - Remote Privilege Escalation Monstra CMS before 3.0.4 - Cross-Site Scripting Monstra CMS < 3.0.4 - Cross-Site Scripting (2) Monstra CMS < 3.0.4 - Cross-Site Scripting Monstra CMS < 3.0.4 - Cross-Site Scripting (1) Navigate CMS 2.8 - Cross-Site Scripting Collectric CMU 1.0 - 'lang' SQL injection Joomla! Component CW Article Attachments 1.0.6 - 'id' SQL Injection LG SuperSign EZ CMS 2.5 - Remote Code Execution MyBB Visual Editor 1.8.18 - Cross-Site Scripting Joomla! Component AMGallery 1.2.3 - 'filter_category_id' SQL Injection Joomla! Component Micro Deal Factory 2.4.0 - 'id' SQL Injection RICOH Aficio MP 301 Printer - Cross-Site Scripting Joomla! Component Auction Factory 4.5.5 - 'filter_order' SQL Injection RICOH MP C6003 Printer - Cross-Site Scripting Linux/ARM - Egghunter (PWN!) + execve(_/bin/sh__ NULL_ NULL) Shellcode (28 Bytes) Linux/ARM - sigaction() Based Egghunter (PWN!) + execve(_/bin/sh__ NULL_ NULL) Shellcode (52 Bytes)
131 lines
No EOL
6.5 KiB
Text
131 lines
No EOL
6.5 KiB
Text
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=749
|
|
|
|
The following crash due to a heap-based buffer overflow can be observed in a slightly modified ASAN build of the standard Graphite2 gr2FontTest utility (git trunk), triggered with the following command:
|
|
|
|
$ ./gr2fonttest /path/to/file text
|
|
|
|
My change in gr2FontTest was to hardcode the tested text to include all characters in the 0x1..0xfff range, instead of having to specify them in command line. The patch is as follows:
|
|
|
|
--- cut ---
|
|
--- graphite_original/gr2fonttest/gr2FontTest.cpp 2016-02-27 19:35:16.308071127 +0100
|
|
+++ graphite/gr2fonttest/gr2FontTest.cpp 2016-02-26 13:57:13.389186376 +0100
|
|
@@ -437,7 +437,17 @@
|
|
if (mainArgOffset < 1) argError = true;
|
|
else if (mainArgOffset > 1)
|
|
{
|
|
- if (!useCodes && pText != NULL)
|
|
+ const unsigned int kCodeLimit = 0x1000;
|
|
+
|
|
+ charLength = kCodeLimit - 1;
|
|
+
|
|
+ pText32 = (unsigned int *)malloc(sizeof(unsigned int) * kCodeLimit);
|
|
+ for (unsigned int i = 1; i < kCodeLimit; ++i) {
|
|
+ pText32[i - 1] = i;
|
|
+ }
|
|
+ pText32[kCodeLimit - 1] = 0;
|
|
+
|
|
+ /*if (!useCodes && pText != NULL)
|
|
{
|
|
charLength = convertUtf<gr2::utf8>(pText, pText32);
|
|
if (!pText32)
|
|
@@ -466,7 +476,7 @@
|
|
{
|
|
pText32[charLength] = 0;
|
|
fprintf(log, "\n");
|
|
- }
|
|
+ }*/
|
|
}
|
|
return (argError) ? false : true;
|
|
}
|
|
--- cut ---
|
|
|
|
The resulting ASAN crash is as follows:
|
|
|
|
--- cut ---
|
|
==27575==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000efd0 at pc 0x00000055daad bp 0x7ffdfb0bfe90 sp 0x7ffdfb0bfe88
|
|
WRITE of size 8 at 0x60200000efd0 thread T0
|
|
#0 0x55daac in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int) graphite/src/GlyphCache.cpp:133:20
|
|
#1 0x549503 in graphite2::Face::readGlyphs(unsigned int) graphite/src/Face.cpp:98:29
|
|
#2 0x56d3f4 in (anonymous namespace)::load_face(graphite2::Face&, unsigned int) graphite/src/gr_face.cpp:54:14
|
|
#3 0x56cf04 in gr_make_face_with_ops graphite/src/gr_face.cpp:89:16
|
|
#4 0x56f240 in gr_make_file_face graphite/src/gr_face.cpp:242:23
|
|
#5 0x4ec193 in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ec193)
|
|
#6 0x4ef595 in main (graphite/gr2fonttest/gr2fonttest+0x4ef595)
|
|
|
|
0x60200000efd1 is located 0 bytes to the right of 1-byte region [0x60200000efd0,0x60200000efd1)
|
|
allocated by thread T0 here:
|
|
#0 0x4b86dc in calloc llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:56
|
|
#1 0x56ac8a in graphite2::GlyphFace const** graphite2::grzeroalloc<graphite2::GlyphFace const*>(unsigned long) graphite/src/./inc/Main.h:96:28
|
|
#2 0x55cb26 in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int) graphite/src/GlyphCache.cpp:119:45
|
|
#3 0x549503 in graphite2::Face::readGlyphs(unsigned int) graphite/src/Face.cpp:98:29
|
|
#4 0x56d3f4 in (anonymous namespace)::load_face(graphite2::Face&, unsigned int) graphite/src/gr_face.cpp:54:14
|
|
#5 0x56cf04 in gr_make_face_with_ops graphite/src/gr_face.cpp:89:16
|
|
#6 0x56f240 in gr_make_file_face graphite/src/gr_face.cpp:242:23
|
|
#7 0x4ec193 in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ec193)
|
|
#8 0x4ef595 in main (graphite/gr2fonttest/gr2fonttest+0x4ef595)
|
|
|
|
SUMMARY: AddressSanitizer: heap-buffer-overflow graphite/src/GlyphCache.cpp:133:20 in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int)
|
|
Shadow bytes around the buggy address:
|
|
0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
=>0x0c047fff9df0: fa fa 00 fa fa fa 01 fa fa fa[01]fa fa fa 00 04
|
|
0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
Shadow byte legend (one shadow byte represents 8 application bytes):
|
|
Addressable: 00
|
|
Partially addressable: 01 02 03 04 05 06 07
|
|
Heap left redzone: fa
|
|
Heap right redzone: fb
|
|
Freed heap region: fd
|
|
Stack left redzone: f1
|
|
Stack mid redzone: f2
|
|
Stack right redzone: f3
|
|
Stack partial redzone: f4
|
|
Stack after return: f5
|
|
Stack use after scope: f8
|
|
Global redzone: f9
|
|
Global init order: f6
|
|
Poisoned by user: f7
|
|
Container overflow: fc
|
|
Array cookie: ac
|
|
Intra object redzone: bb
|
|
ASan internal: fe
|
|
Left alloca redzone: ca
|
|
Right alloca redzone: cb
|
|
==27575==ABORTING
|
|
--- cut ---
|
|
|
|
A cursory analysis shows that the direct reason of the crash is the wrong assumption made by GlyphCache::GlyphCache() that the _num_glyphs field is always greater than 0. A buffer is allocated in line 128:
|
|
|
|
--- cut ---
|
|
128 GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
|
|
--- cut ---
|
|
|
|
And regardless of the _num_glyphs value, data is written to its first entry in line 133:
|
|
|
|
--- cut ---
|
|
132 // The 0 glyph is definately required.
|
|
133 _glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0], &numsubs);
|
|
--- cut ---
|
|
|
|
While this could just end as an off-by-one error and a fixed ~8 byte overflow, it gets worse. The subsequent loop in lines 139-140 also assumes that _num_glyphs is non-zero, and additionally wrongly (in the context of the misassumption) uses the != operator instead of < in the loop end condition:
|
|
|
|
--- cut ---
|
|
138 const GlyphFace * loaded = _glyphs[0];
|
|
139 for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
|
|
140 _glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
|
|
--- cut ---
|
|
|
|
This essentially means that the size of the overflown area is fully controlled by an attacker; it must only be a multiple of the native word size: typically 4 or 8 bytes.
|
|
|
|
The bug was reported at https://bugzilla.mozilla.org/show_bug.cgi?id=1251869. Attached are three font files which trigger the crash.
|
|
|
|
|
|
Proof of Concept:
|
|
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/39859.zip |