麻省理工学院。 讲座课程#6.858。 “计算机系统的安全性。” Nikolai Zeldovich,James Mickens。 2014年
计算机系统安全是一门有关开发和实施安全计算机系统的课程。 讲座涵盖了威胁模型,危害安全性的攻击以及基于最新科学研究的安全技术。 主题包括操作系统(OS)安全性,功能,信息流管理,语言安全性,网络协议,硬件安全性和Web应用程序安全性。
第1课:“简介:威胁模型”
第1 部分 /
第2 部分 /
第3部分第2课:“控制黑客攻击”,
第1 部分 /
第2 部分 /
第3部分第3讲:“缓冲区溢出:漏洞利用和保护”
第1 部分 /
第2 部分 /
第3部分讲座4:“特权分离”,
第1 部分 /
第2 部分 /
第3部分 那么,这个清单上还有什么呢? 流程。 记忆是与过程同时发生的事情。 因此,如果您不在此过程中,则无法访问其内存。 虚拟内存为我们完美地增强了这种隔离。 此外,如果您具有相同的用户ID,则调试机制可让您“弹出”另一个进程的内存
接下来,我们有了网络。
Unix中的网络与上述模型不太对应,部分原因是首先开发了
Unix操作系统,然后出现了网络,这一网络很快流行起来。 它的规则集略有不同。 因此,如果您管理网络,我们真正需要注意的操作就是将某人连接到网络,或者如果您充当服务器,则要侦听某个端口。 您可能需要在此连接上读取或写入数据,或者发送和接收
原始数据包。

因此,
Unix上的网络大多与
userid无关。 规则是,任何人都可以始终连接到任何计算机或IP地址或打开连接。 如果要在端口上侦听,则在这种情况下有一个区别,那就是大多数用户都被禁止侦听小于“魔术值” 1024的数字的端口。原则上,您可以侦听此类端口,但是在这种情况下,您应该成为特殊用户,称为
uid = 0的 “超级用户” 。
通常,在Unix中存在管理员或超级用户的概念,由标识符uid = 0表示,它可以绕过几乎所有这些检查,因此如果使用root权限,则可以读写文件,更改对它们的访问权限。 操作系统将允许您执行此操作,因为它认为您应该拥有所有特权。 而且,您真的需要这样的特权才能监听编号小于1024的端口。您如何看待这种奇怪的限制?
受众群体:它标识特定连接的特定端口号,例如端口80上的
http 。
教授:是的,默认情况下,
HTTP协议使用端口80。另一方面,其他服务可以使用端口号大于1024的端口,为什么需要此限制? 这里有什么用?
受众:因为您不希望任何人无意间听到您的
HTTP 。
教授:是的。 我认为这样做的原因是您曾经在同一台计算机上有许多用户。 他们使用登录名登录并启动了他们的应用程序,因此您想确保某些随机用户登录到计算机后将无法控制在其上运行的Web服务器。 因为从外部连接的用户不知道该端口上的用户,他们只是连接到端口80。如果我要进入此计算机并启动自己的Web服务器,则只需将所有Web服务器流量传输到这辆车。 这可能不是一个很好的计划,但这是Unix网络子系统阻止随机用户控制在这些低端口号上运行的已知服务的方式。 这就是这种限制的理由。

另外,从读取和写入连接数据的角度来看,如果您有用于特定套接字的描述符文件,那么
Unix将允许您在此
TCP或
uTP连接中读取和写入任何数据。 在发送
原始数据包时,
Unix表现得像一个偏执狂,因此它不会让您通过网络发送任意数据包。 这应该在特殊连接的范围内,除非您拥有
root(即权利),并且您可以做任何您想做的事情。
因此,您可能要问的一个有趣的问题是所有这些
用户ID都来自哪里?
我们正在谈论具有
userid或
groupid的进程。 在计算机上启动
PS时,您肯定会看到一系列具有不同
uid值的进程。 他们来自哪里?
我们需要某种机制来加载所有这些
用户ID值。
Unix有几个为此设计的系统调用。 因此,要引导这些标识符值,有一个名为
setuid(uid)的函数,因此您可以将一些当前进程的
uid号分配给该值。 与
Unix传统中的所有其他方法一样,这实际上是一种危险的操作,因为只有在
uid = 0的情况下才能执行此操作。 无论如何,应该是这样。
因此,如果您是具有root用户权限且
uid = 0的用户 ,则可以调用
setuid(uid)并将用户切换到任何进程。 还有两个其他类似的系统调用,用于初始化与进程相关的
gid :
setgid和
setgroups 。 因此,这些系统调用使您可以配置进程特权。

