dll 源码_【技术分享】 | 一个JAVA内存马的源码分析

前言

偶然接触到了这样一个JAVA内存马,其作者也是冰蝎的作者,项目地址:

https://github.com/rebeyond/memShell

正好最近在接触JAVA,借此机会学习下大佬的代码,对自己的编程思路也有了一定的提升。当然笔者只是一个脚本小子,对代码接触不深,如果文中出现理解不当或是错误的情况,还望各位大佬不吝赐教:)

背景知识

Java Instrumentation

JAVA在SE5版本引入了Java Instrumentation,其包含在java.lang.instrument中。通过Instrumentation,我们可以构建独立于应用程序的代理端,而通过这个代理我们可以监控JVM状态以及修改类定义。而在SE6版本中,我们能够实现注入代码到运行时的JVM中。

Java Agent

前面提到的代理端也就是Java Agent,Java Agent是依附于JAVA应用程序并能对其字节码做修改的一项技术,不能独立运行。加载运行方式有两种:premain模式和attach模式,前者是在程序运行前加载,后者是在程序运行后加载,本文分析的这个木马是使用的后者。

项目作者在这篇文章中有个原理demo,感兴趣的可以看看。

分析

分析按由外及里、由简入难的顺序进行,即:用户可见功能模块、注入模块、代理模块、持久化模块。

用户可见模块分析

从项目README文件里可以看到这款木马有以下功能:

l  欢迎页

l  命令执行

l  反弹Shell

l  远程文件下载

l  文件操作

l  本地文件下载

l  文件上传

l  代理

l  菜刀连接

欢迎页

当我们获取目标服务器权限时,将木马上传至目标服务器,执行java -jar inject.jar password,即可进行进程注入获取一个隐藏进程会话。

 [+]OK.i find a jvm. [+]memeShell is injected.

此时我们去浏览器访问目标服务器即可调用目标模块。

4449d72823b2cbbe68d6e254a6813ceb.png

需要注意的是,这个木马和常规木马不同。常规木马需要去访问目标木马文件来执行命令,而这款木马访问任意URL都可以调用木马执行其模块。其原理是此木马向org.apache.catalina.core.ApplicationFilterChain类的internalDoFilter方法注入了自定义代码,这个JAVA类在HTTP请求调用栈的上方,可以相应我们的任意Request请求,因此我们可以用GET请求也可以用POST请求。

internalDoFilter方法的原型如下:

b10f6954f5f8956d4075eaa5364b60dd.png

换个角度来讲,这个类就是一个过滤器,而过滤器可以在客户端的请求访问后端资源之前,拦截这些请求。也可在服务器的响应发送回客户端之前,处理这些响应。也就是说用户的每一个Request请求都会经过过滤器,无论用户访问的资源是否存在,如何处理这些请求也是过滤器的核心所在。

命令执行

命令执行模块的核心就是调用Runtime.getRuntime().exec(cmd)方法来执行任意命令并获取返回结果。

f8c997298966e5e050b04c8cebc4cdc2.png

例如:

5ee8b5a4c5ed965de96cc3faaf5865b7.png

反弹Shell

反弹Shell主要依靠的是Socket通信,首先判断操作系统类型,再进行Socket连接以达到反弹Shell的目的。

85250438efc62dd264e45d4bc56d4c3b.png

例如:

ea259d07b0aa869ea876394e2791c155.png

远程文件下载

远程文件下载支持HTTPS,下面的代码片段为了排版美观我去掉了SSL认证代码。

ed2bfaa2a2b0f5d3af1c748fe6f7a926.png

文件操作

文件操作包含列文件、删除文件、查看文件、删除文件夹,都是一些很基础的文件操作代码,因此我们以查看文件为例。

4faa4136bc43e88871e8b4c2169b1e60.png

b2c22fe632a52879f46cfe3c18775211.png

本地文件下载

f3907c18a02bba323771e446044fe19d.png

文件上传

有普通上传方式,有Base64编码上传方式。

09d8141eaf76fe319c74a2e234ca8ac8.png

代理

木马里内嵌了一个reGeorg代理,因此我们可以直接使用这个木马实现代理转发,进一步渗透内网。

94e1f8fd132e5e0fac1dbbb572d2481d.png

核心源码就是根据reGeorg改的,网上也有分析文章,此处不再多赘述。

菜刀连接

菜刀模块的源码也是根据这个JSP菜刀源码改的,但是个人觉得挺有意思——方法命名全是AA、BB、CC这种,不明白原作者是为了混淆还是只是单纯的恶作剧。

e2e9cfbf4b124a79d163ca53723988ab.png

