2

如果您不希望最后一段的长篇大论头-->

gets()我在用于填充函数的本地 1024-char* 缓冲区的程序中发现了缓冲区溢出漏洞。它在Sparc Solaris 5.8 (sun4u) 32-bit上。

要克服的第一个障碍tch是不让我手动输入 > 257 个字符(如果我想能够按 Enter 键,则为 256 个;)

为了绕过这个,我一直在执行/bin/shstty raw并且我现在可以用> 1095个字符有效地溢出缓冲区。(注意:我必须使用 Ctrl-J 来执行 line-feeds/enter ,尽管我还没有研究 stty raw 来检查为什么会发生这种变化。

我的问题是:现在不仅要溢出缓冲区,还要写新的返回地址/保留 %fp十六进制代码。但由于我不知道如何从终端程序中手动输入十六进制代码,我想我可以找到一种方法来使用 C 并让它与易受攻击的程序执行/交互,并最终将其发送给我的自定义缓冲区。

但是,如果我有办法手动输入/复制粘贴十六进制字节,我可以做这样简单的事情!!!

perl -e 'print "n" . "A"x1094 . "\xff\xbe\xf5\x58" . "\xff\xbe\xff\x68" . "\0"'

(如果您想知道我为什么要打印“n”,那是因为易受攻击的程序会检查字符串的 yes/no @index 0)

因为我不知道手动粘贴此类十六进制信息的方法,所以我一直在尝试使用 C。在 C 中,我制作了特殊的缓冲区,并且一直在学习popen()易受攻击的程序(“w”)和 fputs 我的缓冲区,但它已经充其量工作不确定。(popen,IPC对我来说是全新的)

(我也尝试过piping/dup2ing,但没有得到任何结果,没有有效字符串输出/输入的证据)不确定出了什么问题,我对代码进行了很多试验,后来放弃了它。

描述我的“popen”程序输出的最佳方式是,仅通过在索引 [1096->1099] 处分隔缓冲区,易受攻击的程序中存在段错误,这实际上是函数的位置%fp,所以看起来很正常@首先。但是,将字符串分隔在比这更高的索引处会使编程工作正常(WTF)!!!这种行为让我觉得WTF!?这与手动粘贴的行为不同,因为更多的字符肯定会改变 seg fault -> bus error,因为接下来我将覆盖返回地址,然后是该堆栈帧及以后的任何可能重要的信息!

整个字符串实际上并没有一口气发送吗?!?!?我从 那里听说过一些关于缓冲区fflush()问题的信息popen() manpage,但我不明白那个谈话!!

这是我第一次使用popen(),并且有更多我认为奇怪的行为->如果我停止fputs()数据,易受攻击的程序进入无限循环,重复打印它通常只会打印一次的最后一个输出字符串,但是在这个情况下,每当我停止 fputs'ing 时,事情就会开始无限打印出来。现在,我希望如果我不输出,程序不会像一只好鸭子一样坐下来等待更多输入。???显然不是。显然它必须继续小便和呻吟,我需要输入下一个字符串!这是 popen 的正常行为吗?也许是因为我的 popen 程序在实际完成之前退出并使用 pclose() 关闭(但我期待缓冲区溢出,我不知道为什么我没有像手动粘贴时那样得到它)

注意:我使用 "\r\n" 来指示易受攻击的程序执行 'return' ,我不确定 CTRL-J / Enter 键的等价物(哪个 enter 键在原始 tty 中不起作用)。我也不确定在管道缓冲区时是否需要原始 tty。

然后我想我试着聪明一点,把字符串放到一个文件中,然后通过命令行做一个管道。我不知道你是否可以像这样通过管道连接到一个期望
以这种形式输入的程序,我什至无法得到一个溢出!IE

printf "\r\n" > derp && perl -e 'print "n" . "A"x1025' >> derp && printf "\r\n" >> derp
cat derp | ./vuln

现在,倒回 <-> 回到 tsh,我说我有 257 个字符的限制,如果我想能够按 Enter 并让程序继续运行,我需要做的比这少。所以,也许 \r\n 不在这里,因为那是 2 个字符。要么,要么你不能cat进入这样的程序。但是我在我的 C 程序中使用 \r\n 来告诉易受攻击的程序我已经按回车键,并且它们至少稍微更实用(不是真的),尽管仍然没有以与手动粘贴我相同的方式溢出缓冲区垃圾缓冲区。

啊!!!

此外,仅使用其中一个:'\r' 或 '\n' 绝对行不通!我错过了另一个控制字符吗?这可能是我的程序问题之一吗???

但基本上我的整个问题是我似乎无法理解如何创建一个程序来运行和与命令行可执行文件交互并说嘿!!!将整个缓冲区放入您的gets() 中,我知道您会非常喜欢它!就像我自己从终端运行程序一样。
而且我知道无法手动将十六进制代码粘贴/写入终端,这就是全部原因为什么我要尝试编写一个交互程序来在 C 中制作一个带有十六进制字节的字符串并发送到该程序的gets()!!!!如果您跳到本段,我还希望您知道我正在使用专门的 /bin/bash 和 stty raw 以便我可以手动输入超过 257 个字符(如果我可以成功创建,我不确定是否需要继续这样做一个交互程序向易受攻击的程序发送缓冲区。可能以这种方式发送缓冲区会绕过 tch' 终端 257 字符限制)

谁能帮我!?!?!?!?!

4

4 回答 4

2

The popen call is probably the call you want. Make sure to call pclose after the test is finished so that the child process is properly reaped.

Edit Linux man page mentioned adding "b" to the mode was possible for binary mode, but POSIX says anything other than "r" or "w" is undefined. Thanks to Dan Moulding for pointing this out.

FILE *f = popen("./vuln", "w");
fwrite(buf, size, count, f);
pclose(f);
于 2012-06-25T22:45:11.977 回答
1

没有任何结果。

让我强调一下我怀疑的问题。我管道的字符串在开头包含 a\n以确认易受攻击程序的“按 Enter 继续”。

我继续溢出的缓冲区被声明char c[1024];现在我用超过 1100 个字节填充它。我不明白;有时有效,有时无效。摇摆不定的因素是我是否在 gdb 中(在 gdb 中会产生更好的结果)。但有时它也不会在那里溢出。由于这个原因,我真的相信这是关于我的缓冲区如何传输的外壳/终端设置的某种问题。但我不知道如何解决这个问题:(

我真的很感谢大家的帮助。但我没有收到一致的结果。我做了很多事情,也学到了很多粗略的材料,但我认为可能是时候放弃这种努力了。或者,至少等待更长的时间,直到有人给出答案。

ps安装了Expect,:)但我无法从其中接收溢出...

无论如何,我似乎需要 Expect,因为在管道完成工作后,我需要重新获得对流的控制。除了我不能让程序溢出这一事实之外,Expect 使这变得非常简单。

我发誓这与终端外壳设置有关,但我不知道。

于 2012-06-26T13:34:15.760 回答
1

如果 shell 正在读取gets(),它正在读取它的标准输入。

因此,在您的漏洞利用代码中,您需要生成一个适当的超长字符串。除非你在玩,否则你expect只需将超长缓冲区写入从你的漏洞利用程序连接到受害者标准输入的管道。您只需要确保您的超长字符串不包含任何换行符(CR 或 LF)。如果您使用管道,则可以避免终端设置和 control-J 用于 control-M 等的变幻莫测;管道是一种透明的 8 位传输机制。

因此,您的程序应该:

  1. 创建管道 ( pipe())。
  2. 叉子。
  3. 孩子:
    • 将管道的读取端连接到标准输入 ( dup2())。
    • 关闭管道的读写端。
    • 执行受害者程序。
    • 如果执行受害者失败,则报告错误并退出。
  4. 家长:
    • 关闭管道的读取端。
    • 生成字符串以溢出受害者的输入缓冲区。
    • 将字符串写入管道中的受害者。
  5. 坐下来看烟花!

您可以使用popen()"w"选项来简化此操作(因为父进程将要写入子进程)。

您可能需要考虑如何处理信号。再一次,不这样做更简单,但如果你在接收器(受害者)退出时写入管道,你会得到一个 SIGPIPE 信号,它将终止父级。

于 2012-06-25T22:47:45.287 回答
0

另一个更新

这是最奇怪的。

我实际上已经用 shellcode 环境变量的地址有效地覆盖了返回地址。

那是昨晚,奇怪的是,程序在环境变量结束后崩溃了,从来没有给我一个shell。shellcode 是手写的,并且可以工作(在一个空程序中,将 main 的返回地址更改为 shellcode 的地址并返回,只是为了测试目的,以确保 shellcode 工作)。在这个测试程序中,Main 返回到我的 SPARC shellcode 并生成一个 shell。

...所以.... idk 为什么它在新环境中不起作用。但那是我最小的问题。因为溢出很奇怪......

正如我在之前的帖子中所说,一段时间后我似乎无法重现溢出。所以,我想为什么不呢,让我们发送一个更大、更危险的 4000 字符缓冲区,其中充满垃圾“A”,就像@JonathanLeffler 推荐的那样,以确保段错误。好吧,让我们说奇怪的结果。

如果我发送的字符少于 3960 个,则不会出现溢出(WTF?!?!),尽管早些时候我可能会在仅发送大约 1100 个字符时出现溢出,这要少得多,并且较小的缓冲区会覆盖确切的返回地址的位置(当它工作时。*咳嗽

现在是最奇怪的部分!!!

这个“挑剔”的缓冲区似乎只针对特定长度进行段错误。但是我在发送大的 4000 字符缓冲区后尝试使用 gdb,并注意到一些奇怪的东西。好的,是的,它发生了段错误,但是有“保留区域”,包括我之前能够溢出的返回地址,不知何故没有受到伤害,你可以从图像中看到(不要点击它)阅读下一段以了解所有内容,所以你可以正常查看。我敢肯定,如果没有正确的理解,它看起来很乱。我制作的缓冲区的一部分不会影响我过去用较小的缓冲区影响的某些内存区域!这是如何或为什么发生的。我还不知道。我不知道这种行为有多规律。但我会试着找出答案。

该图像发生在距缓冲区起始地址大约 1000 个字节的位置。您可以看到“保留的内存段”,嵌入在我的缓冲区中的许多 0x41 之间(十六进制中的“A”)。实际上,地址 0xffbef4bc 保存了 0x0001136c 的返回地址,需要被覆盖,它是调用这个的函数的返回地址,'this one' = 保存有漏洞缓冲区的函数。由于 SPARC 中堆栈窗口的性质,我们无法写入(*易受攻击的缓冲区所属的函数) * 的返回地址——该返回地址实际上低于缓冲区的地址,无法访问,因此我们必须覆盖返回我们上面的函数的地址。又名我们的来电者;)

无论如何,关键是我以前也能够使用较小的缓冲区溢出该返回地址。所以WTF弥补了这些差距!?!??!更大的缓冲区不应该能够溢出这些,尤其是。如果较小的缓冲区可以(尽管不一致)..无论如何,这是图像。

[图片] http://s16.postimage.org/4l5u9g3c3/Screen_shot_2012_06_26_at_11_29_38_PM.png

于 2012-06-27T05:54:58.303 回答