当您登录
Unix机器时,您的进程将获得正确的访问权限这一事实不会发生,因为您与进程具有相同的
ID ,因为系统尚不知道您是谁。 相反,在
Unix上,当
SSH安全Shell
协议为连接到计算机并尝试对用户进行身份验证的任何人启动该过程时
,会有某种登录过程。
因此,对于具有root用户权限的用户,此登录过程最初以
uid = 0开始,然后,当他收到特定的用户名和密码时,他在自己的帐户数据库中对其进行检查。 通常,在
Unix上,此数据存储在两个文件中:
/ etc / password (出于历史原因,密码不再存储在此文件中)和
/ etc / shadow文件中,其中存储了密码。 但是,
/ etc / password文件中有一个表,该表将系统中的每个用户名显示为整数值。
因此,您的用户名映射到该
/ etc / password文件中的特定整数,然后登录过程根据此文件检查您的密码是否正确。 如果找到整数
uid ,则将
setuid函数设置为该
uid值,并使用
exec命令
(/ bin / sh)启动shell。 现在您可以与外壳进行交互,但是它可以在您的
uid下工作,因此您将不会对本机造成意外损坏。
受众:如果您的
uid并非真正
为0,是否可以使用
uid = 0启动新进程?
教授:如果您具有root特权,则可以将自己限制为另一个
uid ,降低您的权限,但是在任何情况下,您都可以创建一个仅具有与您相同的
uid的进程。 但是由于种种原因,您可能想增加特权。 假设您需要安装一个需要
root特权的软件包。
在
Unix上有两种设置特权的方法。 我们已经提到的一个是文件描述符。 因此,如果您确实想增加特权,则可以与具有root权限的工作人员交谈,并请他为您打开此文件。 或者,您需要安装一些新界面,然后此助手会为您打开一个文件,并使用
fd transfer向您返回文件描述符。 这是增加特权的一种方法,但是它不方便,因为在某些情况下,有些进程运行着大量特权。 为此,
Unix具有一种聪明但同时存在问题的机制,称为
“ setuid二进制文件” 。 该机制是
Unix文件系统上的常规可执行文件,但在
setuid二进制文件上运行
exec时除外,例如,大多数计算机上的
/ bin / su或启动时的
sudo 。
典型的
Unix系统具有一堆
setuid二进制文件。 区别在于,当您执行这些二进制文件之一时,实际上会将进程的
用户标识切换为该二进制文件的所有者。 当您第一次看到该机制时,它似乎很奇怪。 通常,使用它的方式是该“二进制”很可能具有所有者
uid为 0,因为您确实要还原许多特权。

您想要恢复超级用户权限,以便可以运行此
su命令,并且内核在执行此二进制文件时会将进程
uid切换为0,以便该程序现在可以执行某些特权操作。
受众:如果您的
uid = 0,并且
将所有这些
setuid二进制文件的
uid更改为0以外的值,可以恢复特权吗?
教授:不,降低访问级别时,许多进程将无法还原特权,因此您可能会陷入困境。 该机制不依赖于
uid = 0 。 像
Unix系统的任何用户一样,您可以创建任何二进制文件,构建程序,对其进行编译,并将此
setuid位设置为程序本身。 它属于您,用户,您的用户ID。 这意味着任何运行您的程序的人都将使用您的用户ID运行此代码。 这有什么问题吗? 需要做什么?
听众:也就是说,如果您的应用程序有错误,有人可以以您的特权行事吗?
教授:是的,如果我的应用程序是“越野车”,或者它允许您运行所需的一切,它就会发生。 假设我可以复制系统外壳并为我设置它
setuid ,但是任何人都可以使用我的帐户运行该外壳。 这可能不是最佳的行动计划。 但是这种机制不会产生问题,因为唯一可以在二进制文件上设置
setuid位的人就是该文件的所有者。 您作为文件的所有者,具有
uid特权,因此您可以将您的帐户转让给其他人,但是该其他人将无法使用您的
userid创建
setuid二进制文件。
这个setuid位存储在这些权限位的旁边,也就是说,在每个
inode中还存在一个
setuid位,该位指示该可执行文件是否应该执行,或者在执行过程中程序是否切换到所有者
uid 。

