这是tr0ll2靶机涉及到的东西,先看一下在这个靶机上的过程。
我们获取了noob用户的ssh密钥,之后登录却失败了:
之后我们输入如下命令:
ssh [email protected] -i noob -t '() { :;}; /bin/bash'
再次登录,居然成功了:
以上就是shellshock攻击,其利用的是bash在导入环境变量函数时候的漏洞,启动bash的时候,它不仅会导入这个函数,也会把函数定义后面的命令执行,在有些CGI脚本的设计中,数据是通过环境变量来传递的,这样就给了数据提供者利用Shellshock漏洞的机会。
这个漏洞刚开始接触还会觉得有些奇怪,因为命令本身就是bash执行的,不觉得有什么危害。实际环境中在远程访问时,有些CGI会把post包中的变量导入成用户变量,并起一个子bash来运行。
此利用方式,需要以下条件:
- 远程服务会调用bash。(创建bash子进程)
- 远程服务允许用户定义环境变量。
- 远程服务调用子bash时加载了用户定义的环境变量。
成因分析如下,参考了一位博主的文章,结尾贴链接:
在 bash 中可以自定义 Shell 变量 , 如下所示
但此时该变量仅是当前 Shell 的一个局部变量 , 只有在当前 Shell 进程中可以调用 . 即使是当前 Shell Fork 出的子进程 , 也是不能访问该变量的 .
为此 , 我们可以通过 export 命令 , 将该变量转变为一个环境变量 , 这样当前 Shell 的子进程就可以访问它了
不仅如此 , 在 Bash 中还可以定义 Shell 函数并将其导出为环境函数 , 只需要指明 -f
参数即可
上图这种函数的定义方法是非常普遍的 , 很容易理解 . 但在 Bash 中还有一种独有的方法来定义函数 , 即 : 通过环境变量来定义函数
当某个环境变量的值以字符串 " () {
" 的格式作为开头( 注意大括号与小括号间的空格不能少 ) , 那么该变量就会被当前 Bash 当作一个导出函数( export function
) , 该函数仅会在当前 Bash 的子进程中生效 . 在很多文章中会把它称为 Bash 的 "`自动导入机制( 自动导入函数到当前 Bash
因为这种独特的函数定义方式仅会在当前 bash 的子进程中生效 , 所以网络上很多帖子给出的 POC 都是下面这样 .
POC : env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
通过 bash -c
开启当前 Bash 的子进程 , 在子进程载入时会初始化用户环境变量 , 在初始化时发现了包含 "() {
" 格式的字符串 , 所以将该字符串作为一个自动导入函数 . 但由于没有判断函数定义的结束 , 所以错误的将该函数定义后的语句也初始化并当作命令执行了 . 所以子 Bash 会执行该语句并输出 vulnerable
, 然后再输出 this is a test
.
简单的说 , 就是将恶意命令添加到合法的Bash函数定义后 , 在启动子进程时 , Bash 会先执行恶意命令 , 然后再执行正常的指令 .
在 Shellshock漏洞回顾与分析测试 中有一副图做的非常棒 , 十分容易理解 , 这里贴出来 .
之后看一下源代码:
因为 ShellShock 触发于 Bash 子进程初始化环境变量的时候 . 所以我们进入 variables.c
文件 , 找到 initialize_shell_variables()
函数 .
这里先定义了一些参数 , 然后循环遍历所有环境变量 , 通过 " = " 来分割变量名与变量值。之后判断刚才获取到的环境变量中是否有不合法的( 比如 "=xxx
" 或者没有等号的 ) . 如果发现不合法的变量 , 就跳过它们,并赋值。再之后先判断是否存在自动导出函数( 通过 "() {
" 来判断 ) , 若存在就将其定义为一个函数 . 同时判断当前是否处于 privileged mode
,若不处于该模式就将之前导出的函数导入到新的环境变量中 .
注意这里 , string( 获取到的环境变量值 ) 没有进行任何过滤 , 就被放入到 parse_and_execute
函数中 . 这是典型的注入漏洞。