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 | from pwn import * |
用输入来绕过flag的过滤。
看其它师傅的wp用包含秒了两道OJ题。。。
1 |
Memory Monster I

任意地址写。找了一下发现system("/bin/sh")。想办法跳过去执行。
checksec开了Canary保护,利用任意地址写Hajack掉got里的__stack_chk_fail地址,然后覆盖canary即可.
1 | from pwn import * |
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 | fini_array[0] = __libc_csu_fini |
这样就可以循环执行main,解决数据写入量少的问题。
然后就是部署Rop。One_gadget梭不出来,自己ROPgadget一个个找。
找完之后将Rop部署在fini_array+0x10的地方,然后打断循环,并将栈迁移到我们部署的Rop上。
1 | fini_array[0] = gadget: leave;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 | from pwn import * |