sprintf函数的缓冲区溢出?

rem*_*inn 11 c printf overflow fortify-source

{     
    char buf[8];
    sprintf(buf,"AAAA%3s","XXXXXXXX");
    printf("%s\n",buf);
}
Run Code Online (Sandbox Code Playgroud)

会发生什么?

缓冲区有8个字符空间,只剩下3个空闲字符,但"XXXXXXXX"长度为8个字符.

我在Windows 7上使用Visual Studion 2008进行测试.结果,程序打印出来:AAAXXXXXXX,发生了运行时错误.

den*_*ane 12

考虑一下你的,更重要的是,类似的案例会发生什么事情是很有意义的.正如其他海报所指出的那样,它会调用UB.这可能是真的.然而,世界并不仅仅因为有人没有明确接下来应该发生什么而停止.而接下来的实际情况可能是一个主要的安全漏洞.

如果您的字符串XXX...来自不受控制的源,则非常接近于生成缓冲区溢出漏洞.

(1)您的堆栈通常向后"增长",即地址越小,堆栈填充的越多.

(2)字符串期望存储属于该字符串的字符,以便在字符n 之后存储字符n + 1 .

(3)当你调用一个函数时,返回地址,即函数返回后要执行的指令的地址,被推送到堆栈(通常是其中之一).

现在考虑函数的堆栈帧.

|----------------|
| buf [size 8]   |
|----------------|
| (func args)    |
|----------------|
| (other stuff)  |
|----------------|
| return address |
|----------------|
Run Code Online (Sandbox Code Playgroud)

通过找出buf堆栈与返回地址之间的确切偏移是什么,恶意用户可以操作输入到您的应用程序,其方式是该XXX...字符串包含攻击者在不受控制的sprintf函数将覆盖的位置选择的地址堆栈上的返回地址.(注意:snprintf如果您可以使用,请更好地使用).从而攻击者发起了缓冲区溢出攻击.他可能会使用类似NOP雪橇技术的东西让你的应用程序为他启动一个shell.如果您编写的是在特权用户帐户下运行的应用程序,那么您只需向攻击者提供一个入门级别的系统,即ACE 洞,如果你愿意的话.

更新

您遇到的运行时错误可能是由于覆盖了返回地址.由于你基本上填充了gargabe,CPU跳转到的地址可能包含字节序列,解释为程序文本,导致无效的内存访问(或者地址本身已经坏了).

应该注意的是,一些编译器可以帮助解决这些类型的错误.例如,海湾合作委员会有-fstack-protector.我不熟悉这些功能有多好.

  • "例如,GCC有-fackack-protector.我不熟悉这些功能有多好." - 你永远不应该发现:P (2认同)

In *_*ico 8

该函数sprintf()将在字符串中写入时写入数组,因此会调用未定义的行为.查看您的代码,它可能会写入堆栈上接下来发生的任何事件的前几个字节,或者导致运行时错误,但不保证该行为.

未定义的行为在字面上意味着任何事情都可能发生.这意味着您的代码可能没有任何错误,导致运行时错误,或导致您的计算机爆炸,赢得彩票,使独角兽出现在您的后院,从死者中提升希特勒或暗杀美国总统.请不要这样做.

始终确保您的字符缓冲区有足够的空间来容纳您正在处理的sprintf()内容以及空终止符的额外字符.一般情况下,不要试图弄乱不属于你的内存空间.


Jon*_*nVD 6

如果不使用这种方法,你应该尝试使用为的snprintf()方法的描述在这里.此方法执行基本相同的功能,但它允许您明确地控制字符数,防止未定义的行为(这是一件好事)

保证snprintf不会将大于字节的字节写入str,因此使用它可以帮助避免缓冲区溢出Wiki的风险


R..*_*R.. 5

您的格式字符串中有错误/拼写错误.而不"AAAA%3s"应该是"AAAA%.3s".场[最小]宽度和场精度非常不同.前者设置字段将扩展填充的最小字节数.后者(对于字符串)设置将输出的最大字节数; 字符串的其他字节既不会被检查也不会被复制到输出中.