国赛

本文最后更新于:2022年5月27日 上午

0x01 格式化字符串漏洞

漏洞的产生原因及利用原理

我们在正常的对格式化字符输出时大都使用printf(*format,*arg);
此种形式进行输出,但是部分程序员在开发的使用,为了省事使用了,printf(*format);进行输出
错误:
#include <stdio.h>
void main(){
char str[1024];
scanf(%s,&str);
printf(%s);
}

正确:
#include <stdio.h>
void main(){
char str[1024];
scanf(%s,&str);
printf(%s,str);
}

出现字符串格式化漏洞时,有如下方法

任意地址泄露(读)

任意地址读需要用到printf的另外一个特性,$操作符.这个操作符可以输出指定位置的参数.利用%n$x这样的字符串就可以获得对应的第n+1个参数的数值(因为格式化参数里边的n指的是格式化字符串对应的第n个输出参数,那么相对于输出函数来说就成了第n+1个).
先输入若干个数据确定偏移,比如AAAA%6$x,若输出为AAAA41414141时,就是达到了偏移量,此时偏移为6,若改为AAAA%7$x,脚本写为

conn.sendline(“%7$s”+p32(0x08048000))

会打印处0x0804800地址前几字段。
原因如下:此脚本中将p32(0x08048000)率先压入栈中,当其格式化串超出偏移值1个位置时,会读取栈上此地址,然后进行打印,看如下栈图。

任意地址写

利用%n的特性,可以将已打印字符数传给后续传入的地址
如:
printf(“%.100d%n”,c,&c);
可以打印100个c,然后将100赋值到c的地址处。

总结一下
payload核心在于,先计算出偏移值,再利用%kc%m$n进行修改

攻防世界题 string(新手区)

此题有几点需要注意,首先是这个样子的代码,是可以考虑传入shellcode直接执行

((void (__fastcall*)(_QWORD))v1)(0LL)

此行会将v1转化为代码执行,使用

1
2
3
from pwn import*
context(log_level = 'debug',arch = 'i386', os = 'linux'
shellcode = asm(shellcraft.sh())

得到shellcode机器码。

再者就是灵活运用printf(format)这样的漏洞
如本题中,需要泄露v3的地址,且此地址就在漏洞printf不远处,就不要用AAAA-%p….的形式去泄露AAAA所存储的地址了,而是直接找v3对应内存的值,在输入%p….后对应偏移量为多少

记录一个新方法

修改地址法
用到pwn里的fmtstr_payload(offset,{被替换的:替换为})
这个语法
如将atoi的got地址改为system的plt地址,可以写为
payload = fmtstr_payload(offset,{atoi_got : system_plt})即可利用格式化字符串修改地址

0x02 ROP

寄存器传参顺序

64位系统中,函数传参进入寄存器
而32位是先入栈再传入数据。
64位的传参顺序:前7个参数,从左至右依次传入rdi,rsi,rdx,rcx,r8,r9,r15.

简单ROP

ret2libc

若题目没给libc版本,需要用LibcSearch来做,其中格式为libc.dump(‘system’)
如果给了libc版本,可以这样
libc = ELF(‘./libc-2.xx.so’)这样子
搜索/bin/sh字符串所在位置时,有如下语法:
next(libc.search(b’/bin/sh’))可以获取binsh的地址

关于strlen()检测的绕过

read函数读至’\n’结束
strlen读至’\x00’结束
在32位里面,char数组读入时:read(0,buf,10u),就读入十个char,而’\x00’是一个char
故遇到检查strlen来进行阻碍时,可以在字符串前面输入’\x00’开头,来规避之。

关于构造好ROP以后,接收got表地址时的注意事项

1.32位系统下,got表地址是4byte,用p.recv(4);u32(write)来收取
2.64位系统下,got表地址位8byte,需要进行相当的调整。

0x03 堆heap

引用经典内存布局


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!