Tut01: GDB/x86

Registration

Please refer to the course page in Canvas for registration and flag submission site information.

Did you get an api-key through email? The api-key is essentially your identity for this class. Once you receive an api-key, you can login to the course website.

If you find difficulty in registration, please send us an email. 6265-staff@cc.gatech.edu

Before we proceed further, please first read the game rule.

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:

  1. reading the whole binary first (e.g., try objdump -M intel -d crackme0x00);

  2. starting with a gdb session (e.g., gdb ./crackme0x00) and setting a breakpoint on a well-known entry (e.g., luckily main() is exposed, try nm crackme0x00);

  3. run ./crackme0x00 first (waiting on the "Password" prompt) and attach it to gdb (e.g., gdb -p $(pgrep crackme0x00));

  4. 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  0xf7fd3069 in __kernel_vsyscall ()
#1  0xf7e8cd17 in read () from /usr/lib32/libc.so.6
#2  0xf7e18ab8 in __GI__IO_file_underflow () from /usr/lib32/libc.so.6
#3  0xf7e19bec in __GI__IO_default_uflow () from /usr/lib32/libc.so.6
#4  0xf7dfd98f in __GI__IO_vfscanf () from /usr/lib32/libc.so.6
#5  0xf7e08f15 in scanf () from /usr/lib32/libc.so.6
#6  0x080492fa in main (argc=1, argv=0xffffcbf4) at crackme0x00.c:14

[bt]: print backtrace (e.g., stack frames). Again, don't forget to check help bt

(gdb) tbreak *0x080492fa
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) disas
Dump of assembler code for function main:
    0x080492b8 <+0>:     lea    ecx,[esp+0x4]
    0x080492bc <+4>:     and    esp,0xfffffff0
    0x080492bf <+7>:     push   DWORD PTR [ecx-0x4]
    0x080492c2 <+10>:    push   ebp
    0x080492c3 <+11>:    mov    ebp,esp
    0x080492c5 <+13>:    push   ecx
    0x080492c6 <+14>:    sub    esp,0x14
    0x080492c9 <+17>:    sub    esp,0xc
    0x080492cc <+20>:    push   0x804a05c
    0x080492d1 <+25>:    call   0x8049080 <puts@plt>
    0x080492d6 <+30>:    add    esp,0x10
    0x080492d9 <+33>:    sub    esp,0xc
    0x080492dc <+36>:    push   0x804a074
    0x080492e1 <+41>:    call   0x8049040 <printf@plt>
    0x080492e6 <+46>:    add    esp,0x10
    0x080492e9 <+49>:    sub    esp,0x8
    0x080492ec <+52>:    lea    eax,[ebp-0x18]
    0x080492ef <+55>:    push   eax
    0x080492f0 <+56>:    push   0x804a059
    0x080492f5 <+61>:    call   0x8049090 <scanf@plt>
 => 0x080492fa <+66>:    add    esp,0x10
    0x080492fd <+69>:    sub    esp,0x8
    0x08049300 <+72>:    push   0x804a07f
    0x08049305 <+77>:    lea    eax,[ebp-0x18]
    0x08049308 <+80>:    push   eax
    0x08049309 <+81>:    call   0x8049030 <strcmp@plt>
    0x0804930e <+86>:    add    esp,0x10
    0x08049311 <+89>:    test   eax,eax
    0x08049313 <+91>:    jne    0x8049337 <main+127>
    0x08049315 <+93>:    sub    esp,0xc
    0x08049318 <+96>:    push   0x804a086
    0x0804931d <+101>:   call   0x8049080 <puts@plt>
    0x08049322 <+106>:   add    esp,0x10
    0x08049325 <+109>:   sub    esp,0xc
    0x08049328 <+112>:   push   0x804a095
    0x0804932d <+117>:   call   0x80491f6 <print_key>
    0x08049332 <+122>:   add    esp,0x10
    0x08049335 <+125>:   jmp    0x8049347 <main+143>
    0x08049337 <+127>:   sub    esp,0xc
    0x0804933a <+130>:   push   0x804a0a4
    0x0804933f <+135>:   call   0x8049080 <puts@plt>
    0x08049344 <+140>:   add    esp,0x10
    0x08049347 <+143>:   mov    eax,0x0
    0x0804934c <+148>:   mov    ecx,DWORD PTR [ebp-0x4]
    0x0804934f <+151>:   leave
    0x08049350 <+152>:   lea    esp,[ecx-0x4]
    0x08049353 <+155>:   ret
    End of assembler dump.

