简体   繁体   English

在C中导致缓冲区溢出以强制为真条件

[英]Causing a buffer overflow in C to force a true condition

I'm trying to solve this challenge where the goal is to get the program to display "YOU WIN!" 我正在尝试解决这个挑战,目标是使程序显示“ YOU WIN!”。 To do this I must find the right values ​​of the variables to make both the if condition and assert evaluate to true. 为此,我必须找到变量的正确值以使if条件和assert为true。

Originally I thought this would be relatively simple. 本来我以为这会比较简单。 However, it seems that to make a buffer overflow is an art that requires advanced programming skills (big-endian and little-endian concepts too), but I do not have much experience in C programming. 但是,似乎使缓冲区溢出是一门需要高级编程技能(也需要大端和小端概念)的技术,但是我在C编程方面没有太多经验。

Any help or advice would be greatly appreciated. 任何帮助或建议,将不胜感激。

#include<assert.h>
int
main(int argc, char*argv[]){
    int size = 0;
    int buf[1024];
    read(0,&size,sizeof(size));
    assert (size <= 1024);
    read(0,buf,size*sizeof(int));
    if (size > 0 && size < 100 && buf[999] == 'B')
        printf("YOU WIN!\n");
    return 0;
}

Fun problem. 好玩的问题。

You have to know something about the machine you're running on, so I made the following assumptions: 您必须对所运行的机器有所了解,因此我做出了以下假设:

  1. 32-bit machine, big endian. 32位计算机,大字节序。

  2. Compiler does "classical" stack layout, which would put size adjacent to the end of buf . 编译器执行“经典”堆栈布局,这会将size放在buf的末尾附近。

  3. Data is aligned to 4 bytes or less so there is no padding between the end of buf and size . 数据对齐到4个字节或更少,因此buf的末尾和size之间没有填充。

The classic compiler on this machine allocates your variables on the call stack in the order they appear in the code, so size gets pushed first, and then buf . 这台机器上的经典编译器按照变量在代码中出现的顺序在调用堆栈中分配变量,因此先推size ,然后推buf Your stack will look like this: 您的堆栈如下所示:

                   buf                byte
   top of stack   offset             offset
   +-----------+    0 * sizeof(int) =    0  
   | buf[   0] |   
   +-----------+    1 * sizeof(int) =    4
   |           |   
   ...
   |           |
   +-----------+ 1023 * sizeof(int) = 4092
   | buf[1023] |
   +-----------+ 1024 * sizeof(int) = 4096
   |   size    |
   +-----------+ 1025 * sizeof(int) = 4100
  bottom of stack

Writing to buf[1024] would overwrite size . 写入buf[1024]将覆盖size If we were writing raw bytes, then byte 4096, 4097, 4098, and 4099 would correspond to the bytes in size . 如果我们正在写入原始字节,则字节4096、4097、4098和4099将对应于size的字节。

We know we want size to be negative to pass the assert , and we want size * sizeof(int) to evaluate to 4100. Because if we read 4100 bytes, the last 4 bytes will overwrite size . 我们知道我们希望size为负以传递assert ,并且我们希望size * sizeof(int)的值为4100。因为如果我们读取4100字节,则最后4个字节将覆盖size

size * 4 = 4100.  Solving for size:
size = 1025 (or 0x401)

Now we just make it negative by setting the most significant bit. 现在,我们通过将最高有效位设置为负。

0x80000401

So setting size to this value will pass assert (size <= 1024) . 因此,将大小设置为此值将通过assert (size <= 1024) Because anything with the most significant bit set is negative, and all negative numbers are less than 1024. 因为设置了最高有效位的都是负数,并且所有负数都小于1024。

When we get to the buffer read, it will get evaluated like so: 当我们到达读取的缓冲区时,它将得到如下评估:

read(0, buf, 0x80000401 * sizeof(int));
read(0, buf, 0x80000401 * 4);
read(0, buf, 0x00001004) == read(0, buf, 4100)

Yes, that's right, we just told it to read 4100 bytes because of 32-bit modulo arithmetic. 是的,没错,由于32位模运算,我们只是告诉它读取4100字节。 Or if it helps, you can think of multiplying by 4 as shifting left by 2, so shifting our magic value left by 2 gets rid of the most-significant bit. 或者,如果有帮助,您可以认为乘以4就是左移2,因此将我们的魔术值左移2会去除最高位。

To print "YOU WIN!", you'd write a stream of bytes, where buf[999] is byte 3996 and bytes 4096, 4097, 4098, and 4099 are the bytes of size . 要打印“ YOU WIN!”,您需要编写一个字节流,其中buf [999]是字节3996,字节4096、4097、4098和4099是size字节。 On this hypothetical big-endian machine, we'd set those bytes to 0, 0, 0, and 1-99, respectively. 在此假设的big-endian机器上,我们将这些字节分别设置为0、0、0和1-99。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM