java.net.URL getHost因#@同时存在时优先级问题导致的SSRF

#作为锚点,后面的会忽略;@ 作为登录信息,前面的会忽略
对于java.net.URL取主机 getHost()函数,当#@同时存在时,my_host#@baidu.com
高版本#优先,取#前的,即 my_host;
低版本@优先,取@后的,即 baidu.com。

从而导致低版本(具体各小版本号没测试)用getHost时, my_host#@baidu.com 取@后baidu.com绕过白名单,而请求函数等取#前my_host,造成漏洞。

源自真实漏洞

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>demo_collection</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>7</maven.compiler.source>
        <maven.compiler.target>7</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.5</version>
        </dependency>
    </dependencies>

</project>

漏洞代码

import org.apache.commons.lang3.StringUtils;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;


public class ssrf_bypass_case {
    public static void main(String[] args){
        // 正常情况,#作为锚点,后面的会忽略;@ 作为登录信息,前面的会忽略
        // 同时遇到 # 和 @ 时,不同处理函数优先级不同
        // JAVA 7版本中,java.net.URL gethost   @比#优先,取后面a.baidu.com
        // (JAVA 8中,取#前面)
        boolean check_result = isValidPictureUrl("https://aa.dnslog.cn#@a.baidu.com/");
        if(check_result)
            System.out.println("pass");
            // 接下来HTTP请求,#比@优先,取#前面aa.dnslog.cn
        else
            System.out.println("not pass");
    }

    // 图片的协议
    private static final String[] PICTURE_PROTOCOL_ARR = new String[]{
            "https",
            "http"
    };

    // cdn域名的后缀
    private static final Set<String> CDN_DOMAIN_SUFFIX_SET = new HashSet<>(
            Arrays.asList("a.baidu.com", "b.baidu.com"));

    public static boolean isValidPictureUrl(String urlStr) {
        // 判断是否为空
        if (StringUtils.isBlank(urlStr)) {
            return false;
        }

        // 判断是否以http、https开头
        boolean protocolFlag = false;
        for (String pictureProtocol : PICTURE_PROTOCOL_ARR) {
            if (urlStr.startsWith(pictureProtocol)) {
                protocolFlag = true;
                break;
            }
        }
        if (!protocolFlag) {
            return false;
        }

        URL url;
        try {
            url = new URL(urlStr);
        } catch (Exception e) {
            return false;
        }
        String host = url.getHost();
        return CDN_DOMAIN_SUFFIX_SET.contains(host);
    }
}

posted @ 2023-02-27 20:20  huim  阅读(194)  评论(0编辑  收藏  举报