当然,以上的这些用户可见功能模块都建立在一个判断逻辑里,也就是需要正确输入我们所指定的密码。

  if (pass_the_world!=null&&pass_the_world.equals(net.rebeyond.memshell.Agent.password))

这些用户可见模块除了代理模块和菜刀模块都是一些常用的功能代码,简单易懂。紧接着我们深入分析其他模块。

注入模块分析

注入模块主要是用来遍历目标机器上的JVM实例并进行代码注入。前面提到我们有两种方式进行注入,premain和attach,这个木马里用的attach注入方式。

注入模块在运行的时候,会动态加载一个代理,也就是我们的代理模块。换句话说,代理模块会被注入模块注入到tomcat进程中。

71a56404abae545a7fed92c2762286e6.png

代理模块分析

在代理端被注入到JVM后,会自动运行agentmain方法。agentmain方法在获取用户输入的参数后,会遍历获取当前所有类,如果匹配到我们要注入的目标类,则查看当前的JVM配置是否支持类的重新定义,代码如下所示。

1eb341d52d51b1c093f7c38047c0a2ed.png

为避免默认端口号被更改初始化失败,木马会先获取当前工程的端口号,然后对本地的tomcat发起一起请求进行初始化。进行初始化的原因原作者也解释过,因为我们在运行木马后会将木马文件删除,因此需要在删除之前没有将木马写入内存。写入内存的方式有两种:依次加载需要的类、进行一次模拟访问,这款木马选择的后者。如下代码所示,会访问一次本地的tomcat服务,以达到将木马写入内存的目的。

f869cb6b5c55019ab9f801387b232127.png

在注入进程后,需要删除自身,但是我注意到删除的代码还比较多,原因是操作系统的不同,删除方式也不同,例如Windows下不能直接删除一个占用中的文件。因此首先需要判断操作系统类型,如果是Linux直接删除即可。

6b8ea3ba819fae8a9c01c81442f67d3a.png

如果是Windows,需要利用unlockFile这个方法来进行删除,unlockFile方法里使用了一个二进制文件——forceDelete.exe。例如当我们要删除代理端时,需要先用以下代码获取当前JVM进程PID。

  public static String getCurrentPid() {        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();        return runtimeMXBean.getName().split("@")[0];    }

然后利用命令执行的方式使用这个二进制文件强制删除占用的文件,并且将自身删除。

27bc229ab78770b7e70b5b2487588769.png

这个强制删除功能的二进制文件我们利用IDA进行简单分析,利用IDA打开后,手动调试恢复函数即可看到整个二进制文件代码逻辑。我这里就没有去恢复变量名,各位大佬凑合着看。

首先有一个判断逻辑:

  if ( !sub_411440 () || !sub_411590() )        ExitProcess(0);  

跟进sub_411440()函数,根据其代码逻辑我们发现其实就是Change_access()函数,其代码逻辑如下:

  BOOL sub_411440()    {        HANDLE v0; // eax        struct _TOKEN_PRIVILEGES NewState; // [esp+D0h] [ebp-24h]        HANDLE TokenHandle; // [esp+E8h] [ebp-Ch]            NewState.PrivilegeCount = 1;        v0 = GetCurrentProcess();        if ( !OpenProcessToken(v0, 0x28u, &TokenHandle) )            return 0;        LookupPrivilegeValueW(0, L"SeDebugPrivilege", (PLUID)NewState.Privileges);        NewState.Privileges[0].Attributes = 2;        return AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0x10u, 0, 0) != 0;    }

作用是获取当前进程信息并修改其权限。

再跟进sub_411590()函数,根据其代码逻辑推断是Get_Functions_address()函数

  BOOL sub_411590()    {        v0 = GetModuleHandleW(L"ntdll.dll");        dword_41713C = (int)GetProcAddress(v0, "ZwSuspendProcess");        v1 = GetModuleHandleW(L"ntdll.dll");        QueryInformationFille = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v1,  "ZwQueryInformationFile");        v2 = GetModuleHandleW(L"ntdll.dll");        QuerySystemInformation = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v2,  "ZwQuerySystemInformation");        v3 = GetModuleHandleW(L"ntdll.dll");        QueryObject = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v3, "ZwQueryObject");        v4 = GetModuleHandleW(L"ntdll.dll");        dword_417138 = (int)GetProcAddress(v4, "ZwResumeProcess");        v5 = GetModuleHandleW(L"ntdll.dll");  14.      QueryInformationPrecess = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v5, "ZwQueryInformationProcess");        return dword_41713C && QuerySystemInformation && QueryObject && dword_417138 && QueryInformationPrecess;    }  