事实证明,如果正确使用这是一种非常棘手的机制,而且由于它,内核可以正确地实现程序。 实际上,这很容易做到,因为只执行了一次检查:如果存在此
setuid位,则过程切换到
uid 。 这很简单。
但是安全地使用它是非常困难的,因为如前所述,如果该程序包含错误或发生意外情况,则您可以在
uid = 0或任何其他
uid下执行任意操作。 在
Unix上,当您运行程序时,您将从父进程继承很多东西。
例如,您可以将环境变量传递给
setuid二进制文件。 事实是,在
Unix上,您可以通过设置环境变量来指定要用于该进程的共享库,而
setuid二进制文件并不关心过滤这些环境变量。
例如,您可以运行
bin / su ,但将共享库用于
printf函数,因此,当
bin / su打印某些内容时,
printf将启动,并且可以运行Shell而不是
printf 。
关于程序对用户输入数据的不信任,您必须正确理解许多细微之处。 因为您通常信任用户输入,所以
setuid从来不是整个
Unix系统中最安全的部分。 对这个有疑问吗?
受众: setuid是否也适用于组或仅适用于用户?
教授:有一个与
setuid位对称的
setgid位,您也可以设置。 如果文件具有特定的
gid,并且在程序启动时此
setgid位置1,则将得到它。
Setgid并不是特别使用,但是在您要提供非常特定的特权的情况下很有用。 例如,
bin / su可能需要很多特权,但是也许有些程序需要一些额外的特权,例如,将某些内容写入特殊的日志文件。 因此,您可能想为她提供一个特定的组,并为该组创建一个可写的日志文件。 因此,即使程序“越野车”,除了该组外,您也不会丢失任何东西。 这是一种有用的机制,由于某种原因它不经常使用,因为人们毕竟应该更多地使用根权限。
受众:谁可以更改访问权限是否受到限制?
教授:是的。 不同的
Unix实现对此有不同的检查。 一般规则是,只有root用户才能更改文件的所有者,因为您不想创建将属于其他人的文件,当然您也不想使用其他人的文件。 因此,如果您的
uid不为0,则说明您被卡住了。 您不能更改任何文件的所有权。 如果您的
uid = 0 ,则您具有root特权,可以将所有者更改为任何人。 如果您使用的是二进制
setuid,并且从一个
uid切换到另一个
uid ,则会有些复杂,这非常棘手,但是,如果您没有root特权,则基本上不能更改文件所有者。
从所有人的角度来看,这是一个过时的系统。 您可能会想到许多简化上述过程的方法,但是实际上,大多数高级系统都是这样,因为它们会随着时间的推移而发展。 但是您可以完美地将这些机制用作“沙盒”。
这些只是
Unix的某种基本原理,几乎出现在每个类似Unix的操作系统中:
Mac OS X ,
Linux ,
FreeBSD ,
Solaris ,如果有人使用它,等等。 但是,每个系统都有更复杂的机制可供您使用。 例如,在
Linux上有一个“沙盒”
设置COMP ,
Mac OS X使用了“沙盒”
Seatbelt 。 下周,我将为您提供每个基于
Unix的系统上可用的沙箱示例。
因此,在进入
OKWS之前我们将考虑的最后一种机制,解释了如何处理
setuid二进制文件,并说明了如何保护自己免受现有安全漏洞的影响。 问题是,您的系统上不可避免地会有一些
setuid二进制文件,例如
/ bin / su或
sudo或其他东西,并且您的程序可能会出错。 因此,某人将能够执行
setuid二进制文件,并且该进程将能够获得您不希望允许的
root用户访问权限。
Unix机制通常用于防止使用
setuid二进制文件执行潜在的恶意进程,该机制是使用文件系统名称空间通过
chroot系统调用(即更改根目录的操作)对其进行更改。
OKWS作为专门用于创建快速和安全的Web服务的Web服务器,已经广泛使用了它。

