本篇writeup已收录进pwn解题本. Link
pwn4
题目描述:
An homage to pwny.racing, we present… speedrun pwn challenges. These bite-sized challenges should serve as a nice warm-up for your pwning skills.
题目附件:pwn4
考察点:格式化字符串
难度:好难呀
初始分值:100
最终分值:172
完成人数:28
程序分析
限制十分苛刻的一个格式化字符串漏洞,字符串长度只有13:
v10是mmap+mprotect的一个随机整数,只读格式化字符串漏洞在
log_attempt中v8等于v10时给shell,但是v8是个4位数,基本上等于不了v10v10在栈中可以通过%25$p泄漏,v8也在栈中可通过%16$n修改程序是32位静态编译的,没有GOT表可改
格式化字符串长度为13,且只能用一次
解题思路
由于漏洞只能利用一次,所以必须在泄漏v10的同时修改v8,比赛的时候找了半天也不知道怎么搞…
而且如果用常规的%<N>c的方法去修改v8(N的长度在1-10之间),13字节的字符串根本不够用…
|(·_·) |·_·) |_·) |·) | )太难了…
赛后看wp,学到了新姿势:
Basic idea:
Copy the secret (4 bytes) from the stack to our guess variable (also on the stack) and pass the check.
%<N>dnormally this lets us print N characters total (a decimal int padded to N spaces).%*25$dlets us choose the value of N from the stack, we choose 25$ -> position of the secret value, this will therefore print a number of chars equal to the secret value.%16$nwill write the number of printed chars to our variable on the stack (position 16) that is then compared with the secret.This will print A LOT of characters back (like 500MB of spaces), but works after trying a few times!
记笔记!*的用法
%<N>d这个很常用,打印长度为N的字符串,和%<N>c差不多%*25$d从栈中取变量作为N比如
25$处的值是0x100,那么这个格式化字符串就相当于%256d
那么可以理解为*相当于c语言取值符号…嘛?刨根问底一下,查看man文档,找到*的用方法:
根据文档写个栗子:
1 | int main(){ |
输出如下:
1 | case1: |
小结
*如果单独使用,则按顺序取参数列表中的参数*如果配合$使用,则取参数列表中相应位置的参数,如*1$- 取出的参数将格式化为十进制数,用作限制字符串宽度
用途
- 缩短格式化字符串长度
回到题目,%*25$d%16$n可以把v10的值直接复制给v8
用%n可能会一次打印好多字符,不过多试几次,当v10很小的时候很快的打印完了
写exp时可以使用pwntools的clean函数接受数据
exp
1 | fmt = "%*25$d%16$n" |
clean(10): 接受全部数据并清空缓冲区,timeout为10秒