其作用是加载ntdll.dll模块并从中获取ZwSuspendProcess、ZwQueryInformationFile、ZwQuerySystemInformation、ZwQueryObject、ZwResumeProcess、ZwQueryInformationProcess的函数地址。

还有一个sub_411DD0()函数,根据其代码逻辑推断是Find_SubStr()函数。因此此时整个二进制文件代码逻辑就清晰了。其核心代码如下:

  if ( QueryInformationFille(TargetHandle,&v13,FileInformation,528,9) >= 0 )2.  {        if ( Find_SubStr(FileInformation + 2, L"agent.jar") )        {            v4 = GetCurrentProcess();            if ( DuplicateHandle(hSourceProcessHandle, (HANDLE)v8, v4, &TargetHandle, 0, 0, 1u) )            {                CloseHandle(TargetHandle);                ExitProcess(0);            }        }    }  

我们梳理下整个二进制文件的运行逻辑:首先打开agent.jar进程,遍历该进程的所有句柄信息,通过DuplicateHandle()函数复制句柄到本地进程,关闭文件句柄,此时就能删除占用中的文件了。

本来DuplicateHandle()函数是用来创建新句柄的,但是我们可以利用这个特性来删除被占用的文件,巧妙的实现删除文件的功能。

持久化模块分析

持久化模块主要是用于tomcat服务重启后也能继续使用这款木马,也就是说,只要目标机器不重启,tomcat服务运行起来我们无需进行二次注入也能获取权限,其核心代码如下。

2c1735ecdf8226076c1811cef804eef9.png

主要的核心原理在于addShutdownHook钩子,JVM关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,JVM才会关闭。所以这些钩子可以在JVM关闭的时候进行内存清理、对象销毁等操作。当然这些只是一些“正规的操作”,我们可以设置一些“非法操作”,在JVM关闭的时候将我们已经注入内存的代码写入到文件,然后再调用startInject方法,startInject方法源码如下:

c081c4925c3e705d3842c87207aeece3.png

再次调用startInject方法后就达到了持久化的目的。

总结

我们再梳理下整个木马工作流程:

1.   获取到目标服务器权限,将Inject.jar和Agent.jar上传至服务器。

2.   执行java -jar Inject.jar password,开始注入Tomcat进程。

3.   注入模块寻找目标类。

4.   将代码注入到Tomcat进程。

5.   成功注入后删除自身。

6.   遇到Tomcat进程重启,将内存代码写入临时文件。

7.   再次注入Tomcat进程达到持久化目的。

注入的核心关键在于Servlet过滤器的internalDoFilter方法,因为所有的用户请求都会通过这个方法。

未来工作

JSP服务器的内存注入,使得JAVA内存马的通用性得到提高。原作者也提到使得这个内存马通用性提高的关键就在于要寻找到“关键类”,Tomcat里使用的是Servlet的过滤器关键类,在其他JAVA容器我们也需要找到这样的一个关键类,这也是未来工作的重点。

7101c464fb8835b1c16bff73614263f3.png

安洵信息技术有限公司

www.i-soon.net

f398d08c7cb79bac86ad582a1dc5fdd2.png

以实力陪伴客户成长  使客户更加强大

400-066-5915

上海丨四川丨江苏 | 云南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374471.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ThunderSearch(闪电搜索器)_网络空间搜索引擎工具_信息收集

