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 * |