gdb
is useful for us to understand how a given binary works.
Let's see what this program does...
$> gdb ./level5
(gdb) disassemble main
Dump of assembler code for function main:
0x08048504 <+0>: push %ebp
0x08048505 <+1>: mov %esp,%ebp
0x08048507 <+3>: and $0xfffffff0,%esp
0x0804850a <+6>: call 0x80484c2 <n>
0x0804850f <+11>: leave
0x08048510 <+12>: ret
End of assembler dump.
This
main()
only calls an()
function.
As shown in the main()
function another one is called, let's disasssemble it as well.
$> gdb ./level5
(gdb) disassemble n
Dump of assembler code for function n:
0x080484c2 <+0>: push %ebp
0x080484c3 <+1>: mov %esp,%ebp
0x080484c5 <+3>: sub $0x218,%esp
0x080484cb <+9>: mov 0x8049848,%eax
0x080484d0 <+14>: mov %eax,0x8(%esp)
0x080484d4 <+18>: movl $0x200,0x4(%esp)
0x080484dc <+26>: lea -0x208(%ebp),%eax
0x080484e2 <+32>: mov %eax,(%esp)
0x080484e5 <+35>: call 0x80483a0 <fgets@plt>
0x080484ea <+40>: lea -0x208(%ebp),%eax
0x080484f0 <+46>: mov %eax,(%esp)
0x080484f3 <+49>: call 0x8048380 <printf@plt>
0x080484f8 <+54>: movl $0x1,(%esp)
0x080484ff <+61>: call 0x80483d0 <exit@plt>
End of assembler dump.
Let's also check the list of available functions...
$> gdb ./level5
(gdb) info functions
All defined functions:
Non-debugging symbols:
0x08048334 _init
0x08048380 printf
0x08048380 printf@plt
0x08048390 _exit
0x08048390 _exit@plt
0x080483a0 fgets
0x080483a0 fgets@plt
0x080483b0 system
0x080483b0 system@plt
0x080483c0 __gmon_start__
0x080483c0 __gmon_start__@plt
0x080483d0 exit
0x080483d0 exit@plt
0x080483e0 __libc_start_main
0x080483e0 __libc_start_main@plt
0x080483f0 _start
0x08048420 __do_global_dtors_aux
0x08048480 frame_dummy
0x080484a4 o
0x080484c2 n
0x08048504 main
0x08048520 __libc_csu_init
0x08048590 __libc_csu_fini
0x08048592 __i686.get_pc_thunk.bx
0x080485a0 __do_global_ctors_aux
0x080485cc _fini
We can see that an
o()
function is registered but never called during program execution.
Disassembling o()
gives us the following:
$> gdb ./level5
(gdb) disassemble o
Dump of assembler code for function o:
0x080484a4 <+0>: push %ebp
0x080484a5 <+1>: mov %esp,%ebp
0x080484a7 <+3>: sub $0x18,%esp
0x080484aa <+6>: movl $0x80485f0,(%esp)
0x080484b1 <+13>: call 0x80483b0 <system@plt>
0x080484b6 <+18>: movl $0x1,(%esp)
0x080484bd <+25>: call 0x8048390 <_exit@plt>
End of assembler dump.
0x080484aa <+6>: movl $0x80485f0,(%esp)
(gdb) x/s 0x80485f0
0x80485f0: "/bin/sh"
The string /bin/sh
is stored at address 0x80485f0
.
0x080484dc <+26>: lea -0x208(%ebp),%eax
(gdb) print 0x208
$1 = 520
There is a buffer of size 520 in n()
.
0x080484d4 <+18>: movl $0x200,0x4(%esp)
(gdb) print 0x200
$1 = 512
This instruction represent the maximum bytes read by fgets()
in n()
which is 512. Inportant to note that this is less than the size of the buffer in which we'll store the result meaning no buffer overflow is possible here.