please try reading (and understating the code)

0x080492ec <+52>:    lea    eax,[ebp-0x18]
0x080492ef <+55>:    push   eax
0x080492f0 <+56>:    push   0x804a059
0x080492f5 <+61>:    call   0x8049090 <scanf@plt>
 -> scanf("%s", buf)

by the way that's the size of buf?

(gdb) x/1s 0x804a059
0x804a059:      "%s"

this is your input

(gdb) x/1s $ebp-0x18
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

0x08049300 <+72>:    push   0x804a07f
0x08049305 <+77>:    lea    eax,[ebp-0x18]
0x08049308 <+80>:    push   eax
0x08049309 <+81>:    call   0x8049030 <strcmp@plt>
 -> strcmp(buf, "250381")
(gdb) x/1s 0x804a07f
0x804a07f:      "250381"
0x08049311 <+89>:    test   eax,eax
0x08049313 <+91>:    jne    0x8049337 <main+127>
0x08049315 <+93>:    sub    esp,0xc
0x08049318 <+96>:    push   0x804a086
0x0804931d <+101>:   call   0x8049080 <puts@plt>
...
0x08049335 <+125>:   jmp    0x8049347 <main+143>
0x08049337 <+127>:   sub    esp,0xc
0x0804933a <+130>:   push   0x804a0a4
0x0804933f <+135>:   call   0x8049080 <puts@plt>
->
    if (!strcmp(buf, "250381")) {
        printf("Password OK :)\n")
        ...
    } else {
        printf("Invalid Password!\n");
    }
(gdb) x/1s 0x804a0a4
0x804a0a4:      "Invalid Password!\n"
(gdb) x/1s 0x804a086
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
Dump of assembler code for function main:
    0x08049186 <+0>:     lea    ecx,[esp+0x4]
    0x0804918a <+4>:     and    esp,0xfffffff0
    0x0804918d <+7>:     push   DWORD PTR [ecx-0x4]
    0x08049190 <+10>:    push   ebp
    0x08049191 <+11>:    mov    ebp,esp
    0x08049193 <+13>:    push   ecx
    0x08049194 <+14>:    sub    esp,0x14
    0x08049197 <+17>:    sub    esp,0xc
    0x0804919a <+20>:    push   0x804a008
    0x0804919f <+25>:    call   0x8049040 <puts@plt>
    0x080491a4 <+30>:    add    esp,0x10
    0x080491a7 <+33>:    sub    esp,0xc
    0x080491aa <+36>:    push   0x804a020
    0x080491af <+41>:    call   0x8049030 <printf@plt>
    0x080491b4 <+46>:    add    esp,0x10
    0x080491b7 <+49>:    sub    esp,0x8
    0x080491ba <+52>:    lea    eax,[ebp-0xc]
    0x080491bd <+55>:    push   eax
    0x080491be <+56>:    push   0x804a02b
    0x080491c3 <+61>:    call   0x8049050 <scanf@plt>

what's scanf() doing (i.e., what's the value of 0x804a02b)?

 => 0x080491c8 <+66>:    add    esp,0x10
    0x080491cb <+69>:    mov    eax,DWORD PTR [ebp-0xc]
    0x080491ce <+72>:    cmp    eax,0xc8e

it means that our input with 0xc8e(hex? integer?) is password.

0x080491d3 <+77>:    jne    0x80491e7 <main+97>
0x080491d5 <+79>:    sub    esp,0xc
0x080491d8 <+82>:    push   0x804a02e
0x080491dd <+87>:    call   0x8049040 <puts@plt>
0x080491e2 <+92>:    add    esp,0x10
0x080491e5 <+95>:    jmp    0x80491f7 <main+113>
0x080491e7 <+97>:    sub    esp,0xc
0x080491ea <+100>:   push   0x804a03d
0x080491ef <+105>:   call   0x8049040 <puts@plt>
0x080491f4 <+110>:   add    esp,0x10
0x080491f7 <+113>:   mov    eax,0x0
0x080491fc <+118>:   mov    ecx,DWORD PTR [ebp-0x4]
0x080491ff <+121>:   leave
0x08049200 <+122>:   lea    esp,[ecx-0x4]
0x08049203 <+125>:   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!

Reference