picoCTF 2018 - learn-gdb

Using a debugging tool will be extremely useful on your missions. Can you run this program in gdb and find the flag? You can find the file in /problems/learn-gdb_1_a2decdea3e89bfcdcbd9de1a67ceed0e on the shell server.

Solution

——> ./run
Decrypting the Flag into global variable 'flag_buf'
.....................................
Finished Reading Flag into global variable 'flag_buf'. Exiting.

it takes quite some time; let’s see what it does under the hood

——> ltrace ./run
__libc_start_main(0x4008c9, 1, 0x7fffe0f8a7c8, 0x400920 <unfinished ...>
setvbuf(0x7f31b33445c0, 0, 2, 0)                                                                        = 0
puts("Decrypting the Flag into global "...Decrypting the Flag into global variable 'flag_buf'
)                                                             = 52
malloc(47)                                                                                              = 0x1488260
putchar(46, 0x1488290, 0x1488260, 0x1488260.)                                                            = 46
usleep(250000)                                                                                          = <void>
strtol(0x7fffe0f8a6b0, 0, 16, 0)                                                                        = 69
putchar(46, 0x7fffe0f8a6b1, 112, 0xfffffffffffffff.)                                                     = 46
usleep(250000)                                                                                          = <void>
strtol(0x7fffe0f8a6b0, 0, 16, 0)                                                                        = 62
putchar(46, 0x7fffe0f8a6b1, 105, 0xfffffffffffffff.)                                                     = 46
usleep(250000)                                                                                          = <void>
strtol(0x7fffe0f8a6b0, 0, 16, 0)                                                                        = 56
putchar(46, 0x7fffe0f8a6b1, 99, 0xfffffffffffffff.)                                                      = 46
usleep(250000)                                                                                          = <void>
[..]

okay so it computes a char at a time then sleeps for 0.25 seconds. lets’ geedeebee and break at a call to putchar.

——> gdb ./run
Reading symbols from ./run...(no debugging symbols found)...done.
gdb-peda$ disas main
Dump of assembler code for function main:
   0x00000000004008c9 <+0>:	push   rbp
   0x00000000004008ca <+1>:	mov    rbp,rsp
   0x00000000004008cd <+4>:	sub    rsp,0x10
   0x00000000004008d1 <+8>:	mov    DWORD PTR [rbp-0x4],edi
   0x00000000004008d4 <+11>:	mov    QWORD PTR [rbp-0x10],rsi
   0x00000000004008d8 <+15>:	mov    rax,QWORD PTR [rip+0x200af9]        # 0x6013d8 <stdout@@GLIBC_2.2.5>
   0x00000000004008df <+22>:	mov    ecx,0x0
   0x00000000004008e4 <+27>:	mov    edx,0x2
   0x00000000004008e9 <+32>:	mov    esi,0x0
   0x00000000004008ee <+37>:	mov    rdi,rax
   0x00000000004008f1 <+40>:	call   0x400650 <setvbuf@plt>
   0x00000000004008f6 <+45>:	mov    edi,0x4009d0
   0x00000000004008fb <+50>:	call   0x400600 <puts@plt>
   0x0000000000400900 <+55>:	mov    eax,0x0
   0x0000000000400905 <+60>:	call   0x400786 <decrypt_flag>
   0x000000000040090a <+65>:	mov    edi,0x400a08
   0x000000000040090f <+70>:	call   0x400600 <puts@plt>
   0x0000000000400914 <+75>:	mov    eax,0x0
   0x0000000000400919 <+80>:	leave  
   0x000000000040091a <+81>:	ret    
End of assembler dump.
gdb-peda$ disas decrypt_flag
Dump of assembler code for function decrypt_flag:
   0x0000000000400786 <+0>:	push   rbp
[..]
  0x00000000004007e0 <+90>:	mov    DWORD PTR [rbp-0x1c],0x0
  0x00000000004007e7 <+97>:	jmp    0x400889 <decrypt_flag+259>
  0x00000000004007ec <+102>:	mov    edi,0x2e
  0x00000000004007f1 <+107>:	call   0x4005f0 <putchar@plt>
  0x00000000004007f6 <+112>:	mov    edi,0x3d090
  0x00000000004007fb <+117>:	mov    eax,0x0
  0x0000000000400800 <+122>:	call   0x400670 <usleep@plt>
[..]
  End of assembler dump.
  gdb-peda$ break *0x00000000004007f1
  Breakpoint 1 at 0x4007f1

after running it, having gdb peda, i noticed that on the RDX register were passed the characters of the flag one by one

gdb-peda$ c
Continuing.
.[----------------------------------registers-----------------------------------]
RAX: 0x5
RBX: 0x0
RCX: 0xfffffffffffffff
RDX: 0x70 ('p') <---- first char of "picoCTF{......}"

so at this point i just told gdb to redirect the output to a file and print the value in $rdx every time it hit that breakpoint and ran the program again from the start

(gdb) set pagination off
(gdb) set logging file gdb.output
(gdb) set logging on
Copying output to gdb.output.
(gdb)
Already logging to gdb.output.
(gdb) break *0x00000000004007f1
Breakpoint 1 at 0x4007f1
(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>p/c $rdx
>continue
>end

also had to rerun gdb without sourcing .gdbinit because with gdb-peda it crashed.

(gdb) r
Starting program: /home/andrei/Documents/pico/run
Decrypting the Flag into global variable 'flag_buf'

Breakpoint 1, 0x00000000004007f1 in decrypt_flag ()
$1 = 96 '`'
.
Breakpoint 1, 0x00000000004007f1 in decrypt_flag ()
$2 = 112 'p'
[..]
Breakpoint 1, 0x00000000004007f1 in decrypt_flag ()
$36 = 49 '1'
.
Breakpoint 1, 0x00000000004007f1 in decrypt_flag ()
$37 = 52 '4'
.
Finished Reading Flag into global variable 'flag_buf'. Exiting.

then parse the output in the gdb.output to get the flag printed sanely, with this horrendous line

——> cat gdb.output  | grep "'" | sed -e "s_.* __g" -e "s_'__g" | tr -d '\n' | tr -d '`'
picoCTF{gDb_iS_sUp3r_u53fuL_f3f39814

just add the last bracket and we’re done.