所以我有这个功能:

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加到所有的%us中,这样才安全。)
%.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/

10-13 02:19