麻省理工学院的课程“计算机系统安全”。 第2课:“控制黑客攻击”,第2部分

麻省理工学院。 讲座课程#6.858。 “计算机系统的安全性。” Nikolai Zeldovich,James Mickens。 2014年


计算机系统安全是一门有关开发和实施安全计算机系统的课程。 讲座涵盖了威胁模型,危害安全性的攻击以及基于最新科学研究的安全技术。 主题包括操作系统(OS)安全性,功能,信息流管理,语言安全性,网络协议,硬件安全性和Web应用程序安全性。

第1课:“简介:威胁模型” 第1 部分 / 第2 部分 / 第3部分
第2课:“控制黑客攻击”, 第1 部分 / 第2 部分 / 第3部分

因此,我们有一个缓冲来放置“ canary”。 在其上方是已保存的断点指针已保存的EBP值,并且返回地址位于其上方。 如果您还记得,溢出是自下而上的,因此在到达寄信人地址之前,它将首先销毁“ canary”。



观众:为什么会影响“金丝雀”?

教授:因为假设攻击者不知道如何任意“跳”入内存。 传统的内存溢出攻击始于黑客检查缓冲区大小限制,然后从底线开始溢出。 但是您是对的-如果攻击者可以直接进入回信地址栏,那么“金丝雀”将无法帮助我们。 但是,使用传统的缓冲区溢出攻击,所有事情都应该以这种方式发生-从下到上。

因此,使用“ canary”的主要思想是我们允许恶意利用溢出内存缓冲区。 我们有一个运行时代码,当从函数返回时,将检查“ canary”以确保其具有正确的值。

受众:攻击者可以重写寄信人地址并更改“金丝雀”吗? 他如何验证它已被修改,但继续履行其职能?

教授:是的,也许。 因此,您应该有一些代码可以在函数返回之前进行实际检查。 也就是说,在这种情况下,必须有编译器的支持,该编译器实际上将扩展调用约定,调用约定 。 因此,在我们考虑该值的有效性以确保“ canary”没有被破坏之前,会发生返回序列的一部分。 只有在那之后,我们才能考虑其他事情。

受众:攻击者无法知道或猜测“金丝雀”是什么意思吗?

教授:这正是我要谈的! 该电路有什么问题? 例如,如果我们将值A放入每个程序怎么办? 还是A的4个值的整个分支? 当然,任何黑客都可以找出缓冲区的大小,其容量,从而确定“ canary”在任何系统中的位置。 因此,我们可以使用放入“金丝雀”中的不同类型的数量来防止这种情况。

您可以用我们的“金丝雀”做一件事。 这将是一个非常有趣的“ canary”类型,它使用C程序函数并处理特殊字符,即所谓的“ canary”确定性类型。



假设您为“ canary”使用了字符0,二进制值为零就是零字节,即ASCII中的零字符。 值-1表示返回到上一个位置,依此类推。 当许多功能遇到字符或值(例如0,CR,LF,-1)时,它们将停止或更改操作。 想象一下,作为一名黑客,您使用一些字符串管理功能来增加缓冲区,在“ canary”中遇到字符0,并且过程停止了! 如果使用“回车” -1功能(通常用作行终止符),则该过程也将停止。 因此-1是另一个魔术符号。

“ canary”中还有另外一件事可以使用-这些是随机值,攻击者很难猜测。 随机值的功效取决于攻击者猜测它的难度。 例如,如果攻击者意识到您的系统中只有3位熵,那么他将能够使用蛮力攻击。 因此,使用随机数防御攻击的可能性非常有限。



受众:通常发生的情况是,我从另一个缓冲区读取并将写入的内容写入该堆栈的缓冲区。 在这种情况下,“ canary”的随机值似乎没有用,因为我从另一个缓冲区读取了数据,并且知道“ canary”在哪里。 我有另一个缓冲区,我控制并且从未检查过。 在此缓冲区中,我可以放入很多我想放入的内容。 我不需要随机的“ canary”,因为我可以放心地重写它。 因此,我看不出它是如何工作的-在您提出的方案中,当从缓冲区读取数据时函数停止运行。

教授:我理解您的问题-您的意思是我们使用确定性的“ canary”,但不使用标准库中可以被字符0,CR,LF,-1欺骗的功能之一。 然后,是的,在您描述的情况下,不需要“金丝雀”。

这个想法是您可以从任何地方用字节填充此缓冲区,但是任何允许您猜测这些值或随机获取它们的值都会导致失败。

受众:是否可以将秒或毫秒之类的数字用作随机数,并在“金丝雀”中使用它们?

教授:数据呼叫所包含的事故并不像您想象的那么多。 因为该程序具有日志或您可以调用的函数以了解下载该程序的时间以及其他类似内容。 但是总的来说,您是对的-在实践中,如果您可以使用硬件设备(通常级别较低)且具有更好的系统时序,则这种方法可能会起作用。

