文章首发于先知社区:https://xz.aliyun.com/t/4309
之前在补天平台首发了巧用命令注入的N种方式,看到了有几个师傅衍生出了不同的几个后续版本,都感觉挺不错的,对我的版本进行了一些补充。本来这个总结应该算是前半部分,想写的还没写完,当时又是在考试周,原本想在考试结束后就来写后半部分,又因为各种事给推掉了。所以现在来写后半部分提升篇,也算是对前半部分的补充与解释。
[TOC]
提权
这里我们讲讲在命令注入中更有意思的一种方法。
Wildcard Wilderness
Example 1
首先我们先看一个示例
1 | echo "Hello Friends" > file1 |
首先创建几个文件,其中有一个是--help
,然后使用cat
命令读取文件内容
1 | cat file1 |
如果按照我们预期的,是不是在第三个cat --help
处应该是要读取—help
文件的内容呢?然而我们执行cat —help
却优先执行了cat
命令的帮助选项,并没有读出—help
里的内容。
不仅是cat
,ls
等命令也会优先调用内置--help
选项。
以及还有--all
选项。
其实讲道理,词法分析把对诸如--help
、--all
等选项优先处理为内置选项输出,看起来并没有任何问题
这个技巧叫做Wildcard wildness
,中文有人译为通配符在野。(-all
、--help
可以通过加入./
成./-all
、./--help
来特指这个文件,避免这个问题)
Example 2
如图,我们有两个文件,当用rm *
的时候,只删掉了file1
与file2
,并没有删除*
或者使用rm file1 file2 -rf
逐个删除之时,也只删掉了file1
与file2
使用strace rm *
我们可以发现
由于当前目录中存在-rf
文件名,rm
将-rf
选项作为最后一个参数,并且递归删除当前目录中的所有文件。同样,若要删除可以加上./-rf
进行删除
Trick
我们可以利用Wildcard Wilderness
做一些更有用的事情。
File Owner Hijacking
现在我们有三个用户,一个zedd
,一个test
,一个root
用户。
我们分别用zedd
与test
创建了不同的文件,1.php
与test.php
都属于test
用户的文件,zedd.php
与--reference=zedd.php
均属于zedd
用户的文件。
然后使用root
用户使用chown -R test:test *.php
命令,想把本目录下所有的.php
文件修改为test
用户所有。
但是结果我们可以发现,结果该目录下所有的.php
文件都被修改为了zedd
用户所有,成功“提权”。
原理我们可以用strace chown -R zedd:zedd *.php
来看一下(注意这里换了一下,模拟想把.php
文件改变成zedd
用户所有)
我们可以看到
1 | execve("/bin/chown", ["chown", "-R", "zedd:zedd", "config.php", "index.php", "--reference=.backdoor.php"], 0x7ffe5b43b1e8 /* 35 vars */) = 0 |
跟我们上个例子原理其实一样,--reference=.backdoor.php
被作为一个选项进行了处理,而
1 | --reference=RFILE use RFILE's owner and group rather than |
--reference=RFILE
这个选项则是使用RFILE
的文件拥有者和用户组来改变文件属性,而不是使用传入的OWNER:GROUP
参数。
因此,在这种情况下,chown
的--reference
选项将覆盖指定为root
用户输入的参数zedd:zedd
,把此目录中所有.php
文件的所有者改变与.backdoor.php
的所有者test
。
所以,按照这种方法,我们可以劫持root
将文件的所有权更改为任意用户,并“劫持”我们想要的文件。
Chmod File Reference
类似chown
的还有一个命令chmod
,它也有--reference=RFIE
的选项
1 | --reference=RFILE use RFILE's mode instead of MODE values |
与chown
类似,因为有--reference=.backdoor.php
的存在,在使用chmod 000 *
的时候也会把劫持到与.backdoor.php
文件权限一样的权限
Tar命令利用
首先我们来看看tar
命令帮助文档中的几个有意思的选项
1 | --checkpoint[=NUMBER] |
从帮助文档,我们大致可以从中理解到,--checkpoint=1
可以用来显示信息,--checkpoint-action=exec=sh shell.sh
可以用来执行命令
先尝试构建一个shell.sh
脚本,内容为/usr/bin/id
,以及文件名为--checkpoint=1
与--checkpoint-action=exec=sh shell.sh
的文件,使用tar -cf test.tar *
把当前目录下所有文件压缩到test.tar
压缩包内
可见,/usr/bin/id
已经被成功执行输出。
与之前一样,--checkpoint=1
与--checkpoint-action=exec=sh shell.sh
被作为选项处理
在 2018 SWPUCTF 上有一道 web 题考点也正是利用了这个点,由于题目官方没有开源,这里给一个比较详细的 @一叶飘零 师傅写的 wp 用于参考学习: 2018SWPUCTF-Web#信息再次发掘
rsync命令利用
rsync
命令可能比较少用,我们这里简单介绍一下
NAME
rsync - a fast, versatile, remote (and local) file-copying tool
rsync
命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。使用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器。如:rsync -t *.c foo:src
,复制当前本地文件夹下的所有的.c
文件到 foo 远程服务器的/src
文件夹下。
rsync
帮助文档含有以下几个比较有意思的选项
1 | -e, --rsh=COMMAND specify the remote shell to use |
--rsh=COMMAND
又是一个我们可以利用的地方,我们首先创建一个文件名为-e sh shell.c
的文件,然后再创建一个shell.c
文件,污染rsync
参数来实现执行我们在shell.c
中写入的预期命令
假设当前目录下我们拥有一个只有root
用户可读的rootfile
文件,由于不能直接输出结果,我们可以构造cat ./rootfile > ./output
,将文件内容读出。
得到的output
文件是 644 的权限,这样我们就成功构造了一个提权读取的文件的 payload ,这里可能需要注意的是,只能提取到执行rsync
用户的权限,不是直接的root
权限,这里因为执行命令的是root
权限,所以能读取只有root
用户才能读取的rootfile
文件
Tips
既然能执行命令,其实我们可以参照上篇列举的反弹 shell 的方式将 shell 反弹给我们,也可以配合
msfvenom
来使用。tar
命令比较多的都用在/etc/crontab
计划任务中,经常会有管理员会用crontab
来执行一些tar
命令的备份操作,而且crontab
执行的权限还是root
权限,所以这是个很好利用的点tar
命令需要进入到--checkpoint=1
文件所在的目录内,如果加上绝对路径将会失效,例如tar cf test.tar /var/www/html/*
我们可以看到 shell 处理方式将
/home/zedd/Desktop/test
与目录下的文件名逐个拼接起来,就达不到污染参数的效果了还可以用
echo "zedd ALL=(root) NOPASSWD: ALL" > /etc/sudoers
,把自己直接写入管理员组利用
chmod u+s /usr/bin/find
提升为root
权限执行,配合find
命令的-exec COMMAND
来执行命令,例如find f1 -exec "whoami" \;
文章中讨论的技术可以以不同的形式在各种流行的Unix工具上应用,这里仅仅是抛砖引玉,列举一部分命令。 在实际攻击中,任意 shell 选项/参数都可以隐藏在常规文件中,管理员也不容易发现,比如使用.backdoor.php
等形式。
Other
这里讲讲几个虽然不属于提权,但是也比较有意思的几个点。
Echo
echo *
可以用来显示目录,echo /???g
可以用来探测文件
ln
NAME
ln - make links between files
ln
命令常常用于链接两个文件,而且分两种链接模式,一种硬链接一种软链接,详细可以参考理解Linux硬链接与软链接。这里主要讲讲软链接,软链接相当于我们 Windows 中的快捷方式,可以使用ln -s
创建
例如,这里我们根目录下有一个文件内容为flag{xxx}
的名为flag
文件,我们使用ln -s /flag file
,在当前目录下创建一个file
文件链接到/flag
,使用cat file
与php -r "echo file_get_contents('file')"
均可以读取到/flag
的内容。
这个软链接读取文件内容已经被多次利用
- 在 GitLab CVE-2016-9086 也是利用了这点,参考GitLab 任意文件读取漏洞 (CVE-2016-9086) 和任意用户 token 泄露漏洞
- CTF 中也出现了类似的题目,参考一个有趣的任意文件读取,以及在 2018 年赛博地球杯上有一道题也是利用这个点,参考记录一道题的多种解法,“赛博地球杯”工业互联网安全大赛线上赛Writeup
ShellShock(CVE-2014-6271)
Bash 4.3以及之前的版本在处理某些构造的环境变量时存在安全漏洞,向环境变量值内的函数定义后添加多余的字符串会触发此漏洞,攻击者可利用此漏洞改变或绕过环境限制,以执行任意的 shell 命令,甚至完全控制目标系统,详细分析参考破壳(ShellShock)漏洞样本分析报告
CVE-2014-6271 测试方式:
env x=’() { :;}; echo vulnerable’ bash -c “echo this is a test”
CVE-2014-7169 测试方式:(CVE-2014-6271补丁更新后仍然可以绕过)
env -i X=’;() { (a)=>' bash -c ‘echo date’; cat echo
从一道题看Shell Shock
题目地址:command-executor——来源于 HackMe
题目描述:
Here’s my useless developer assistant website, try to execute your own command!
题目大体思路是:
- 读取源码
- Shell Shock命令执行
- 重定向读写文件
题目设置为几个功能,一个man
命令的帮助文档
选择了ls
,多了个请求参数file=ls
尝试用其他命令,比如find
猜测eval("man /bin/" + command)
或者一些其他的目录
Tar Tester
界面可以上传压缩包但是并没有解压,只是tar -tvf test.tar
查看压缩包内的内容
Cmd Exec
界面只有两个命令,一个ls
,一个env
List files
是个目录列举界面,可以列举几个目录
观察题目,题目 urlhttps://command-executor.hackme.inndy.tw/index.php?func=untar
等均带有func=xxx
参数来展示页面,猜测会有文件包含漏洞,尝试使用func=php://filter/read=convert.base64-encode/resource=index
读取文件内容,成功得到回显
解码得到 index.php
源码
1 | <?php |
man.php
源码:
1 |
|
untar.php
源码:
1 |
|
ls.php
源码:
1 |
|
cmd.php
源码:
1 |
|
接下来我们就可以利用ls.php
来找flag
了,因为ls.php
没什么过滤,所以用func=ls&file=../../../
可以发现根目录下的文件
接下来就是考虑怎么去读了,man.php
因为有preg_match('/^[\w\-]+$/', $file) !== 1
限制得比较死,untar.php
貌似只有tar -tvf
并没有什么用处,只有cmd.php
给出了一个比较不太寻常的env
这个命令,其实这样也算是提示得比较明显了,比较容易让人想到也可以比较容易搜到ShellShock
漏洞,并且在index.php
中发现有
1 | $black_list = [ |
关键就在putenv
函数,由于ShellShock
漏洞 padyload 需要参数
1 | env x='() { :;}; echo vulnerable' bash -c "echo this is a test" |
我们就可以利用putenv
实现参数传递,直接设置User-agent: () { :;}; echo 222222
,发现被 waf
分析 waf 结合漏洞成因,我们可以在最后的};
中间添加一个空格绕过,设置User-Agent: () { :;} ; echo 222222
,成功发现输出 22222 ,我们也可以使用() { _; } >_[$($())] { whoami; }
这个 payload
发现当前用户为www-data
,而我们之前发现根目录flag
的权限为-r-------- 1 flag root 37 Jan 9 2018 flag
,所以不能直接读取,但是有一个flag-reader
与flag-reader.c
的文件,这应该是题目提示了。因为index.php
又把flag
关键字屏蔽了,我们也不能直接读取flag-reader.c
,但是我们这里可以利用通配符读取,例如使用fla*.c
使用() { _; } >_[$($())] { cat /fla*.c; }
得到flag-reader.c
源码
Flag-reader.c:
1 |
|