因此,在
Unix上,您可以在特定目录中执行
chroot ,因此也许也可以执行
chroot(“ / foo”) 。
chroot的作用有2种解释。 第一个是直观的,这意味着在运行
chroot之后 ,根目录或位于斜杠后面的目录基本上与调用
chroot之前
使用的/ foo等效。 似乎将名称空间限制在
/ foo下面。 因此,如果您有一个以前称为
/ foo / x的文件 ,则在调用
chroot之后,只需打开
/ x就可以得到此文件。 因此,仅将您的名称空间限制为一个子目录。 这是直观的版本。

当然,在安全性上,不是直观的版本很重要,但是内核对该系统调用的作用是什么? 它基本上做了两件事。 首先,它会更改此斜杠的值,因此,每当您访问或以斜杠开头的目录名时,内核都会包含
chroot操作提供的任何文件。 在我们的示例中,这是在您调用
chroot之前的文件
/ foo ,即,我们得到了
/ = / foo 。

内核将尝试做的下一件事情是保护您,使其能够从
/中 “逃脱”。 因为在
Unix上,我可能会要求您给我,例如
/../etc/password 。 因此,如果我只是这样补充这一行:
/foo/../ etc/password ,那将不是很好,因为我可以退出
/ foo并继续获取
/ etc / password 。
内核对
Unix系统调用所做的第二件事是,当您为该特定进程调用
chroot时,它将更改
/../在此目录中求值的方式。 因此,它修改
/../,以便
/ foo指向自身。 因此,这不允许您“退出”,并且此更改仅适用于此过程,不会影响其余过程。 您对如何使用
chroot环境“逃脱”有什么想法?
有趣的是,内核仅监视一个
chroot目录,因此您可能会执行
chroot =(/ foo)操作,但是您会被困在这个地方。 所以您想获取
/ etc / password ,但是该怎么做呢? 您可以通过键入
open(* / *)立即打开根目录。 这将为您提供描述
/ foo是什么的文件描述符。 然后,您可以再次调用
chroot并执行
chroot(`/ bar) 。

, :
root /foo ,
/foo/bar /../ /foo / bar/..
,
/foo .
fchdir (fd) (*/*) ,
chdir (..) .

/foo ,
/../ .
/foo ,
root , .
, , . .
Unix root-
chroot ,
chroot . ,
Unix uid = 0 ,
chroot . . , ,
chroot ,
userid . ,
Unix , ,
root , .
, , , .
chroot — . .
: ,
inod , ?
: ! , , , : «
inode 23», -
hroot . ,
Unix inode inode , , , root-.
, , ,
OKWS . ,
OKWS .
, -, , - , . , ,
httpd , ,
Apache .
userid www /etc/password . , ,
SSL ,
PHP , . , , ,
MySQL , .
MySQL .
MySQL , , , .

, , ,
MySQL , , .
, , , , . , , ,
Apache或SSL或应用程序代码或PHP解释器。并且由于存在错误,因此您可以使用它们来获取应用程序的全部内容。52:30分钟继续:麻省理工学院的课程“计算机系统安全”。 讲座4:“共享特权”,第2部分该课程的完整版本可在此处获得。感谢您与我们在一起。 你喜欢我们的文章吗? 想看更多有趣的资料吗? 通过下订单或将其推荐给您的朋友来支持我们,为我们为您开发
的入门级服务器的独特模拟,为Habr用户提供
30%的折扣: 关于VPS(KVM)E5-2650 v4(6核)的全部真相10GB DDR4 240GB SSD 1Gbps从$ 20还是如何划分服务器? (RAID1和RAID10提供选件,最多24个内核和最大40GB DDR4)。
戴尔R730xd便宜2倍? 仅
在荷兰和美国,我们有
2台Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100电视(249美元起) ! 阅读有关
如何构建基础架构大厦的信息。 使用价格为9000欧元的Dell R730xd E5-2650 v4服务器的上等课程?