利用“进程注入”实现无文件复活 WebShell
上周末,一个好兄弟找我说一个很重要的目标shell丢了,这个shell之前是通过一个S2代码执行的漏洞拿到的,现在漏洞还在,不过web目录全部不可写,问我有没有办法搞个webshell继续做内网。正好我之前一直有个通过“进程注入”来实现内存webshell的想法,于是就趁这个机会以Java为例做了个内存webshell出来(暂且叫它memShell吧),给大家分享一下:)
前言
一般在渗透过程中,我们通常会用到webshell,一个以文件的形式存在于Web容器内的恶意脚本文件。我们通过webshell来让Web Server来执行我们的任意指令。如果在某些机选情况下,我们不想或者不能在Web目录下面写入文件,是不是就束手无策了?当然不是,写入webshell并不是让Web Server来执行我们任意代码的唯一方式,通过直接修改进程的内存也可以实现这个目的。我们只要拥有一个web容器进程执行用户的权限,理论上就可以完全控制该进程的地址空间(更确切的说是地址空间中的非Kernel部分),包括地址空间内的数据和代码。OS层进程注入的方法有很多,不过具体到Java环境,我们不需要使用操作系统层面的进程注入方法。Java为我们提供了更方便的接口:Java Instrumentation。
Java Instrumentation简介
先看下官方概念:java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。简单一句话概括下:Java Instrumentation可以在JVM启动后,动态修改已加载或者未加载的类,包括类的属性、方法。该机制最早于Java SE5 引入,Java SE6之后的机制相对于Java SE5有较大改进,因为现在Java SE5这种古董级别的环境已经不多,此处不再赘述。
下面看一个简单的例子:首先新建3个Java工程Example、Agent和AgentStarter。
在工程Example中新建2个类:
Bird.java:
public class Bird {
public void say()
{
System.out.println("bird is gone.");
}
}
然后把编译后的Bird.class复制出来,放到D盘根目录。然后把Bird.java再改成如下:
Bird.java:
public class Bird {
public void say()
{
System.out.println("bird say hello");
}
}
Main.java:
public class Main {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
while(true)
{
Bird bird=new Bird();
bird.say();
Thread.sleep(3000);
}
}
}
把整个工程打包成可执行jar包normal.jar,放到D盘根目录。在工程Agent中新建2个类:
AgentEntry.java:
public class AgentEntry {
public static void agentmain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException,
InterruptedException {
inst.addTransformer(new Transformer (), true);
Class[] loadedClasses = inst.getAllLoadedClasses();
for (Class c : loadedClasses) {
if (c.getName().equals("Bird")) {
try {
inst.retransformClasses(c);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println("Class changed!");
}
}
Transformer.java:
public class Transformer implements ClassFileTransformer {
static byte[] mergeByteArray(byte[]... byteArray) {
int totalLength = 0;
for(int i = 0; i if(byteArray[i] == null) {
continue;
上周末,一个好兄弟找我说一个很重要的目标shell丢了,这个shell之前是通过一个S2代码执行的漏洞拿到的,现在漏洞还在,不过web目录全部不可写,问我有没有办法搞个webshell继续做内网。正好我之前一直有个通过“进程注入”来实现内存webshell的想法,于是就趁这个机会以Java为例做了个内存webshell出来(暂且叫它memShell吧),给大家分享一下:)
前言
一般在渗透过程中,我们通常会用到webshell,一个以文件的形式存在于Web容器内的恶意脚本文件。我们通过webshell来让Web Server来执行我们的任意指令。如果在某些机选情况下,我们不想或者不能在Web目录下面写入文件,是不是就束手无策了?当然不是,写入webshell并不是让Web Server来执行我们任意代码的唯一方式,通过直接修改进程的内存也可以实现这个目的。我们只要拥有一个web容器进程执行用户的权限,理论上就可以完全控制该进程的地址空间(更确切的说是地址空间中的非Kernel部分),包括地址空间内的数据和代码。OS层进程注入的方法有很多,不过具体到Java环境,我们不需要使用操作系统层面的进程注入方法。Java为我们提供了更方便的接口:Java Instrumentation。 www.wnhack.com
Java Instrumentation简介
先看下官方概念:java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。简单一句话概括下:Java Instrumentation可以在JVM启动后,动态修改已加载或者未加载的类,包括类的属性、方法。该机制最早于Java SE5 引入,Java SE6之后的机制相对于Java SE5有较大改进,因为现在Java SE5这种古董级别的环境已经不多,此处不再赘述。
下面看一个简单的例子:首先新建3个Java工程Example、Agent和AgentStarter。
在工程Example中新建2个类:
Bird.java:
public class Bird {
public void say()
{
System.out.println("bird is gone.");
}
}
然后把编译后的Bird.class复制出来,放到D盘根目录。然后把Bird.java再改成如下:
Bird.java:
public class Bird {
public void say()
{
System.out.println("bird say hello"); 无奈人生安全网
}
}
Main.java:
public class Main {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
while(true)
{
Bird bird=new Bird();
bird.say();
Thread.sleep(3000);
}
}
}
把整个工程打包成可执行jar包normal.jar,放到D盘根目录。在工程Agent中新建2个类:
AgentEntry.java:
public class AgentEntry {
public static void agentmain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException,
InterruptedException {
inst.addTransformer(new Transformer (), true);
Class[] loadedClasses = inst.getAllLoadedClasses();
for (Class c : loadedClasses) {
if (c.getName().equals("Bird")) {
try {
inst.retransformClasses(c);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace(); 无奈人生安全网
}
}
}
System.out.println("Class changed!");
}
}
Transformer.java:
public class Transformer implements ClassFileTransformer {
static byte[] mergeByteArray(byte[]... byteArray) {
int totalLength = 0;
for(int i = 0; i if(byteArray[i] == null) {
continue;