文章目录 ThunderSearch简介1 项目地址2 使用方式2.1 配置文件config.json说明2.2 构建和运行 3 使用式例 ThunderSearch简介 ThunderSearch(闪电搜索器)是一款使用多个(【支持Fofa、Shodan、Hunter、Zoomeye、360Quake网络空间搜索引擎】网络空间搜索引…

字符串匹配方法

介绍两种字符串匹配方法1.暴力匹配母串用s表示,长度为m子串用p表示,长度为n时间复杂度为:(m-n1)n算法:从s串的第一个字符开始匹配,若匹配,继续根据p向后匹配,若后续的不匹配,s右移重新匹配p 2.K…

区分几进制的标志

自己总是记不住进制的开头标记,就写下来忘了就看看 1.二进制:Binary,数字以0b 、0B开头 2.八进制:octal number system,数字自然以0打头 3.十六进制:hexadecimal,以0x、0X开头

每个人都知道MVC…

从一个最近的博客中,您可能已经了解到我最近一直在进行一些采访,因为他们是针对Web应用程序开发人员的,所以我问的一个问题是“您能解释一下MVC模式是什么吗?”,值得称赞的是,每个候选人知道答案。 对于不认…

php无限分类

无限循环 1.需要套2个foreach 2.2个foreach结构一样 纯代码获取数据 public function CycleData($parent_id0){$where[parent_id] $parent_id;$res $this->m->where($where)->field(id,name)->select();foreach($res as $k>$v){$result[$v[id]][id] $v[id];$r…

动态网页数据的采集方案

我在上一篇文章中介绍了使用ScrapySharp快速从网页中采集数据,这种方式是通过直接发送的Http请求来获取的原始页面信息,对于静态网页非常有效,但还有许多网站中的页面内容并非全部存放在原始的页面中,很多内容是通过javascript来动…

r语言ggplot2 多线图绘制图例_plotnine: Python版的ggplot2作图库

腾讯课堂 | Python网络爬虫与文本数据分析同样的基本作图任务,plotnine比matplotlib和seaborn代码量少,更美观。所以我又重新发一遍,大家可以先收藏起来,后面总有用到的时候~R语言的ggplot2绘图能力超强,python虽有mat…

单元和集成测试的代码覆盖率

我最近在一个宠物项目中着手构建自动化的UI(集成)测试以及普通的单元测试。 我想将所有这些集成到我的Maven构建中,并提供代码覆盖率报告,以便我可以了解测试覆盖率不足的区域。 我不仅发布了项目的源代码,还整理了一个…

javascript事件与event对象的属性

javascript事件列表解说事件浏览器支持解说一般事件onclickIE3、N2鼠标点击时触发此事件ondblclickIE4、N4鼠标双击时触发此事件onmousedownIE4、N4按下鼠标时触发此事件onmouseupIE4、N4鼠标按下后松开鼠标时触发此事件onmouseoverIE3、N2当鼠标移动到某对象范围的上方时触发此…

感想

读完三篇文章看到了前辈们的努力与坚持和对各自的学科的热爱,以及各位前辈的奋斗的艰苦环境,我与那些前辈相比也许还达不到前辈们的那种级别,但是我的学习的条件却比那些前辈们好的多,看完前辈们的奋斗史,以及前辈们的…

python学生分布_Python数据分析实战之分布分析

前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。 作者:严小样儿 分布分析法,一般是根据分析目的,将数据进行分组,研究各组别分布规律的一种分析方法。…

使用Spring Security 3.1保护RESTful Web服务,第3部分

1.概述 本教程显示了如何使用Spring和基于Java的Spring Security 3.1来保护REST服务 。 本文将重点介绍如何使用“登录和Cookie”方法专门针对REST API设置安全配置。 2. Spring Security的体系结构完全基于Servlet过滤器,因此,在HTTP请求处理方面&…

一次完整的HTTP请求所经历的7个步骤

HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1、建立TCP连接 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共…

jQuery基础--样式篇(3)

1.jQuiery对象与DOM对象   对于刚刚接触jQuery的初学者,我们要清楚认识一点:jQuery对象与DOM对象是不一样的。可能一时半会分不清楚哪些是jQuery对象,哪些是DOM对象,下面重点介绍一下jQuery对象,以及两者相互间的转换…

hls fifo_HLS优化方法DATAFLOW你用了吗

上期内容:异步跨时钟域电路该怎么约束DATAFLOW作为HLS的一种优化方法,对于改善吞吐率(Throughput)、降低延迟(Latency)非常有效。DATAFLOW的作用对象DATAFLOW可以作用于函数,也可以作用于for循环。如下图所示(图片来源Figure62, Figure 63, u…

Java 8虚拟扩展方法

我一直关注Java 8 Lambda表达式项目的发展已经有一段时间了,我对其当前的进展状态感到非常兴奋。 我发现的最新“易于理解”的演示文稿是这样的: http://blogs.oracle.com/briangoetz/resource/devoxx-lang-lib-vm-co-evol.pdf 现在,作为一名…

python爬虫 库_七款必备的Python爬虫库,你知道几个?

很多你需要的信息数据都是在网站内,虽然有些网站的数据会以整洁、结构化的形式呈现,但大部分网站却无法做到这样。因此,当你想要获得一些数据的时候,你需要一些爬虫工具帮助抓取,然后再对其进行分析。今天,…

62个Android Studio小技巧合集

转载: 原文链接:http://laobie.github.io/android/2016/02/14/android-studio-tips.html转载于:https://www.cnblogs.com/kesteler/p/5618490.html

在Hibernate,EhCache,Quartz,DBCP和Spring中启用JMX

继续使用JMX的过程(请参阅: 人类JMX ),我们将学习如何在一些流行的框架中启用JMX支持(通常是统计和监视功能)。 这些信息大部分都可以在项目的主页上找到,但是我决定在收集这些信息的同时&#…

二叉树遍历(前中后)

二叉树前序遍历&#xff1a; /*** Definition for binary tree* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:vector<int> preorderTravers…