【问题标题】:Format String Attack格式化字符串攻击
【发布时间】:2012-11-04 18:14:59
【问题描述】:

我有一个小 C 程序可以利用。而且我也理解了要执行的攻击背后的逻辑。但是,尽管我尝试了,但它对我不起作用。

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

#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("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 */

  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;
}

我只需要使用格式字符串“printf(user_input);”打印secret[0]的地址和值

我尝试过提供类似“\x6e\xaf\xff\xff%x%x%x%x%s”的内容。但它不工作。任何建议将不胜感激。非常感谢。

【问题讨论】:

  • 如果你想打印某物的地址,你应该使用addressof操作符,&amp;

标签: c buffer-overflow format-string fortify-source


【解决方案1】:

这看起来像是一个类的练习,所以我将提供一些指针,但没有实际的解决方案。

您正试图通过提供不受信任的输入来利用此程序。这里有两个相当明显的错误;一种是使用%sscanf(),因为您可以溢出缓冲区并覆盖堆栈。另一个是格式字符串漏洞。在函数返回之前,覆盖堆栈可能不会让您做任何有趣的事情。根据“验证您的攻击是否成功”部分,您可能希望在此之前利用该漏洞,所以我猜测它应该是一个格式字符串漏洞。

根据验证部分,您应该覆盖secret 指向的内存。使printf 写入内存中受控位置的唯一方法是使用%n 格式说明符,它会写入给定的指针。

现在的诀窍是弄清楚如何向上堆栈,直到找到合适的指针。方便的是,在堆栈指针之前有一个用户控制的整数。因此,我们输入一个易于识别的数字(可能是 65535,即十六进制的 ffff),并使用包含大量 %xs 的格式字符串来查看堆栈中的内容。一旦我们发现,栈上的下一个东西应该是指针。

嗯。我刚刚尝试了这个,结果发现它并不是那么简单。堆栈帧的确切布局实际上与声明的顺序无关;对我来说,不同的系统之间有所不同。相反,我不得不使用很多%lxs,以及开头的一个众所周知的字符串,并添加一行来打印出实际的指针,这样我就会知道什么时候找到它。然后将相应的%lx 替换为%n 以通过该指针进行写入。最简单的方法可能是尝试 20 个左右的 %lxs,然后将每个替换为 %n,直到您设法覆盖该指针。

无论如何,希望这足以让您入门。如果您有任何问题,请告诉我。

【讨论】:

  • 事实上,在 x86_64 上有足够多的寄存器,如果你用 O2 或 O3 编译,堆栈上可能除了缓冲区之外什么都没有。
  • 此外,未使用的变量可能会被编译器优化掉,因此堆栈的实际设置可能与您的预期不同。
  • 非常感谢您的意见。当我多次给出 %1x 时,我得到重复的地址,这让我很困惑。我知道在堆栈上(从高到低)变量存储的顺序是 user_input、secret、int_input。所以如果我给 %1x 8 次,我应该能够指向 &int_input。 secret = 0xbffffa5c, user_input = bffffa60, int_input = bffffa58 请输入十进制整数 1 请输入字符串 %1x%1x%1x%1x%1x%1x%1x%1x bffffa60bffffa60bffffa584002c8a440021000400212d810 原始密码:0x44 -- 0 0x44 -- 0x55
  • @BrianCampbell 另外,由于 scanf 是这样使用的,scanf("%s", user_input);... 并且我提供输入为\x5c\xfa\xff\xbf,输入的所有值都转换为其 ASCII 的十六进制并存储在堆。 0xbffffa58: 0x01 0x00 0x00 0x00 0xd8 0x99 0x04 0x08 0xbffffa60: 0x5c 0x78 0x35 0x63 0x5c 0x78 0x66 0x61 0xbffffa68: 0x5c 0x78 0x66 0x66 0x5c 0x78 0x62 0x66你能举个例子,我应该如何给出我的输入来利用?
  • 感谢所有 cmets 。我可以得到解决方案。
猜你喜欢
  • 2013-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
  • 2012-09-26
  • 2021-02-01
  • 2016-02-16
相关资源
最近更新 更多