听众:即使我们设法查看有关缓冲区溢出开始的日志,对我们什么时候拒绝请求仍然很重要。 而且,如果我们无法控制计算机向服务器发送请求所花费的时间,则可以确定地猜测确切的时间是值得怀疑的。

教授:很对,我已经说过邪恶在于细节,这就是这种情况。 换句话说,例如,如果您有某种方法来确定定时通道的类型,则可能会发现熵的数量或随机性的数量不会填满整个时间戳,而会填满更少的时间。 因此,攻击者可以确定执行此操作的小时和分钟,但无法确定。

观众:记录下来,减少自己的随机性是一个坏主意吗?

教授:绝对正确!

观众:也就是说,通常我们只需要使用系统支持的所有内容,对吧?

教授:是的,是的。 这就像我们自己的密码系统的发明一样,这是我们的毕业生有时想要做的另一件事。 但是我们不是国家安全局,我们也不是数学家,因此这通常会失败。 因此,您绝对正确。

但是,即使您使用系统随机性,仍然可以获得比预期更少的熵。 让我给你一个地址相位随机化的例子。 正是基于此原理, 堆栈金丝雀方法才起作用 。 由于我们从事计算机安全,因此您可能想知道“金丝雀”在什么情况下无法应付其任务,以及是否有办法使“金丝雀”失效。

一种这样的方式是通过重写函数指针的攻击。 因为如果对函数指针进行打击,那么“ canary”将无能为力。

假设您有一个格式为int * ptr ... ..的代码,它的初始化指针无关紧要,那么您就可以使用char buf缓冲区[128]gets(buf)函数,并在最底部有一个分配了一些值的指针: * ptr = 5

我注意到我们没有尝试攻击包含此代码的函数的返回地址。 如您所见,当缓冲区溢出时,位于其上方的指针地址将被损坏。 如果攻击者可以破坏此指针,则可以将5分配给他控制的地址之一。 每个人都能看到“金丝雀”在这里无济于事吗? 因为我们不攻击函数返回的路径。



观众:指针可以位于缓冲区下方吗?

教授:可以,但是特定变量的顺序取决于许多不同的事物,取决于编译器安排内容的方式,取决于硬件列的大小等等。 但是您是对的,如果缓冲区溢出上升,并且指针位于缓冲区下方,则溢出不会损坏它。

受众:为什么不能像您对寄信人地址那样将“金丝雀”与“金丝雀”功能相关联?

教授:这是一个有趣的时刻! 你可以做这样的事情。 实际上,您可以尝试想象一个编译器,只要它有一个指针,它总是尝试为某些东西添加一个附件。 但是,检查所有这些东西将太昂贵。 因为每次您要使用任何指针或调用任何函数,您都必须有一个代码来检查此“ canary”是否正确。 基本上,您可以做类似的事情,但这有意义吗? 我们看到“金丝雀”在这种情况下无济于事。

我们前面讨论的另一件事是,如果攻击者可以猜测随机性,那么原则上随机的“ canaries”将不起作用。 基于随机性创建安全资源是一个单独的,非常复杂的主题,因此我们不再赘述。



听众:那么金丝雀包含的位数少于返回地址? 因为否则您不能只记住该地址并检查它是否已更改?

教授:让我们看看。 当“ canary”位于缓冲区上方时,您正在谈论此方案,这意味着如果无法查看返回地址并检查是否已更改,则系统将不安全。



是的,没有。 请注意,如果发生缓冲区溢出攻击,则其上的所有内容都会被覆盖,因此仍然可能导致问题。 但是基本上,如果这些事情在某种程度上是不可变的,那么您可以做这样的事情。 但是问题在于,在很多情况下,处理返回地址是一件相当复杂的事情。 因为您可以想象可以从不同位置调用特殊函数,依此类推。 在这种情况下,我们会领先一些,如果在讲座结束时有时间,我们将返回到此。

在这些情况下,“金丝雀”可能会失败。 还有其他可能发生故障的地方,例如,攻击mallocfree函数时。 malloc函数以字节为单位分配一定大小的内存块,并返回指向该块开头的指针。 分配的内存块的内容未初始化,仍保留未定义的值。 free函数释放先前动态分配的内存。

这是C风格的独特攻击。让我们看看这里发生了什么。 想象一下,这里有两个指针p和q,我们使用malloc为这些指针分配1.024字节的内存。 假设我们利用攻击者控制的某种缓冲区错误来为str提供p的strcpy函数。 这是发生溢出的地方。 然后我们运行命令free qfree p 。 这是非常简单的代码,对吧?



我们有2个指针,我们为其分配了内存,我们将其中一个指针用于某个功能,发生缓冲区溢出,并释放两个指针的内存。

