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 0x03) 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.
aaaaaaaaaaaaaa
[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 understanding) the code
0x080486c3 <+32>: lea eax,[ebp-0x10]
0x080486c6 <+35>: push eax
0x080486c7 <+36>: push 0x80487f1
0x080486cc <+41>: call 0x8048480 <scanf@plt>
can be interpreted as:
-> scanf("%s", buf)
By the way, what'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>
is equivalent to:
-> strcmp(buf, "250381")
Examine the arguments:
(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!
Bomblab
Bomblab challenges are in one bomb
binary, which you can find under
the home directory of lab01
on the CTF server.
[host] ssh lab01@<ctf-server-address>
[CTF server] $ pwd
/home/lab01
[CTF server] $ ls -alh | grep bomb
-rwsr-x--- 1 bomb110-raspberry lab01 22K Jan 14 2021 bomb
Execute the bomb binary and provide your API key to get started:
[CTF server] $ ./bomb
Enter your api-key: <your-api-key>
,--.!, ____ _ _ _
__/ -*- | __ ) ___ _ __ ___ | |__ | | __ _| |__
,d08b. '|` | _ \ / _ \| '_ ` _ \| '_ \| |/ _` | '_ \
0088MM | |_) | (_) | | | | | | |_) | | (_| | |_) |
`9MMP' |____/ \___/|_| |_| |_|_.__/|_|\__,_|_.__/
cs6265
Welcome to my fiendish little bomb. You have N? phases with
which to blow yourself up. See you alive!
(hint: seriously, security question?)
>
[Task] Defuse the bomb by providing the right answer to each phase. Be careful when handling the bomb; if you enter a wrong answer, the bomb will explode, and you will lose points for the phase. Submit the flags from each phase to the submission site to collect points.