• 구름많음동두천 20.1℃
  • 흐림강릉 20.0℃
  • 구름조금서울 23.4℃
  • 구름많음대전 25.0℃
  • 천둥번개대구 19.9℃
  • 구름많음울산 19.6℃
  • 맑음광주 24.6℃
  • 구름많음부산 22.2℃
  • 맑음고창 22.9℃
  • 맑음제주 23.3℃
  • 구름많음강화 20.5℃
  • 구름많음보은 24.5℃
  • 구름조금금산 24.1℃
  • 맑음강진군 25.8℃
  • 흐림경주시 20.4℃
  • 맑음거제 22.8℃
기상청 제공

php injection, safe_mod

요즘 php injection 보안버그 때문에 말이 많습니다. phpbb의 경우에는 worm 같이 그 외에 많이 사용되는 zeroboard, korweblog, jsboard, gnuboard 등등..

대부분의 injection 보안버그는 대부분 system 관련 함수를 사용하여 spam 을 보내거나 index page 를 변고 하거나, 대부분의 관리자들이 간과하는 local expolit 을 실행해서 root shell 을 얻는데 많이 이용됩니다. 이 경우 가장 많이 사용되는 것이 system 함수이며, 그 외에 exec, passthru, popen 등의 함수가 있습니다. php.ini 에서 이 함수들을 막아놓는 것도 한방법이지만 그렇다고 막으면 원성이 자자합니다.

그러던 중에, safe mode 에서 사용되는 safe_mode_exec_dir 을 safe mode 가 아닐 경우에도 사용을 할 수 있으면, system 관련 함수를 제어하는데 아주 좋을 것 같아서, php 4.3.10 을 기준으로 safe mode 가 아닐때도 사용이 가능하도록 패치를 해 보았습니다.

대략 safe mode 일 경우, php 는 meta charactor 를 escape 시키는데 반해서 safe mode 가 아닐 경우에는 이를 정상적으로 이용할 수 있도록 패치가 되었습니다.

보통 safe mode 에서 system 함수를 사용하면, php 를 빌드 할 때, prefix 를 /usr/local 로 하면 safe_mode_exec_dir 의 기본값은 /usr/local/bin 이 되며, /usr 로 했을 경우에는 /usr/bin 이 됩니다. 하지만 php.ini 의 기본 설정이

인용:


safe_mode_exec_dir =

참고로
safe_mode_exec_dir =

;safe_mode_exec_dir =
는 완전히 다른 설정값을 가지게 됩니다. 전자는 safe mode 에서는 / 가 되며,

후자는 configure 시의 가본값이 됩니다.



와 같이 되어 있으므로 실제로는 "/명령어" 가 실행이 됩니다. 또한 아래와 같은 명령은

인용:

/usr/bin/cat /etc/passwd; ls -al


인용:

/cat /etc/passwd; ls -al


와 같이 치환이 됩니다. 위와 같이 기본 명령의 path 가 safe_mode_exec_dir 로 명령어의 path 가 변경이 되고, meta charactor 가 존재할 경우에는 escape 처리를 해서 에러가 나게 만드는 것이 safe mode 에서의 system 관련 함수 제어를 합니다.

아래의 nosafe_mode_exec_dir 패치를 적용할 경우에는 다음과 같이 치환이 됩니다.
일단

인용:

safe_mode_exec_dir =


과 같이 지정이 되어 있을 경우에는, 패치를 하지 않았을 경우와 완전하게 동일하게 작동을 합니다. (이 경우가 기본값입니다.

인용:

;safe_mode_exec_dir =


와 같이 주석 처리가 된다면 ./configure 시의 값이 적용이 됩니다.

인용:

safe_mode_exec_dir = /var/php/bin


과 같이 지정이 된다면, 명령어의 모든 경로는 /var/php/bin/명령어 가 됩니다. 처리가 가능한 파서는

인용:

명령; 명령
명령 $(명령)
명령 `명령`
명령 | 명령
명령 && 명령
명령 || 명령


을 parsing 할 수 있습니다. 즉,

인용:

cat $(echo "/etc/passwd") | /bin/grep root; ls -al
or
cat `echo "/etc/passwd"` | grep root; ls -al


와 같이 system 함수를 사용을 하면,

인용:

/var/php/bin/cat $(/var/php/bin/echo "/etc/passwd") | /var/php/bin/grep root; /var/php/bin/ls -al
or
/var/php/bin/cat `/var/php/bin/echo "/etc/passwd"` | /var/php/bin/grep root; /var/php/bin/ls -al


와 같이 쉘에서 사용할 수 있는 명령어 형식의 명령들의 path 는 safe_mode_exec_dir 에 지정한 경로로 변경이 되게 됩니다. 즉, system 함수를 막지 않고서도, 꼭 사용해야만 하는 명령들 (예를 들어 moniwiki 의 경우 rcs package 의 명령들을 사용하죠) 을 /var/php/bin 에 soft link 만 시켜 놓으면 된다는 얘기입니다. 즉 system 함수를 풀어 주고서도, cracker 들이 노리는 xterm 이나 wget 같은 것을 만질 수 없게 함으로서 cracker 들의 제약을 할 수가 있는 것입니다.

이와 더불어 각 가상 호스트 별로 open_basedir 을 document root 로 지정을 하고, php.ini 에서 upload tmp 와 session save_path 를 다른 곳으로 이동을 시키면 계정간의 보안도 어느정도 처리를 할 수가 있게 됩니다.

예를 들어 php.ini 에서

인용:

safe_mode_exec_dir = /var/php/bin
upload_tmp_dir = /var/php/tmp
session.safe_path = /var/php/session

chown apache.apache /var/php/{tmp,session}


<VirtualHost IP-ADDR>
DocumentRoot /path/domain
ServerName Some-Domain

<IfModule mod_php4.c>
php_admin_value open_basedir /path/domain:/var/php
</IfModule>
</VritualHost>


와 같이 지정을 하고, 각 계정의 권한을 711 과 같이 지정을 한다면, php 를 이용해서 남의 계정을 탐색하는 것 자체를 원천 봉쇄를 할 수 있습니다. 이는, nosafe_mode_exec_dir 패치가 되어 있어야 되며, open_basedir 은 system 함수를 이용해서 shell 명령을 실행하는 것과는 무관하기 때문입니다.

또한, safe_mode_exec_dir 을 사용할 경우 주의해야 할 것은 find 와 같이 옵션으로 명령행을 실행시키는 경우는 파싱이 되지 않으므로 될 수 있으면 사용을 하지 않는 것이 좋습니다. 즉 예를 들어

인용:

find /tmp -exec ls -al
=> /var/php/bin/find /tmp -exec ls -al


과 같이 파싱이 되기 때문에 safe_mode_exec_dir 의 영향을 받지않고 시스템 명령을 실행할 수가 있음을 주의하셔야 합니다. 이 패치에 영향을 받는 함수는 아래와 같습니다.

인용:

popen
exec
system
passthru
proc_open
shell_exec


또는, 내부적으로 php_Exec 함수를 호출하는 함수들은 모두 적용이 됩니다.

* 변경 사항

&& 구문과 || 구문 파싱 가능하도록 변경.
첫 번 째 명령어가 잘리는 현상 수정
shell_exec 함수에서도 작동 하도록 변경
popen 에서도 get_php_shell_cmd call 을 사용하도록 변경