mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
cc29c30d32
101
published/20140519 Epilogues Canaries and Buffer Overflows.md
Normal file
101
published/20140519 Epilogues Canaries and Buffer Overflows.md
Normal file
@ -0,0 +1,101 @@
|
||||
探秘“栈”之旅(II):结语、金丝雀和缓冲区溢出
|
||||
============================================================
|
||||
|
||||
上一周我们讲解了 [栈是如何工作的][2] 以及在函数的<ruby>序言<rt>prologue</rt></ruby>上栈帧是如何被构建的。今天,我们来看一下它的相反的过程,在函数<ruby>结语<rt>epilogue</rt></ruby>中栈帧是如何被销毁的。重新回到我们的 `add.c` 上:
|
||||
|
||||
```
|
||||
int add(int a, int b)
|
||||
{
|
||||
int result = a + b;
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc)
|
||||
{
|
||||
int answer;
|
||||
answer = add(40, 2);
|
||||
}
|
||||
```
|
||||
|
||||
*简单的一个做加法的程序 - add.c*
|
||||
|
||||
在运行到第 4 行时,在把 `a + b` 值赋给 `result` 后,这时发生了什么:
|
||||
|
||||
![](https://manybutfinite.com/img/stack/returnFromAdd.png)
|
||||
|
||||
第一个指令是有些多余而且有点傻的,因为我们知道 `eax` 已经等于 `result` 了,但这就是关闭优化时得到的结果。`leave` 指令接着运行,这一小段做了两个任务:重置 `esp` 并将它指向到当前栈帧开始的地方,另一个是恢复在 `ebp` 中保存的值。这两个操作在逻辑上是独立的,因此,在图中将它们分开来说,但是,如果你使用一个调试器去跟踪,你就会发现它们都是自动发生的。
|
||||
|
||||
在 `leave` 运行后,恢复了前一个栈帧。`add` 调用唯一留下的东西就是在栈顶部的返回地址。它包含了运行完 `add` 之后在 `main` 中必须运行的指令的地址。`ret` 指令用来处理它:它弹出返回地址到 `eip` 寄存器(LCTT 译注:32 位的指令寄存器),这个寄存器指向下一个要执行的指令。现在程序将返回到 `main` ,主要部分如下:
|
||||
|
||||
![](https://manybutfinite.com/img/stack/returnFromMain.png)
|
||||
|
||||
`main` 从 `add` 中拷贝返回值到本地变量 `answer`,然后,运行它自己的<ruby>结语<rt>epilogue</rt></ruby>,这一点和其它的函数是一样的。在 `main` 中唯一的怪异之处是,保存在 `ebp` 中的是 `null` 值,因为它是我们的代码中的第一个栈帧。最后一步执行的是,返回到 C 运行时库(`libc`),它将退回到操作系统中。这里为需要的人提供了一个 [完整的返回顺序][3] 的图。
|
||||
|
||||
现在,你已经理解了栈是如何运作的,所以我们现在可以来看一下,一直以来最臭名昭著的黑客行为:利用缓冲区溢出。这是一个有漏洞的程序:
|
||||
|
||||
```
|
||||
void doRead()
|
||||
{
|
||||
char buffer[28];
|
||||
gets(buffer);
|
||||
}
|
||||
|
||||
int main(int argc)
|
||||
{
|
||||
doRead();
|
||||
}
|
||||
```
|
||||
|
||||
*有漏洞的程序 - buffer.c*
|
||||
|
||||
上面的代码中使用了 [gets][4] 从标准输入中去读取内容。`gets` 持续读取直到一个新行或者文件结束。下图是读取一个字符串之后栈的示意图:
|
||||
|
||||
![](https://manybutfinite.com/img/stack/bufferCopy.png)
|
||||
|
||||
在这里存在的问题是,`gets` 并不知道缓冲区(`buffer`)大小:它毫无查觉地持续读取输入内容,并将读取的内容填入到缓冲区那边的栈,清除保存在 `ebp` 中的值、返回地址,下面的其它内容也是如此。对于利用这种行为,攻击者制作一个精密的载荷并将它“喂”给程序。在这个时候,栈应该是下图所示的样子,然后去调用 `gets`:
|
||||
|
||||
![](https://manybutfinite.com/img/stack/bufferOverflowExploit.png)
|
||||
|
||||
基本的思路是提供一个恶意的汇编代码去运行,通过覆写栈上的返回地址指向到那个代码。这有点像病毒侵入一个细胞,颠覆它,然后引入一些 RNA 去达到它的目的。
|
||||
|
||||
和病毒一样,挖掘者的载荷有许多特别的功能。它以几个 `nop` 指令开始,以提升成功利用的可能性。这是因为返回的地址是一个绝对的地址,需要猜测,而攻击者并不知道保存它的代码的栈的准确位置。但是,只要它们进入一个 `nop`,这个漏洞利用就成功了:处理器将运行 `nop` 指令,直到命中它希望去运行的指令。
|
||||
|
||||
`exec /bin/sh` 表示运行一个 shell 的原始汇编指令(假设漏洞是在一个网络程序中,因此,这个漏洞可能提供一个访问系统的 shell)。将一个命令或用户输入以原始汇编指令的方式嵌入到一个程序中的思路是很可怕的,但是,那只是让安全研究如此有趣且“脑洞大开”的一部分而已。对于防范这个怪异的 `get`,给你提供一个思路,有时候,在有漏洞的程序上,让它的输入转换为小写或者大写,将迫使攻击者写的汇编指令的完整字节不属于小写或者大写的 ascii 字母的范围内。
|
||||
|
||||
最后,攻击者重复猜测几次返回地址,这将再次提升他们的胜算。以 4 字节为界进行多次重复,它们就会更好地覆写栈上的原始返回地址。
|
||||
|
||||
幸亏,现代操作系统有了 [防止缓冲区溢出][5] 的一系列保护措施,包括不可执行的栈和<ruby>栈内金丝雀<rt>stack canary</rt></ruby>。这个 “<ruby>金丝雀<rt>canary</rt></ruby>” 名字来自 <ruby>[煤矿中的金丝雀][6]<rt>canary in a coal mine</rt></ruby> 中的表述(LCTT 译注:指在过去煤矿工人下井时会带一只金丝雀,因为金丝雀对煤矿中的瓦斯气体非常敏感,如果进入煤矿后,金丝雀死亡,说明瓦斯超标,矿工会立即撤出煤矿。金丝雀做为煤矿中瓦斯预警器来使用),这是对计算机科学词汇的补充,用 Steve McConnell 的话解释如下:
|
||||
|
||||
> 计算机科学拥有比其它任何领域都丰富多彩的语言,在其它的领域中你进入一个无菌室,小心地将温度控制在 68°F,然后,能找到病毒、特洛伊木马、蠕虫、臭虫(bug)、炸弹(逻辑炸弹)、崩溃、爆发(口水战)、扭曲的变性者(双绞线转换头),以及致命错误吗?
|
||||
|
||||
> —— Steve McConnell 《代码大全 2》
|
||||
|
||||
不管怎么说,这里所谓的“栈金丝雀”应该看起来是这个样子的:
|
||||
|
||||
![](https://manybutfinite.com/img/stack/bufferCanary.png)
|
||||
|
||||
金丝雀是通过汇编来实现的。例如,由于 GCC 的 [栈保护器][7] 选项的原因使金丝雀能被用于任何可能有漏洞的函数上。函数序言加载一个魔法值到金丝雀的位置,并且在函数结语时确保这个值完好无损。如果这个值发生了变化,那就表示发生了一个缓冲区溢出(或者 bug),这时,程序通过 [`__stack_chk_fail`][8] 被终止运行。由于金丝雀处于栈的关键位置上,它使得栈缓冲区溢出的漏洞挖掘变得非常困难。
|
||||
|
||||
深入栈的探秘之旅结束了。我并不想过于深入。下一周我将深入递归、尾调用以及其它相关内容。或许要用到谷歌的 V8 引擎。作为函数的序言和结语的讨论的结束,我引述了美国国家档案馆纪念雕像上的一句名言:(<ruby>凡是过去 皆为序章<rt>what is past is prologue</rt></ruby>)。
|
||||
|
||||
![](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)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [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://linux.cn/article-9645-1.html
|
||||
[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
|
@ -3,33 +3,31 @@
|
||||
|
||||
![](https://fedoramagazine.org/wp-content/uploads/2017/12/zsh-816x345.jpg)
|
||||
|
||||
对于一些人来说,终端可能会很吓人。但终端不仅仅是在黑屏中输入。它通常运行一个 shell,因为它围绕着内核调用。shell 是一个基于文本的界面,可让你在系统上运行命令。它有时也被称为命令行解释器或 CLI。与大多数Linux发行版一样,Fedora带有bash作为默认shell。但是,它不是唯一可用的 shell,你可以安装其他的 shell。本文重点介绍 Z Shell 或 zsh。
|
||||
对于一些人来说,终端可能会很吓人。但终端不仅仅是一个输入的黑屏。它通常运行一个 shell(外壳),如此称呼的原因是它围绕着内核。shell 是一个基于文本的界面,可让你在系统上运行命令。它有时也被称为<ruby>命令行解释器<rt>command line interpreter</rt></ruby>(CLI)。与大多数 Linux 发行版一样,Fedora 带有 bash 作为默认 shell。但是,它不是唯一可用的 shell,你可以安装其他的 shell。本文重点介绍 Z Shell (即 zsh)。
|
||||
|
||||
Bash 是对 UNIX 中提供的旧 Bourne shell(sh)的重写。通过更好的交互,zsh 旨在比 bash 更友善。它的一些有用功能是:
|
||||
Bash 是对 UNIX 中提供的旧式 Bourne shell(sh)的重写(LCTT 译注:Bourne Again SHell)。zsh 视图通过更好的交互以比 bash 更友善。它的一些有用功能是:
|
||||
|
||||
* 可编程的命令行补全
|
||||
* 在运行的 shell 会话之间共享命令历史
|
||||
* 拼写纠正
|
||||
* 可加载模块
|
||||
* 交互选择文件和文件夹
|
||||
|
||||
|
||||
* 交互式选择文件和文件夹
|
||||
|
||||
zsh 在 Fedora 仓库中存在。要安装,请运行以下命令:
|
||||
|
||||
```
|
||||
$ sudo dnf install zsh
|
||||
|
||||
```
|
||||
|
||||
### 使用 zsh
|
||||
|
||||
要开始使用它,只需输入 zsh,新的 shell 在第一次运行时显示向导。该向导可帮助你配置初始功能,如历史记录行为和自动补全。或者你可以选择保持[ rc 文件][1] 为空:
|
||||
要开始使用它,只需输入 `zsh`,新的 shell 在第一次运行时显示向导。该向导可帮助你配置初始功能,如历史记录行为和自动补全。或者你可以选择保持 [rc 文件][1] 为空:
|
||||
|
||||
![zsh First Run Wizzard][2]
|
||||
|
||||
如果输入 1,则启动配置向导。其他选项立即启动 shell。
|
||||
如果输入 `1`,则启动配置向导。其他选项立即启动 shell。
|
||||
|
||||
请注意,与 bash 相同,用户提示符是 **%** 而不是 **$**。这里的一个重要功能是自动补全功能,它允许你使用 Tab 键在文件和目录之间移动,非常类似于菜单:
|
||||
请注意,用户提示符是 `%` 而不是与 bash 的 `$`。这里的一个重要功能是自动补全功能,它允许你使用 `Tab` 键在文件和目录之间移动,非常类似于菜单:
|
||||
|
||||
![zsh cd Feature][3]
|
||||
|
||||
@ -39,17 +37,16 @@ $ sudo dnf install zsh
|
||||
|
||||
## 使用 zsh 成为你的默认 shell
|
||||
|
||||
zsh 提供了很多插件,如 zsh-syntax-highlighting 和著名的 “Oh my zsh”([在此查看其页面][5])。也许你希望将其设为默认 shell,以便在你在开始会话或打开终端时运行。为此,请使用 chsh(“更改 shell”)命令:
|
||||
zsh 提供了很多插件,如 zsh-syntax-highlighting 和著名的 “Oh my zsh”([在此查看其页面][5])。也许你希望将其设为默认 shell,以便在你在开始会话或打开终端时运行。为此,请使用 `chsh`(“更改 shell”)命令:
|
||||
|
||||
```
|
||||
$ chsh -s $(which zsh)
|
||||
|
||||
```
|
||||
|
||||
这个命令告诉你的系统你要设置(-s)默认shell 的正确位置(which zsh)。
|
||||
这个命令告诉你的系统你要设置(`-s`)默认 shell 为该 shell 的正确位置(`which zsh`)。
|
||||
|
||||
图片来自 [Flickr][7] 由 [Kate Ter Haar][6] 提供(CC BY-SA)。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/set-zsh-fedora-system/
|
||||
@ -57,7 +54,7 @@ via: https://fedoramagazine.org/set-zsh-fedora-system/
|
||||
作者:[Eduard Lucena][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,6 +1,8 @@
|
||||
4 种基于 Markdown 的幻灯片生成器
|
||||
======
|
||||
|
||||
> 这些简单的幻灯片创建工具可以无缝地使用 Markdown,可以让你的演示添加魅力。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bus_presentation.png?itok=CQeyO61b)
|
||||
|
||||
假设你需要做一个<ruby>演示<rt>presentation</rt></ruby>。在准备的过程中,你想到“我需要写几张幻灯片”。
|
||||
@ -13,18 +15,17 @@
|
||||
|
||||
在这些工具中,[Landslide][3] 具有更高的灵活性。它是一个命令行工具,可以将 Markdown、[reStructuredText][4] 或 [Textile][5] 格式的文件转换为基于 [Google HTML5 幻灯片模板][6]的 HTML 文件。
|
||||
|
||||
你要做的不过是编写 Markdown 格式的幻灯片源文件,打开一个终端窗口并运行 `landslide` 命令即可,其中命令参数为 Markdown 文件的文件名。Landslide 会生成 presentation.html,可以在任何 Web 浏览器中打开。简单吧?
|
||||
你要做的不过是编写 Markdown 格式的幻灯片源文件,打开一个终端窗口并运行 `landslide` 命令即可,其中命令参数为 Markdown 文件的文件名。Landslide 会生成 `presentation.html`,可以在任何 Web 浏览器中打开。简单吧?
|
||||
|
||||
但不要被简易的操作误导你。Landslide 提供了不少有用的特性,例如增加注记以及为幻灯片增加配置文件。为何要使用这些特性呢?按照 Landslide 开发者的说法,这样可以汇聚不同演示中的源文件目录并重用。
|
||||
|
||||
|
||||
![landslide.png][8]
|
||||
|
||||
在 Landslide 演示中查看演示者注记。
|
||||
*在 Landslide 演示中查看演示者注记*
|
||||
|
||||
### Marp
|
||||
|
||||
[Marp][9] 仍处于开发中,但值得期待。它是 "Markdown Presentation Writer" 的简写。Marp 是一个基于 [Electron][10] 的工具,让你在一个简单的双栏编辑器中编写幻灯片:在左栏编写 Markdown,在右栏中预览效果。
|
||||
[Marp][9] 仍处于开发中,但值得期待。它是 “Markdown Presentation Writer” 的简写。Marp 是一个基于 [Electron][10] 的工具,让你在一个简单的双栏编辑器中编写幻灯片:在左栏编写 Markdown,在右栏中预览效果。
|
||||
|
||||
Marp 支持 [GitHub 风格 Markdown][11]。如果你需要一个使用 GitHub 风格 Markdown 编写幻灯片的快速教程,可以参考 [示例项目][12]。GitHub 风格 Markdown 比基础 Markdown 更加灵活。
|
||||
|
||||
@ -33,20 +34,20 @@ Marp 只自带两个基础主题,但你可以为幻灯片增加背景图片、
|
||||
|
||||
![marp.png][14]
|
||||
|
||||
使用 Marp 编辑简单的幻灯片
|
||||
*使用 Marp 编辑简单的幻灯片*
|
||||
|
||||
### Pandoc
|
||||
|
||||
你可能已经知道 [pandoc][15] 是一种支持多种<ruby>标记语言<rt>markup languages</rt></ruby>相互转换的神奇工具。但你可能不知道,pandoc 可以将 Markdown 格式文件转换为 [Slidy][16]、[Slideous][17]、[DZSlides][18] 和 [Reveal.js][20] 等演示框架支持的优雅 HTML 幻灯片。如果你使用 [LaTeX][21],可以使用 [Beamer 软件包][22]输出 PDF 格式的幻灯片。
|
||||
|
||||
你需要在幻灯片中[使用特定格式][23],但可以通过[变量][24]控制效果。你也可以更改幻灯片的外观与风格,增加幻灯片之间的暂停,添加演示者注记等。
|
||||
你需要在幻灯片中[使用特定格式][23],但可以通过[变量][24]控制其效果。你也可以更改幻灯片的外观与风格,增加幻灯片之间的暂停,添加演示者注记等。
|
||||
|
||||
当然,你需要在你的主机上安装你喜欢的演示框架,因为 Pandoc 只生成原始幻灯片文件。
|
||||
|
||||
|
||||
![pandoc.png][26]
|
||||
|
||||
查看使用 Pandoc 和 DZSlides 创建的幻灯片
|
||||
*查看使用 Pandoc 和 DZSlides 创建的幻灯片*
|
||||
|
||||
### Hacker Slides
|
||||
|
||||
@ -56,16 +57,15 @@ Marp 只自带两个基础主题,但你可以为幻灯片增加背景图片、
|
||||
|
||||
你可能会说,你不使用 Sandstorm 或 Sandstorm Oasis 怎么办?不要担心,Hacker Slides 提供了可以在桌面或服务器上运行的[版本][30]。
|
||||
|
||||
|
||||
![hacker-slides.png][32]
|
||||
|
||||
在 Hacker Slides 中编辑幻灯片
|
||||
*在 Hacker Slides 中编辑幻灯片*
|
||||
|
||||
### 两点特别补充
|
||||
|
||||
如果你使用 [Jupyter <ruby>笔记本<rt>Notebooks</rt></ruby>][33] (参考社区版主 Don Watkins 的[文章][34])发布数据或指令文本,你可以使用 [Jupyter2slides][35]。该工具基于 Reveal.js,可以将笔记本转换为一系列精美的 HTML 幻灯片。
|
||||
|
||||
如果你倾向于托管应用,试试 [GitPitch][36],支持 GitHub,GitLab 和 Bitbucket。只需在将幻灯片源文件推送到支持的代码仓库中,在 GitPitch 中指向该仓库,这样你就可以在 GitPitch 网站上看到你的幻灯片了。
|
||||
如果你倾向于托管应用,试试 [GitPitch][36],支持 GitHub、GitLab 和 Bitbucket。只需在将幻灯片源文件推送到支持的代码仓库中,在 GitPitch 中指向该仓库,这样你就可以在 GitPitch 网站上看到你的幻灯片了。
|
||||
|
||||
你有最喜欢的基于 Markdown 的幻灯片生成器吗?留下评论分享吧。
|
||||
|
||||
@ -76,7 +76,7 @@ via: https://opensource.com/article/18/5/markdown-slide-generators
|
||||
作者:[Scott Nesbitt][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[pinewall](https://github.com/pinewall)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -114,6 +114,6 @@ via: https://opensource.com/article/18/5/markdown-slide-generators
|
||||
[31]:/file/397456
|
||||
[32]:https://opensource.com/sites/default/files/uploads/hacker-slides.png (hacker-slides.png)
|
||||
[33]:http://jupyter.org/
|
||||
[34]:https://opensource.com/article/18/3/getting-started-jupyter-notebooks
|
||||
[34]:https://linux.cn/article-9664-1.html
|
||||
[35]:https://github.com/datitran/jupyter2slides
|
||||
[36]:https://gitpitch.com/
|
@ -1,100 +0,0 @@
|
||||
[探秘“栈”之旅(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
|
Loading…
Reference in New Issue
Block a user