假设p和q的存储线在存储空间中彼此相邻。 在这种情况下,可能会发生坏事,对吧? 因为strcpy函数用于将str2的内容复制到str1Str2应该是指向以零结尾的字符串的指针,而strcpy返回指向str1的指针。 如果str1str2行重叠,则strcpy函数的行为未定义。

因此,处理内存pstrycpy函数可能同时影响分配给q的内存。 这可能会导致问题。

当您使用某种奇怪类型的指针时,有可能在您自己的代码中无意间执行了类似的操作。 一切似乎都可以正常工作,但是当您需要调用free函数时,就会出现这种麻烦。 攻击者可以利用它,我将解释为什么会发生这种情况。

想象一下,在freemalloc函数的实现内部,突出显示的块如下所示。

假设在该块的顶部有可见的应用程序数据,在下面有变量的大小。 该大小不是应用程序直接看到的大小,而是由freemalloc进行的一种“记帐”,以便您知道分配的内存缓冲区的大小。 空闲块位于突出显示的块旁边。 假设一个空闲块具有一些看起来像这样的元数据:我们具有上面块的大小,下面有空闲空间,下面有后向指针和前向指针。 并且在块的最底部,再次显示大小。



为什么我们这里有2个指针? 因为在这种情况下,内存分配系统使用双链表来跟踪空闲块之间的关系。 因此,当您选择一个空闲块时,会将其从此双向链接列表中排除。 然后,当您释放它时,您将对指针进行一些算术运算,并将这些内容按顺序排列。 之后,将其添加到此链接列表中,对吗?

每当您听说指针算术时,您都应该认为这是您的“金丝雀”。 因为会出现很多问题。 让我提醒您,缓冲区溢出p 。 如果我们假设pq彼此相邻,或者在内存空间中非常接近,那么最终可能发生这种缓冲区溢出会覆盖分配的指针q的某些大小数据的情况-这是分配的块的底部。 如果您从一开始就继续遵循我的想法,那么您的想像力将告诉您一切从哪里开始出错。 实际上,从本质上讲,这些操作最终会发生的是自由q自由p-它们查看所选块中的此元数据,以对指针进行所有必要的操作。



也就是说,在执行的某个时刻, 自由函数将基于大小值获取特定的指针: p = get.free.block(size) ,大小是攻击者控制的,因为攻击者正确地进行了缓冲区溢出?

他做了很多算术运算,查看了back函数和该块的指针,现在将要进行一些操作,例如更新“ back”和“ forward”指针-这是最后两行。



但实际上,这不应打扰您。 这只是在这种情况下发生的代码的示例。 但是事实是,由于黑客重写了大小,他现在控制了该指针,该指针通过free函数传递。 因此,最下面一行的两个状态实际上是指针更新。 而且由于攻击者能够控制此p ,所以它实际上控制了这两个指针。 正是在这个地方可以发生攻击。

因此,当自由运行并尝试执行将两个模块组合在一起的操作时,您将获得一个双向链接列表。 因为如果您有两个相互碰撞的块并且两个块都是免费的,则您希望将它们组合成一个大块。

但是,如果我们控制大小,则意味着我们从上面的四行控制了整个过程。 这意味着,如果我们了解溢出是如何工作的,则可以按照选择的方式将数据写入内存。 就像我说的那样,如果您不擅长使用指针,这些事情通常会在您自己的代码中发生。 当您犯一些双重自由错误,例如自由q自由p或其他问题时,您的函数将崩溃。 因为您弄乱了每个选定块中的元数据,并且在某些时候此计算将指示某种“垃圾”值,之后您将“死亡”。 但是,如果您是攻击者,则可以选择此值并利用它来发挥自己的优势。

让我们继续另一种防止缓冲区溢出攻击的方法。 这种方法是检查边界。 边界检查的目的是确保当您使用特定的指针时,它只会引用什么是内存对象。 并且此指针在此内存对象的允许范围内。 这是验证的主要思想。 — . , C, . , : , , ?

, – . 1024 , : char [1024] , char *y = & [108].



? ? 很难说。 , , . , , - .
- , , , . . , , , . , , . , , .

, , struct union . , . : integer , struct , int .

, union , . , integer , struct , .

, , - : int p: & (u,s,k) , : u, s, k.



, , , , . , , union integer , struct . , , , . .

p' , p , p' , .



, , . , , union . , - - union , , , . , , X. , , , , . , , . .

, . , p p' , . .

? Electric fencing – . , , , , .



, - , . , , . , . , , , .

- C C++, , , . - , , - . , . , «» — , , , . , , .

, guard page – ! , .

59:00

:

MIT « ». 2: « », 2


该课程的完整版本可在此处获得

, . ? ? , 30% entry-level , : VPS (KVM) E5-2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps $20 ? ( RAID1 RAID10, 24 40GB DDR4).

Dell R730xd 2 ? 2 Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100 $249 ! . c Dell R730xd 5-2650 v4 9000 ?

Source: https://habr.com/ru/post/zh-CN416047/


All Articles