利用Bambdas发掘非常规端点的Web安全研究

本文介绍了PortSwigger团队如何利用Burp Suite的Bambda功能快速发现异常HTTP端点,包括大型重定向响应、多重HTML标签、错误内容长度及畸形HTTP头等漏洞模式,通过具体代码示例展示高效的安全测试方法。

安全研究往往伴随着大量失败。这是在采取可预测但枯燥的小步骤与尝试可能成功但大概率失败的疯狂概念之间不断权衡的过程。

在PortSwigger Research,我们发现降低疯狂创意的尝试成本极具价值,因为这能最小化失败代价,鼓励大胆实验并带来激动人心的发现。我们通常通过编写自定义Burp扩展来测试想法,并在一个包含约所有允许测试网站首页的20GB项目文件上运行这些扩展。

Burp Suite近期推出的Bambda功能允许用户直接在代理中编写迷你扩展,支持代码自动补全、语法高亮和即时评估。我们发现这极大提升了漏洞挖掘效率,因为它消除了对独立IDE的需求并提供即时反馈。

我们快速开发了一系列用于检测异常HTTP端点行为的Bambda,以下是其中至少发现过一个真实网站问题的示例:

大型重定向响应 检测响应体超过1000字节的重定向响应,可能表明网站在用户认证失败时未终止脚本执行,通常导致信息泄露:

1
2
3
4
return requestResponse.hasResponse() &&
       requestResponse.response().statusCode() <= 399 &&
       requestResponse.response().statusCode() >= 300 &&
       requestResponse.response().body().length() > 1000;

多重标签响应 当页面未在正确点退出脚本且非重定向响应时,可能导致响应包含多个HTML闭合标签。通过过滤仅显示HTML内容类型的响应,我们发现了一个本应受认证保护的页面和意外的源代码泄漏:

1
2
3
return requestResponse.response().statedMimeType() == MimeType.HTML &&
       utilities().byteUtils().countMatches(
       requestResponse.response().body().getBytes(), "</html>".getBytes()) > 1;

错误内容长度 检测中间件注入额外内容但未修正Content-Length的情况:

1
2
3
4
int realContentLength = requestResponse.response().body().length();
int declaredContentLength = Integer.parseInt(    
     requestResponse.response().headerValue("Content-Length"));
return declaredContentLength != realContentLength;

畸形HTTP头 检测响应头名称包含空格的异常情况,意外发现多个在443端口运行SMTP的服务器:

1
2
return requestResponse.response().headers().stream().anyMatch(    
     e -> e.name().contains(" "));

Gareth的Bambda示例

查找无MIME类型或text/html类型的JSON端点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
if(!requestResponse.hasResponse()) {
    return false;
}
var response = requestResponse.response();
if (response.hasHeader("Content-Type")) {
    if (!response.headerValue("Content-Type").contains("text/html")) {
        return false;
    }
}

String body = response.bodyToString().trim();
boolean looksLikeJson = body.startsWith("{") || body.startsWith("[");

if(!looksLikeJson) {
    return false;
}

return true;

查找非常规位置的GraphQL端点:

 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
var req = requestResponse.request();

if(!req.hasParameters()) {
    return false;
}

var types = new HttpParameterType[]{
HttpParameterType.JSON, HttpParameterType.BODY, HttpParameterType.URL
};
for(HttpParameterType type: types) {
    if(req.hasParameter("query", type)) {
     var value = req.parameterValue("query", type);
        if(type == HttpParameterType.JSON) {
        if(value.contains("\\n")) {
                return true;
            }
        } else {
            if(value.toLowerCase().contains("%0a")) {
                return true;
            }
        }
    }
}

return false;

查找用于CSP绕过JSONP端点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
var req = requestResponse.request();
var res = requestResponse.response();
var paramRegex = Pattern.compile("^[a-zA-Z][.\\w]{4,}$");

if(res == null || res.body().length() == 0) return false;

if(!req.hasParameters()) return false;

var body = res.bodyToString().trim();
var params = req.parameters();
for(var param: params) {
    var value = param.value();
    if(param.type() != HttpParameterType.URL)continue;
    if(paramRegex.matcher(value).find()) {
        var start = "(?:^|[^\\w'\".])";
        var end = "\\s*[(]";
        var callbackRegex = Pattern.compile(start+Pattern.quote(value)+end);
        if(callbackRegex.matcher(body).find())return true;
    }
}

return false;

这些Bambda总计耗时不到一小时,却实现了极具趣味性的研究。我们已在https://github.com/PortSwigger/bambdas 建立精选代码库,期待看到社区未来的发现。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计