Tut01: GDB/x86
IOLI-crackme
Did you successfully connect to the CTF server? Let's play with a binary.
We prepared four binaries. The goal is very simple: find a password that each binary accepts. Before tackling this week's challenges, you will learn how to use GDB, how to read x86 assembly, and a hacker's mindset!
We highly recommend to tackle crackme binaries first (at least upto 0x04) before jumping into the bomblab. In bomblab, if you make a mistake (i.e., exploding the bomb), you will get some deduction.
In this tutorial, we walk together to solve two binaries.
crackme0x00
# login to the CTF server
# ** check Canvas for login information! **
[host] $ ssh lab01@<ctf-server-address>
# let's start lab01!
[CTF server] $ cat README
[CTF server] $ cd tut01-crackme
Where to start? There are many ways to start:
-
reading the whole binary first (e.g., try
objdump -M intel -d crackme0x00
); -
starting with a gdb session (e.g.,
gdb ./crackme0x00
) and setting a breakpoint on a well-known entry (e.g., luckilymain()
is exposed, trynm crackme0x00
); -
run
./crackme0x00
first (waiting on the "Password" prompt) and attach it to gdb (e.g.,gdb -p $(pgrep crackme0x00)
); -
or just running with gdb then press
C-c
(i.e., sending a SIGINT signal).
Let's take 4. as an example
$ gdb ./crackme0x00
Reading symbols from ./crackme0x00...(no debugging symbols found)...done.
(gdb) r
[r]un
: run a program, please check help run
Starting program: /home/lab01/tut01-crackme/crackme0x00
IOLI Crackme Level 0x00
Password: ^C
press ctrl+C (^C)
to send a signal to stop the process
Program received signal SIGINT, Interrupt.
0xf7fd8d09 in __kernel_vsyscall ()
(gdb) bt
#0 0xf7fd5079 in __kernel_vsyscall ()
#1 0xf7ecbdf7 in __GI___libc_read (fd=0, buf=0x804b570, nbytes=1024) at ../sysdeps/unix/sysv/linux/read.c:27
#2 0xf7e58258 in _IO_new_file_underflow (fp=<optimized out>) at fileops.c:531
#3 0xf7e5937b in __GI__IO_default_uflow (fp=0xf7fbd5c0 <_IO_2_1_stdin_>) at genops.c:380
#4 0xf7e3ccb1 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=<optimized out>, errp=<optimized out>) at vfscanf.c:630
#5 0xf7e47e25 in __scanf (format=0x80487f1 "%s") at scanf.c:33
#6 0x080486d1 in main (argc=1, argv=0xffffd6c4) at crackme0x00.c:14
[bt]
: print backtrace (e.g., stack frames). Again, don't forget to check help bt
(gdb) tbreak *0x080486d1
Temporary breakpoint 1 at 0x080492fa
set a (temporary) breakpoint (help b, tb, rb
) to the call site (next)
of the scanf()
, which is potentially the most interesting part.
(gdb) c
Continuing.
aaaaaaaaaaaaaaaaaaaaaaaa
[c]ontinue
to run the process, type aaaaaaaaaaaaaa
(inject a random input)
Temporary breakpoint 1, 0x080492fa in main ()
ok, it hits the breakpoint, let check the context
[disas]semble
: dump the assembly code in the current scope
(gdb) set disassembly-flavor intel
(gdb) disas
0x080486a3 <+0>: push ebp
0x080486a4 <+1>: mov ebp,esp
0x080486a6 <+3>: sub esp,0x10
0x080486a9 <+6>: push 0x80487f4
0x080486ae <+11>: call 0x8048470 <puts@plt>
0x080486b3 <+16>: add esp,0x4
0x080486b6 <+19>: push 0x804880c
0x080486bb <+24>: call 0x8048430 <printf@plt>
0x080486c0 <+29>: add esp,0x4
0x080486c3 <+32>: lea eax,[ebp-0x10]
0x080486c6 <+35>: push eax
0x080486c7 <+36>: push 0x80487f1
0x080486cc <+41>: call 0x8048480 <scanf@plt>
=> 0x080486d1 <+46>: add esp,0x8
0x080486d4 <+49>: push 0x8048817
0x080486d9 <+54>: lea eax,[ebp-0x10]
0x080486dc <+57>: push eax
0x080486dd <+58>: call 0x8048420 <strcmp@plt>
0x080486e2 <+63>: add esp,0x8
0x080486e5 <+66>: test eax,eax
0x080486e7 <+68>: jne 0x8048705 <main+98>
0x080486e9 <+70>: push 0x804881e
0x080486ee <+75>: call 0x8048470 <puts@plt>
0x080486f3 <+80>: add esp,0x4
0x080486f6 <+83>: push 0x804882d
0x080486fb <+88>: call 0x80485f6 <print_key>
0x08048700 <+93>: add esp,0x4
0x08048703 <+96>: jmp 0x8048712 <main+111>
0x08048705 <+98>: push 0x804883c
0x0804870a <+103>: call 0x8048470 <puts@plt>
0x0804870f <+108>: add esp,0x4
0x08048712 <+111>: mov eax,0x0
0x08048717 <+116>: leave
0x08048718 <+117>: ret
End of assembler dump.
please try reading (and understating the code)
0x080486c3 <+32>: lea eax,[ebp-0x10]
0x080486c6 <+35>: push eax
0x080486c7 <+36>: push 0x80487f1
0x080486cc <+41>: call 0x8048480 <scanf@plt>
-> scanf("%s", buf)
by the way that's the size of buf
?
(gdb) x/1s 0x80487f1
0x80487f1: "%s"
this is your input
(gdb) x/1s $ebp-0x10
0xffffcb30: 'a' <repeats 24 times>
please learn about the e[x]amine
command (help x
), which is
one of the most versatile commands in gdb
0x080486d4 <+49>: push 0x8048817
0x080486d9 <+54>: lea eax,[ebp-0x10]
0x080486dc <+57>: push eax
0x080486dd <+58>: call 0x8048420 <strcmp@plt>
-> strcmp(buf, "250381")
(gdb) x/1s 0x8048817
0x8048817: "250381"
0x080486e5 <+66>: test eax,eax
0x080486e7 <+68>: jne 0x8048705 <main+98>
0x080486e9 <+70>: push 0x804881e
0x080486ee <+75>: call 0x8048470 <puts@plt>
0x080486f3 <+80>: add esp,0x4
0x080486f6 <+83>: push 0x804882d
0x080486fb <+88>: call 0x80485f6 <print_key>
0x08048700 <+93>: add esp,0x4
0x08048703 <+96>: jmp 0x8048712 <main+111>
0x08048705 <+98>: push 0x804883c
0x0804870a <+103>: call 0x8048470 <puts@plt>
->
if (!strcmp(buf, "250381")) {
printf("Password OK :)\n")
...
} else {
printf("Invalid Password!\n");
}
(gdb) x/1s 0x804883c
0x804a0a4: "Invalid Password!\n"
(gdb) x/1s 0x804881e
0x804a086: "Password OK :)\n"
[Task] Try the password we found? Does it work? You can submit the flag to the submission site (see above) to get +20 points!
crackme0x01
Let's go fast on this binary. Please take similar steps from crackme0x00 and reach to this place.
(gdb) disas
0x08048486 <+0>: push ebp
0x08048487 <+1>: mov ebp,esp
0x08048489 <+3>: sub esp,0x4
0x0804848c <+6>: push 0x8048570
0x08048491 <+11>: call 0x8048330 <puts@plt>
0x08048496 <+16>: add esp,0x4
0x08048499 <+19>: push 0x8048588
0x0804849e <+24>: call 0x8048320 <printf@plt>
0x080484a3 <+29>: add esp,0x4
0x080484a6 <+32>: lea eax,[ebp-0x4]
0x080484a9 <+35>: push eax
0x080484aa <+36>: push 0x8048593
0x080484af <+41>: call 0x8048340 <scanf@plt>
what's scanf()
doing (i.e., what's the value of 0x8048593
)?
=> 0x080484b4 <+46>: add esp,0x8
0x080484b7 <+49>: mov eax,DWORD PTR [ebp-0x4]
0x080484ba <+52>: cmp eax,0xc8e
it means that our input with 0xc8e
(hex? integer?) is password.
0x080484b4 <+46>: add esp,0x8
0x080484b7 <+49>: mov eax,DWORD PTR [ebp-0x4]
0x080484ba <+52>: cmp eax,0xc8e
0x080484bf <+57>: jne 0x80484d0 <main+74>
0x080484c1 <+59>: push 0x8048596
0x080484c6 <+64>: call 0x8048330 <puts@plt>
0x080484cb <+69>: add esp,0x4
0x080484ce <+72>: jmp 0x80484dd <main+87>
0x080484d0 <+74>: push 0x80485a5
0x080484d5 <+79>: call 0x8048330 <puts@plt>
0x080484da <+84>: add esp,0x4
0x080484dd <+87>: mov eax,0x0
0x080484e2 <+92>: leave
0x080484e3 <+93>: ret
[Task] Try the password we found? Does it work? Great. Please explore all crackme binaries and if you think you are ready, please start bomblab!