intro to gdb

Last meeting we learned about how to use GDB, lecture here.

There were two challenges, which were compiled differently (gdb_demo and gdb_demo_harder).

gdb demo

You can start gdb by running the command gdb gdb_demo in the /cybersec/rev/gdb_demo directory.

Let’s take a look at the main function:

gef➤  disass main
Dump of assembler code for function main:
   0x000000000040136d <+0>:     push   rbp
   0x000000000040136e <+1>:     mov    rbp,rsp
   0x0000000000401371 <+4>:     sub    rsp,0x140
   0x0000000000401378 <+11>:    lea    rax,[rip+0xc85]        # 0x402004
   0x000000000040137f <+18>:    mov    rdi,rax
   0x0000000000401382 <+21>:    call   0x401030 <puts@plt>
   0x0000000000401387 <+26>:    mov    rdx,QWORD PTR [rip+0x2cb2]        # 0x404040 <stdin@GLIBC_2.2.5>
   0x000000000040138e <+33>:    lea    rax,[rbp-0x110]
   0x0000000000401395 <+40>:    mov    esi,0x100
   0x000000000040139a <+45>:    mov    rdi,rax
   0x000000000040139d <+48>:    call   0x401050 <fgets@plt>
   0x00000000004013a2 <+53>:    lea    rax,[rbp-0x110]
   0x00000000004013a9 <+60>:    lea    rdx,[rip+0xc60]        # 0x402010
   0x00000000004013b0 <+67>:    mov    rsi,rdx
   0x00000000004013b3 <+70>:    mov    rdi,rax
   0x00000000004013b6 <+73>:    call   0x401040 <strcspn@plt>
   0x00000000004013bb <+78>:    mov    BYTE PTR [rbp+rax*1-0x110],0x0
   0x00000000004013c3 <+86>:    movabs rax,0xd0ab00da1433ce15
   0x00000000004013cd <+96>:    movabs rdx,0x1ce6c3b971c298e5
   0x00000000004013d7 <+106>:   mov    QWORD PTR [rbp-0x140],rax
   0x00000000004013de <+113>:   mov    QWORD PTR [rbp-0x138],rdx
   0x00000000004013e5 <+120>:   movabs rax,0x7de75c7e8fa44d19
   0x00000000004013ef <+130>:   movabs rdx,0x7812867cdce6c5c
   0x00000000004013f9 <+140>:   mov    QWORD PTR [rbp-0x130],rax
   0x0000000000401400 <+147>:   mov    QWORD PTR [rbp-0x128],rdx
   0x0000000000401407 <+154>:   mov    BYTE PTR [rbp-0x120],0x0
   0x000000000040140e <+161>:   lea    rax,[rbp-0x140]
   0x0000000000401415 <+168>:   mov    rsi,rax
   0x0000000000401418 <+171>:   mov    edi,0x20
   0x000000000040141d <+176>:   call   0x4012e9 <decrypt>
   0x0000000000401422 <+181>:   mov    DWORD PTR [rbp-0x4],0x0
   0x0000000000401429 <+188>:   jmp    0x401469 <main+252>
   0x000000000040142b <+190>:   mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040142e <+193>:   cdqe   
   0x0000000000401430 <+195>:   movzx  eax,BYTE PTR [rbp+rax*1-0x110]
   0x0000000000401438 <+203>:   movsx  edx,al
   0x000000000040143b <+206>:   mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040143e <+209>:   cdqe   
   0x0000000000401440 <+211>:   movzx  eax,BYTE PTR [rbp+rax*1-0x140]
   0x0000000000401448 <+219>:   movzx  eax,al
   0x000000000040144b <+222>:   cmp    edx,eax
   0x000000000040144d <+224>:   je     0x401465 <main+248>
   0x000000000040144f <+226>:   lea    rax,[rip+0xbbc]        # 0x402012
   0x0000000000401456 <+233>:   mov    rdi,rax
   0x0000000000401459 <+236>:   call   0x401030 <puts@plt>
   0x000000000040145e <+241>:   mov    eax,0x1
   0x0000000000401463 <+246>:   jmp    0x401483 <main+278>
   0x0000000000401465 <+248>:   add    DWORD PTR [rbp-0x4],0x1
   0x0000000000401469 <+252>:   cmp    DWORD PTR [rbp-0x4],0x20
   0x000000000040146d <+256>:   jle    0x40142b <main+190>
   0x000000000040146f <+258>:   lea    rax,[rip+0xbb1]        # 0x402027
   0x0000000000401476 <+265>:   mov    rdi,rax
   0x0000000000401479 <+268>:   call   0x401030 <puts@plt>
   0x000000000040147e <+273>:   mov    eax,0x0
   0x0000000000401483 <+278>:   leave  
   0x0000000000401484 <+279>:   ret    
End of assembler dump.

At main+176, there is a call to a “decrypt” function, but our input is not being used in the call to it. So the decrypt function is probably going to be somewhat related to the flag. We can break at main+181 by typing in break * 0x0000000000401422 or with break * main+181. Note that this challenge was compiled without PIE enabled, so that means we can break directly at the address (0x0000000000401422) and not worry about it changing between runs.

When we run the program with r and we get to the breakpoint we set, we can see the flag in the registers! Due to how Jason wrote this code it was conveniently located at the end of the stack frame.

registers.png

Flag: flag{reading_your_mind_with_gdb}

gdb demo harder

Now, our executable has a couple of changes. First, there are no debug symbols. This means we can’t break *main+<whatever> or even disass main because when compiling, those names were thrown out. Now they are all just memory addresses.

Second, PIE is enabled. This means that memory addresses for instructions are relative only to each other, and are loaded at a random base every run. GDB can partially solve this by always loading the binary at some fixed address, typically with a bunch of 0x55555555s at the beginning, like 0x0000555555554000. This can be toggled with the command set disable-randomization [on/off] with GEF.

Not gonna lie I don’t really know if this is the best way to do it but this is how I did it.

I first ran the program with r. The program waits for input so I decided to hit ctrl-c to interrupt the program. Because the program is reading input, I know that at some point the actual code has a call to a function that reads input. So if I interrupt and get a backtrace with bt, I can probably figure out where the calling function is:

backtrace.png

In this case, 0x00005555555550b4 looks pretty promising. It was entered into by __libc_start_main, which happens to be the function that calls the main function in executables that use libc, which is pretty much everything.

Taking a look at the raw instructions starting from 0x00005555555550b4, it looks kind of like the gdb demo program we did earlier. Playing around with ni and si leads to the conclusion that call 0x555555555360 calls the decrypt function and right after the flag is on the stack. So we want to break at 0x5555555550f3.

Sure enough, our flag is there:

registers2.png

Flag: flag{reading_your_mind_with_gdb}

Note that the flags are the same because the code compiled for the program is literally the exact same, but the two were compiled differently.

See you at the next meeting!