From 4a27d1a4e29b0aa9b64681ad034a3479493cf6df Mon Sep 17 00:00:00 2001 From: qhwdw Date: Tue, 23 Jan 2018 14:41:19 +0800 Subject: [PATCH] Translated by qhwdw --- ...Epilogues Canaries and Buffer Overflows.md | 101 ------------------ ...Epilogues Canaries and Buffer Overflows.md | 100 +++++++++++++++++ 2 files changed, 100 insertions(+), 101 deletions(-) delete mode 100644 sources/tech/20140519 Epilogues Canaries and Buffer Overflows.md create mode 100644 translated/tech/20140519 Epilogues Canaries and Buffer Overflows.md diff --git a/sources/tech/20140519 Epilogues Canaries and Buffer Overflows.md b/sources/tech/20140519 Epilogues Canaries and Buffer Overflows.md deleted file mode 100644 index 5f3ddca532..0000000000 --- a/sources/tech/20140519 Epilogues Canaries and Buffer Overflows.md +++ /dev/null @@ -1,101 +0,0 @@ -Translating by qhwdw [Epilogues, Canaries, and Buffer Overflows][1] -============================================================ - -Last week we looked at [how the stack works][2] and how stack frames are built during function prologues. Now it's time to look at the inverse process as stack frames are destroyed in function epilogues. Let's bring back our friend add.c: - -Simple Add Program - add.c - -``` -int add(int a, int b) -{ - int result = a + b; - return result; -} - -int main(int argc) -{ - int answer; - answer = add(40, 2); -} -``` - - -We're executing line 4, right after the assignment of a + b into result. This is what happens: - -![](https://manybutfinite.com/img/stack/returnFromAdd.png) - -The first instruction is redundant and a little silly because we know eax is already equal to result, but this is what you get with optimization turned off. The leave instruction then runs, doing two tasks for the price of one: it resets esp to point to the start of the current stack frame, and then restores the saved ebp value. These two operations are logically distinct and thus are broken up in the diagram, but they happen atomically if you're tracing with a debugger. - -After leave runs the previous stack frame is restored. The only vestige of the call to add is the return address on top of the stack. It contains the address of the instruction in main that must run after add is done. The ret instruction takes care of it: it pops the return address into the eip register, which points to the next instruction to be executed. The program has now returned to main, which resumes: - -![](https://manybutfinite.com/img/stack/returnFromMain.png) - -main copies the return value from add into local variable answer and then runs its own epilogue, which is identical to any other. Again the only peculiarity in main is that the saved ebp is null, since it is the first stack frame in our code. In the last step, execution has been returned to the C runtime (libc), which will exit to the operating system. Here's a diagram with the [full return sequence][3] for those who need it. - -You now have an excellent grasp of how the stack operates, so let's have some fun and look at one of the most infamous hacks of all time: exploiting the stack buffer overflow. Here is a vulnerable program: - -Vulnerable Program - buffer.c - -| -``` -void doRead() -{ - char buffer[28]; - gets(buffer); -} - -int main(int argc) -{ - doRead(); -} -``` - -The code above uses [gets][4] to read from standard input. gets keeps reading until it encounters a newline or end of file. Here's what the stack looks like after a string has been read: - -![](https://manybutfinite.com/img/stack/bufferCopy.png) - -The problem here is that gets is unaware of buffer's size: it will blithely keep reading input and stuffing data into the stack beyond buffer, obliterating the saved ebp value, return address, and whatever else is below. To exploit this behavior, attackers craft a precise payload and feed it into the program. This is what the stack looks like during an attack, after the call to gets: - -![](https://manybutfinite.com/img/stack/bufferOverflowExploit.png) - -The basic idea is to provide malicious assembly code to be executed and overwrite the return address on the stack to point to that code. It is a bit like a virus invading a cell, subverting it, and introducing some RNA to further its goals. - -And like a virus, the exploit's payload has many notable features. It starts with several nop instructions to increase the odds of successful exploitation. This is because the return address is absolute and must be guessed, since attackers don't know exactly where in the stack their code will be stored. But as long as they land on a nop, the exploit works: the processor will execute the nops until it hits the instructions that do work. - -The exec /bin/sh symbolizes raw assembly instructions that execute a shell (imagine for example that the vulnerability is in a networked program, so the exploit might provide shell access to the system). The idea of feeding raw assembly to a program expecting a command or user input is shocking at first, but that's part of what makes security research so fun and mind-expanding. To give you an idea of how weird things get, sometimes the vulnerable program calls tolower or toupper on its inputs, forcing attackers to write assembly instructions whose bytes do not fall into the range of upper- or lower-case ascii letters. - -Finally, attackers repeat the guessed return address several times, again to tip the odds ever in their favor. By starting on a 4-byte boundary and providing multiple repeats, they are more likely to overwrite the original return address on the stack. - -Thankfully, modern operating systems have a host of [protections against buffer overflows][5], including non-executable stacks and stack canaries. The "canary" name comes from the [canary in a coal mine][6] expression, an addition to computer science's rich vocabulary. In the words of Steve McConnell: - -> Computer science has some of the most colorful language of any field. In what other field can you walk into a sterile room, carefully controlled at 68°F, and find viruses, Trojan horses, worms, bugs, bombs, crashes, flames, twisted sex changers, and fatal errors? Steve McConnellCode Complete 2 - -At any rate, here's what a stack canary looks like: - -![](https://manybutfinite.com/img/stack/bufferCanary.png) - -Canaries are implemented by the compiler. For example, GCC's [stack-protector][7] option causes canaries to be used in any function that is potentially vulnerable. The function prologue loads a magic value into the canary location, and the epilogue makes sure the value is intact. If it's not, a buffer overflow (or bug) likely happened and the program is aborted via [__stack_chk_fail][8]. Due to their strategic location on the stack, canaries make the exploitation of stack buffer overflows much harder. - -This finishes our journey within the depths of the stack. We don't want to delve too greedily and too deep. Next week we'll go up a notch in abstraction to take a good look at recursion, tail calls and other tidbits, probably using Google's V8\. To end this epilogue and prologue talk, I'll close with a cherished quote inscribed on a monument in the American National Archives: - -![](https://manybutfinite.com/img/stack/past-is-prologue.jpg) - --------------------------------------------------------------------------------- - -via:https://manybutfinite.com/post/epilogues-canaries-buffer-overflows/ - -作者:[Gustavo Duarte][a] -译者:[译者ID](https://github.com/译者ID) -校对:[校对者ID](https://github.com/校对者ID) - -本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 - -[a]:http://duartes.org/gustavo/blog/about/ -[1]:https://manybutfinite.com/post/epilogues-canaries-buffer-overflows/ -[2]:https://manybutfinite.com/post/journey-to-the-stack -[3]:https://manybutfinite.com/img/stack/returnSequence.png -[4]:http://linux.die.net/man/3/gets -[5]:http://paulmakowski.wordpress.com/2011/01/25/smashing-the-stack-in-2011/ -[6]:http://en.wiktionary.org/wiki/canary_in_a_coal_mine -[7]:http://gcc.gnu.org/onlinedocs/gcc-4.2.3/gcc/Optimize-Options.html -[8]:http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---stack-chk-fail-1.html \ No newline at end of file diff --git a/translated/tech/20140519 Epilogues Canaries and Buffer Overflows.md b/translated/tech/20140519 Epilogues Canaries and Buffer Overflows.md new file mode 100644 index 0000000000..b74400a68b --- /dev/null +++ b/translated/tech/20140519 Epilogues Canaries and Buffer Overflows.md @@ -0,0 +1,100 @@ +[探秘“栈”之旅(II)—— 谢幕,金丝雀,和缓冲区溢出][1] +============================================================ + +上一周我们讲解了 [栈是如何工作的][2] 以及在函数的开端上栈帧是如何被构建的。今天,我们来看一下它的相反的过程,在函数结束时,栈帧是如何被销毁的。重新回到我们的 add.c 上: + +简单的一个做加法的程序 - add.c + +``` +int add(int a, int b) +{ + int result = a + b; + return result; +} + +int main(int argc) +{ + int answer; + answer = add(40, 2); +} +``` + + +在运行到第 4 行时,在把 `a + b` 值赋给 `result` 后,这时发生了什么: + +![](https://manybutfinite.com/img/stack/returnFromAdd.png) + +第一个指令是有些多余而且有点傻的,因为我们知道 `eax` 已经等于了 `result` ,但这就是关闭优化时得到的结果。剩余的指令接着运行,这一小段做了两个任务:重置 `esp` 并将它指向到当前栈帧开始的地方,另一个是恢复在 `ebp` 中保存的值。这两个操作在逻辑上是独立的,因此,在图中将它们分开来说,但是,如果你使用一个调试器去跟踪,你就会发现它们都是自动发生的。 + +在运行完毕后,恢复了前一个栈帧。`add` 调用唯一留下的东西就是在栈顶部的返回地址。它包含了运行完 `add` 之后在 `main` 中的指令的地址。它带来的是 `ret` 指令:它弹出返回地址到 `eip` 寄存器(译者注:32位的指令寄存器),这个寄存器指向下一个要执行的指令。现在程序将返回到 `main` ,主要部分如下: + +![](https://manybutfinite.com/img/stack/returnFromMain.png) + +`main` 从 `add` 中拷贝返回值到本地变量 `answer`,然后,运行它的“谢幕仪式”,这一点和其它的函数是一样的。在 `main` 中唯一的怪异之处是,它在 `ebp` 中保存了 `null` 值,因为,在我们的代码中它是第一个栈帧。最后一步执行的是,返回到 C 运行时库(libc),它将退回到操作系统中。这里为需要的人提供了一个 [完整的返回顺序][3] 的图。 + +现在,你已经理解了栈是如何运作的,所以我们现在可以来看一下,一直以来最著名的黑客行为:挖掘缓冲区溢出。这是一个有漏洞的程序: + +有漏洞的程序 - buffer.c + +``` +void doRead() +{ + char buffer[28]; + gets(buffer); +} + +int main(int argc) +{ + doRead(); +} +``` + +上面的代码中使用了 [gets][4] 从标准输入中去读取内容。`gets` 持续读取直到一个新行或者文件结束。下图是读取一个字符串之后栈的示意图: + +![](https://manybutfinite.com/img/stack/bufferCopy.png) + +在这里存在的问题是,`gets` 并不知道缓冲区大小:它毫无查觉地持续读取输入内容,并将读取的内容填入到栈那边的缓冲区,清除保存在 `ebp` 中的值,返回地址,下面的其它内容也是如此。对于挖掘行为,攻击者制作一个载荷片段并将它“喂”给程序。在这个时候,栈应该是下图所示的样子,然后去调用 `gets`: + +![](https://manybutfinite.com/img/stack/bufferOverflowExploit.png) + +基本的想法是提供一个恶意的汇编代码去运行,通过覆写栈上的返回地址指向到那个代码。这有点像病毒侵入一个细胞,颠覆它,然后引入一些 RNA 去达到它的目的。 + +和病毒一样,挖掘者的载荷有许多特别的功能。它从使用几个 `nop` 指令开始,以提升成功挖掘漏洞的可能性。这是因为返回的地址是一个靠猜测的且不受约束的地址,因此,攻击者并不知道保存它的代码的栈的准确位置。但是,只要它们进入一个 `nop`,这个漏洞挖掘工作就会进行:处理器将运行 `nops`,直到击中它希望去运行的指令。 + +exec /bin/sh 表示运行一个 shell(假设漏洞是在一个网络程序中,因此,这个漏洞可能提供一个访问系统的 shell)的原生汇编指令。将原生汇编指令嵌入到一个程序中,使程序产生一个命令窗口或者用户输入的想法是很可怕的,但是,那只是让安全研究如此有趣且“脑洞大开”的一部分而已。对于防范这个怪异的 `get`, 给你提供一个思路,有时候,在有漏洞的程序上,让它的输入转换为小写或者大写,将迫使攻击者写的汇编指令的完整字节不属于小写或者大写的 ascii 字母的范围内。 + +最后,攻击者重放几次猜测的返回地址,这将再次提升他们的胜算。通过从一个 4 字节的边界上多次重放,它们可能会覆写栈上的原始返回地址。 + +幸亏,现代操作系统有了 [防止缓冲区溢出][5] 的一系列保护措施,包括不可执行的栈和栈金丝雀(stack canaries)。这个 “金丝雀(canary)” 名字来自 [煤矿中的金丝雀(canary in a coal mine)][6] 中的表述(译者注:指在煤矿工人下井时,带一只金丝雀,因为金丝雀对煤矿中的瓦斯气体非常敏感,如果进入煤矿后,金丝雀死亡,说明瓦斯超标,矿工会立即撤出煤矿。金丝雀做为煤矿中瓦斯预警器来使用),是对丰富的计算机科学词汇的补充,用 Steve McConnell 的话解释如下: + +> 计算机科学拥有比其它任何领域都丰富多彩的语言,在其它的领域中你进入一个无菌室,小心地将温度控制在 68°F,然后,能找到病毒、特洛伊木马、蠕虫、臭虫、炸弹、崩溃、爆发、扭曲的变性者、以及致命错误吗? Steve McConnell 代码大全 2 + +不管怎么说,这里所谓的“栈金丝雀”应该看起来是这个样子的: + +![](https://manybutfinite.com/img/stack/bufferCanary.png) + +金丝雀是通过汇编来实现的。例如,由于 GCC 的 [栈保护器][7] 选项的原因使金丝雀被用于任何可能有漏洞的函数上。函数开端加载一个神奇的值到金丝雀的位置,并且在函数结束调用时确保这个值完好无损。如果这个值发生了变化,那就表示发生了一个缓冲区溢出(或者 bug),这时,程序通过 [__stack_chk_fail][8] 被终止运行。由于金丝雀处于栈的关键位置上,它使得栈缓冲区溢出的漏洞挖掘变得非常困难。 + +深入栈的探秘之旅结束了。我并不想过于深入。下一周我将深入递归、尾调用以及其它相关内容。或许要用到谷歌的 V8 引擎。为总结函数的开端和结束的讨论,我引述了美国国家档案馆纪念雕像上的一句名言:(what is past is prologue) + +![](https://manybutfinite.com/img/stack/past-is-prologue.jpg) + +-------------------------------------------------------------------------------- + +via:https://manybutfinite.com/post/epilogues-canaries-buffer-overflows/ + +作者:[Gustavo Duarte][a] +译者:[qhwdw](https://github.com/qhwdw) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]:http://duartes.org/gustavo/blog/about/ +[1]:https://manybutfinite.com/post/epilogues-canaries-buffer-overflows/ +[2]:https://manybutfinite.com/post/journey-to-the-stack +[3]:https://manybutfinite.com/img/stack/returnSequence.png +[4]:http://linux.die.net/man/3/gets +[5]:http://paulmakowski.wordpress.com/2011/01/25/smashing-the-stack-in-2011/ +[6]:http://en.wiktionary.org/wiki/canary_in_a_coal_mine +[7]:http://gcc.gnu.org/onlinedocs/gcc-4.2.3/gcc/Optimize-Options.html +[8]:http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/libc---stack-chk-fail-1.html \ No newline at end of file