所以我有这个功能:
void print_usage(char* arg)
{
char buffer[640];
sprintf(buffer, "Usage: %s [options]\n"
"Randomly generates a password, optionally writes it to /etc/shadow\n"
"\n"
"Options:\n"
"-s, --salt <salt> Specify custom salt, default is random\n"
"-e, --seed [file] Specify custom seed from file, default is from stdin\n"
"-t, --type <type> Specify different encryption method\n"
"-v, --version Show version\n"
"-h, --help Show this usage message\n"
"\n"
"Encryption types:\n"
" 0 - DES (default)\n"
" 1 - MD5\n"
" 2 - Blowfish\n"
" 3 - SHA-256\n"
" 4 - SHA-512\n", arg);
printf(buffer);
}
我希望利用格式字符串漏洞攻击(我的任务)。以下是我的尝试:
我有一个利用漏洞的程序,它用noop和shell代码填充缓冲区(我用这个程序缓冲同一个函数的溢出,所以我知道它很好)。现在,我对文件做了一个对象转储以找到.dtors_列表地址,得到了0x0804a20c,添加了4个字节以得到0x804a210。
接下来,我使用gdb查找运行程序时noops的起始地址。用这个我得到了0xffbfdb8。
所以到目前为止,我觉得我是对的,现在我知道我想使用格式字符串将noop地址复制到我的.dtors结尾地址这是我想出的字符串(这是我作为用户输入提供给函数的字符串):
“\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%.168u%%1$n%.51u%%2$n%.228u%%3$n%.64u%%4$n”
这对我不起作用。程序正常运行,%s被替换为字符串I输入(减去前面的小尾数内存地址,由于某种原因,两个百分号现在是一个百分号)。
不管怎样,我在这里有点难堪,任何帮助都将不胜感激。
最佳答案
免责声明:我不是专家。
您将"\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$n%%.228u%%3$n%%.64u%%4$n"
作为arg
的值传递?这意味着buffer
将包含"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%.168u%1$n%.51u%2$n%.228u%3$n%.64u%4$n [options]\x0aRandomly..."
现在让我们进一步假设您在x86-32目标上(如果您在x86-64上,这将不起作用),并且您正在使用优化级别编译,除了640字节的print_usage
数组之外,不会在buffer
的堆栈帧中放入任何内容。
然后printf(buffer)
将按顺序执行以下操作:
按下4字节地址&buffer
。
按4字节返回地址。
调用printf
。。。
打印出"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08"
(23字节的序列)。%.168u
:将printf
的下一个参数解释为无符号int,并将其打印到宽度168的字段中由于printf
没有下一个参数,这实际上将在堆栈上打印下一个参数;即buffer
的前四个字节;即"Usag"
(0x67617355
)。%1$n
:将printf
的第二个参数解释为指向int的指针,并在该位置存储23+168。这将0x000000bf
存储在0x67617355
位置所以这是你的主要问题:你应该使用%2$n
而不是%1$n
并在arg
前面添加一个垃圾字节(顺便说一下,注意GNU上写着"If any of the formats has a specification for the parameter position all of them in the format string shall have one. Otherwise the behavior is undefined.",所以你应该把1$
s加到所有的%u
s中,这样才安全。)%.51u
:再打印51字节的垃圾。%2$n
:将printf
的第三个参数解释为指向int的指针,并将0x000000f2
存储在该垃圾位置如上所述,这应该是%3$n
。
... 等等等等。。。
所以,这里的主要错误是忘记解释"Usage: "
前缀。
我想你是想把这四个字节存储到地址中。假设你已经开始工作了但那你下一步要做什么呢?如何让程序将0xffbfdbb8
处的四字节数量视为函数指针并跳过它?
利用此代码的传统方法是利用0x804a210
中的缓冲区溢出,而不是利用0x804a210
中更复杂的sprintf
漏洞。您只需要让"%n"
大约640个字符长,并确保与printf
的返回地址相对应的4个字节包含NOP sled的地址。
不过,即使是那部分也很棘手你可能会想到一些与AA>相关的东西:因为你的雪橇在一次运行中存在于地址arg
并不意味着它将在下一次运行的同一个地址中存在。
这有用吗?
关于c - 格式字符串漏洞问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10740308/