/*
http://beist.org
beist@hanmail.net
wowcode at wowhacker team
*/
1) system, exec, passthru 함수 사용시 주의할점
Cracker 가 Web Hacking 시에 가장 궁극적인 목적은 (원하는) 바로 System
명령어 실행일 것이다. 개발자가 Web 프로그래밍을 할때 프로그램에 필요한 기능으로
Language 에서 제공하는 System Execute Fucntion 을 사용하는 경우가 많이 있다.
이러한 기능을 하는 Function 으로써, PHP 를 예를 들자면 system() 나 exec()
Function 을 들 수 있다. 이와 같은 System Execute Function 들은 Web 에서 System 으로 명령을 Execute 를 할 수 있게끔 도와준다. 그리고 실행되는 Process 들의 권한은 현재 돌아가고 있는 WebServer 의 uid, gid, euid, guid 로 실행된다. (프로세스가 가지는 것은 effective uid 이다.)
uid (user identifier) 같은 것들은 like unix 에서 사용자를 구별하기 위해
사용되는 숫자 또는 이름이다. like unix 에서는 보안을 위하여 uid 나 혹은
euid 를 갖고 그 사용자의 권한을 Check 하는 경우가 많다.
Web 어플리케이션 개발자로서 이러한 부분은 크게 신경쓰지 않아도 된다.
실질적으로 Web 에서 System Execute 를 하였다고 하여도, 커널 내부적으로는
보통의 uid 를 가진 user 가 Shell 상에서 System call 을 요청하는 것이랑 별반
다를바가 없지만 Web 어플리케이션 개발자는 그런 깊숙한 부분은 신경쓸 필요가
없다는 이야기이다. Web 어플리케이션 개발자는 Cracker 가 System 에 침입할 수
없게끔 1 차 적인 보안 조취를 취하도록 프로그래밍을 하면 된다.
그러면 실제로 Web 프로그래밍을 할시에 system(), exec() 같은 Function 을
사용하는 경우는 어떤 경우인가. 가장 대표적인 예를 들자면 게시판을 들 수가
있다. 예를 들어 사용자가 Upload Board 를 이용해 특정 자료를 Server 에
올렸다고 하자. 그런데 자료 Upload 에 실수를 하여 게시물을 지우고자 할때는
Delete 메뉴를 이용한다. Delete 메뉴를 이용하여 해당 게시물을 지우고,
같이 올려진 파일도 지워야 한다. 예를 들어 다음과 같이 지운다고 하자.
http://beist.org/delete.php?text=1.txt&file=1.zip
/* delete.php 파일을 요청할때 argument 로 text 와 file 을 건내주었고
그 값은 해당 게시물이 담긴 txt 파일과 Upload 시에 올린 자료명이다. */
sample1.php
<?
/* 생략 */
system("/bin/rm -f data/$text");
system("/bin/rm -f data/$file");
/* 생략 */
?>
/* system() Function 을 이용하여 OS 내부에 있는 /bin/rm 이라는 프로그램을
이용하여 data 디렉토리 밑의 1.txt 를 지우게 한 프로그램이다.
/bin/rm 은 지우기를 시도하는 사용자의 ID 가 해당 지우려고 하는 파일의
소유자와 일치할때 그 파일을 지워주는 프로그램이다. /bin/rm 을 실행할때
준 -f 옵션은 force 의 의미로써 조건만 만족한다면 무조건 지우는 옵션을
뜻한다. */
sample1.php 에는 게시물 처리를 위하여 다른 부분도 필요하겠지만 여기서는
이해를 쉽게 하기 위하여 프로그램에서 취약한 부분만을 적게 되었다.
이런 식으로 Web CGI 에서 System Execute Function 은 이용된다. 그러면 이제
실제로 존재하는 CGI 에서 System Execute Function 을 잘못 사용하였을때 일어
나는 취약점을 알아보자.
실제로 필자가 발견한 버그를 이용할 것이다. 해당되는 Web CGI 는 게시판으로
유명한 Zeroboard 3.5.x 이다. 이 글을 쓰는 지금, Zeroboard 의 버전은 4.0.x
버전까지 나와있지만 잘못된 System Execute Function 사용으로 인한 결과를
설명하기에 적절한 코드인것 같아 이것으로 설명하겠다.
문제가 되는 부분은 zeroboard 의 delete_list.php3 파일이다.
delete_list.php3
1 <?
2 // 지금 삭제할려는 글의 데이타를 가져옴
3 $data=mysql_fetch_array(mysql_query("select * from zeroboard_$id where
4 no='$no'",$connect));
5 // 이 글에 답글이 있는지 없는지를 검사
6 $check=mysql_fetch_array(mysql_query("select count(*) from zeroboard_$id
7 where headnum='$data[headnum]' and arrangenum>'$data[arrangenum]' and
8 depth>'$data[depth]'", $connect));
9 if($check[0]>0) Error("답글이 있는 글은 삭제할수 없습니다");
10
11 // 파일삭제
12 if($data[file_name]||$data[file_name2])
13 {
14 @system("rm -rf data/$id/$data[reg_date]/$data[file_name]");
15 @system("rm -rf data/$id/$data[reg_date]/$data[file_name2]");
17 @system("rm -rf data/$id/$data[reg_date]");
18 @unlink("data/$id/$data[reg_date]/$data[file_name]");
19 @unlink("data/$id/$data[reg_date]/$data[file_name2]");
20 @unlink("data/$id/$data[reg_date]");
21 }
22
23 // 글 삭제
24 mysql_query("delete from zeroboard_$id where no='$no'",$connect); 25 mysql_query("delete from zeroboard_memo_$id where parent='$no'",$connect); 26 $temp=mysql_fetch_array(mysql_query("select count(no) from zeroboard_$id", 27 $connect)); 28 mysql_query("update $admin_table set total='$temp[0]' where name='$id'", 29 $connect); 30 31 // 간단한 답글 삭제 32 mysql_query("delete from $comment_table where table_name='$id' and parent='$no'", 33 $connect); 34 ?>
이 script 의 기능은 특정 게시물을 지우는 것이다. 지울 때 file 도 같이 삭제를 한다.
중요 취약성이 되는 부분은 14~17 라인이다. $data[file_name] 과 $data[file_name2] 변수는 file name 이다.
zeroboard 에서 upload 된 file 이 놓이는 위치는 data/$id/$data[reg_date] 이다. $id 는 board name 을 뜻하고 $data[reg_date] 는 게시물을 쓴 시간을 뜻한다. 이 것들은 mysql database 에 담겨있으며 3 번째 라인에서처럼 가져와 $data 변수에 담는다.
file 을 지울때 System Execute Function 인 system 함수를 이용하는데 Cracker 는 이를 이용하여 System 에 침입할 수가 있다.
자세한 방법을 알아보자. Cracker 는 Write Form 에서 File upload 할때 File 의 이름을 임의로 설정할 수 있다.
write_main.php3
1 <?
2 // 자료실 사용시
3 if($data[file_name])
4 {
5 $file_exist=$data[file_name]."파일이 등록되어 있습니다
6 <br>";$file_del="<input type=checkbox name=del_file value=1> 삭제";
7 }
8 if($data[file_name2])
9 {
10 $file_exist2=$data[file_name2]."파일이 등록되어 있습니다<br>";
11 $file_del2="<input type=checkbox name=del_file2 value=1> 삭제"; 12 }
13 if($setup[use_pds])
14 {
15 ?>
16 <tr>
17 <td align=right>Upload File </td>
18 <td><div style=line-height:160%>
19 <? echo $file_exist;?> <input type=file name=file
20 size=<?echo $size[8];?> maxlength=255 class=input>
21 <? echo $file_del; ?><br>
22 <? echo $file_exist2;?> <input type=file name=file2
23 size=<?echo $size[8];?> maxlength=255 class=input>
24 <? echo $file_del2; ?>
25 </tr>
26 <?
27 }
28 ?>
위 소스는 write_main.php3 의 일부이다. 취약성이 되는 부분은 아니고 사용자가
Write 버튼을 클릭했을때 보여주는 Write Form 이다. 13 번째 줄에서 Admin 이
해당 게시판에 File Upload 를 허용했다면 16~25 줄까지의 내용을 뿌린다. 잠깐
살펴보면
<input type=file name=file size=200000000 maxlength=255 class=input>
이 정도일 것이다. 우리는 이 필드를 이용하여 File 을 Upload 할 수 있는데,
여기서 악의적인 조취를 취하면 Server 에 특정 Command 를 실행할 수 있다.
delete_list.php3 에서 봤듯이 file 을 지울때 rm 을 이용하여 지우게 된다.
이는 shell 을 사용한다는 것이다. ; 와 | 는 연속, 연결을 의미하니까 file
name 에서 악의적인 file name 을 주면 cracker 는 원하는 일을 할 수 있다.
ex)
filename : test;/usr/bin/touch /tmp/imbeist
이런 식으로 file name 을 주어 Server 에 올린다면 mysql Database 에도
test;/usr/bin/touch /tmp/imbeist 가 올라가게 될 것이다. 그리고 해당 게시물을
다시 지운다면 delete_list.php3 에 의해서
@system("rm -rf data/test1/4444444/test;/usr/bin/touch /tmp/imbeist");
의 명령이 실행될 것이다.
(여기서 test1 과 4444444 는 임의로 만든 것이다)
그렇다면 세미콜론에 의해서 두 명령이 내려질 것이고 touch 를 이용하여
cracker 는 /tmp directory 밑에 imbeist 라는 file 을 생성시킬 수 있다.
이 것을 이용하여 term 이라든가 port 를 열어서 shell 을 실행 시킬수 있게끔
해놓는다던가 방법은 많다. Cracker 에게 있어서 이 Security Hole 은 Web hacking
에 있어서 궁극적인 목표까지 다달은 것이다.
해결책을 알아 보자.
필자가 생각하는 해결 방법은 (위의 상황으로만 프로그래밍을 해야할때)
file name 을 체크하는 것이다. file name 에는 정상적인 알파벳이나 숫자, 그리고
. 를 제외하고 나머지의 문자가 들어갈 필요가 없다. 그래서 file name 을 검사할때
만약 ../ or ; or | 같은 문자가 들어온다면 script 실행을 중지하는 것이 좋을것
같다.
if(eregi(";", $file_name))
{
echo "장난하니?.. file 이름에 ; 가 들어있습니다.";
exit;
}
if(eregi("\|", $file_name))
{
echo "장난하니?.. file 이름에 | 가 들어있습니다.";
exit;
}
(여기에서는 ; 과 | 만 처리를 하였다.)
위와 같은 방법으로 script 실행을 중지하는 것을 원치 않는다면 eregi_replace
같은 function 을 이용하여 빈칸으로 만드는 방법도 괜찮은 방법이다.
http://beist.org
beist@hanmail.net
wowcode at wowhacker team
*/
1) system, exec, passthru 함수 사용시 주의할점
Cracker 가 Web Hacking 시에 가장 궁극적인 목적은 (원하는) 바로 System
명령어 실행일 것이다. 개발자가 Web 프로그래밍을 할때 프로그램에 필요한 기능으로
Language 에서 제공하는 System Execute Fucntion 을 사용하는 경우가 많이 있다.
이러한 기능을 하는 Function 으로써, PHP 를 예를 들자면 system() 나 exec()
Function 을 들 수 있다. 이와 같은 System Execute Function 들은 Web 에서 System 으로 명령을 Execute 를 할 수 있게끔 도와준다. 그리고 실행되는 Process 들의 권한은 현재 돌아가고 있는 WebServer 의 uid, gid, euid, guid 로 실행된다. (프로세스가 가지는 것은 effective uid 이다.)
uid (user identifier) 같은 것들은 like unix 에서 사용자를 구별하기 위해
사용되는 숫자 또는 이름이다. like unix 에서는 보안을 위하여 uid 나 혹은
euid 를 갖고 그 사용자의 권한을 Check 하는 경우가 많다.
Web 어플리케이션 개발자로서 이러한 부분은 크게 신경쓰지 않아도 된다.
실질적으로 Web 에서 System Execute 를 하였다고 하여도, 커널 내부적으로는
보통의 uid 를 가진 user 가 Shell 상에서 System call 을 요청하는 것이랑 별반
다를바가 없지만 Web 어플리케이션 개발자는 그런 깊숙한 부분은 신경쓸 필요가
없다는 이야기이다. Web 어플리케이션 개발자는 Cracker 가 System 에 침입할 수
없게끔 1 차 적인 보안 조취를 취하도록 프로그래밍을 하면 된다.
그러면 실제로 Web 프로그래밍을 할시에 system(), exec() 같은 Function 을
사용하는 경우는 어떤 경우인가. 가장 대표적인 예를 들자면 게시판을 들 수가
있다. 예를 들어 사용자가 Upload Board 를 이용해 특정 자료를 Server 에
올렸다고 하자. 그런데 자료 Upload 에 실수를 하여 게시물을 지우고자 할때는
Delete 메뉴를 이용한다. Delete 메뉴를 이용하여 해당 게시물을 지우고,
같이 올려진 파일도 지워야 한다. 예를 들어 다음과 같이 지운다고 하자.
http://beist.org/delete.php?text=1.txt&file=1.zip
/* delete.php 파일을 요청할때 argument 로 text 와 file 을 건내주었고
그 값은 해당 게시물이 담긴 txt 파일과 Upload 시에 올린 자료명이다. */
sample1.php
<?
/* 생략 */
system("/bin/rm -f data/$text");
system("/bin/rm -f data/$file");
/* 생략 */
?>
/* system() Function 을 이용하여 OS 내부에 있는 /bin/rm 이라는 프로그램을
이용하여 data 디렉토리 밑의 1.txt 를 지우게 한 프로그램이다.
/bin/rm 은 지우기를 시도하는 사용자의 ID 가 해당 지우려고 하는 파일의
소유자와 일치할때 그 파일을 지워주는 프로그램이다. /bin/rm 을 실행할때
준 -f 옵션은 force 의 의미로써 조건만 만족한다면 무조건 지우는 옵션을
뜻한다. */
sample1.php 에는 게시물 처리를 위하여 다른 부분도 필요하겠지만 여기서는
이해를 쉽게 하기 위하여 프로그램에서 취약한 부분만을 적게 되었다.
이런 식으로 Web CGI 에서 System Execute Function 은 이용된다. 그러면 이제
실제로 존재하는 CGI 에서 System Execute Function 을 잘못 사용하였을때 일어
나는 취약점을 알아보자.
실제로 필자가 발견한 버그를 이용할 것이다. 해당되는 Web CGI 는 게시판으로
유명한 Zeroboard 3.5.x 이다. 이 글을 쓰는 지금, Zeroboard 의 버전은 4.0.x
버전까지 나와있지만 잘못된 System Execute Function 사용으로 인한 결과를
설명하기에 적절한 코드인것 같아 이것으로 설명하겠다.
문제가 되는 부분은 zeroboard 의 delete_list.php3 파일이다.
delete_list.php3
1 <?
2 // 지금 삭제할려는 글의 데이타를 가져옴
3 $data=mysql_fetch_array(mysql_query("select * from zeroboard_$id where
4 no='$no'",$connect));
5 // 이 글에 답글이 있는지 없는지를 검사
6 $check=mysql_fetch_array(mysql_query("select count(*) from zeroboard_$id
7 where headnum='$data[headnum]' and arrangenum>'$data[arrangenum]' and
8 depth>'$data[depth]'", $connect));
9 if($check[0]>0) Error("답글이 있는 글은 삭제할수 없습니다");
10
11 // 파일삭제
12 if($data[file_name]||$data[file_name2])
13 {
14 @system("rm -rf data/$id/$data[reg_date]/$data[file_name]");
15 @system("rm -rf data/$id/$data[reg_date]/$data[file_name2]");
17 @system("rm -rf data/$id/$data[reg_date]");
18 @unlink("data/$id/$data[reg_date]/$data[file_name]");
19 @unlink("data/$id/$data[reg_date]/$data[file_name2]");
20 @unlink("data/$id/$data[reg_date]");
21 }
22
23 // 글 삭제
24 mysql_query("delete from zeroboard_$id where no='$no'",$connect); 25 mysql_query("delete from zeroboard_memo_$id where parent='$no'",$connect); 26 $temp=mysql_fetch_array(mysql_query("select count(no) from zeroboard_$id", 27 $connect)); 28 mysql_query("update $admin_table set total='$temp[0]' where name='$id'", 29 $connect); 30 31 // 간단한 답글 삭제 32 mysql_query("delete from $comment_table where table_name='$id' and parent='$no'", 33 $connect); 34 ?>
이 script 의 기능은 특정 게시물을 지우는 것이다. 지울 때 file 도 같이 삭제를 한다.
중요 취약성이 되는 부분은 14~17 라인이다. $data[file_name] 과 $data[file_name2] 변수는 file name 이다.
zeroboard 에서 upload 된 file 이 놓이는 위치는 data/$id/$data[reg_date] 이다. $id 는 board name 을 뜻하고 $data[reg_date] 는 게시물을 쓴 시간을 뜻한다. 이 것들은 mysql database 에 담겨있으며 3 번째 라인에서처럼 가져와 $data 변수에 담는다.
file 을 지울때 System Execute Function 인 system 함수를 이용하는데 Cracker 는 이를 이용하여 System 에 침입할 수가 있다.
자세한 방법을 알아보자. Cracker 는 Write Form 에서 File upload 할때 File 의 이름을 임의로 설정할 수 있다.
write_main.php3
1 <?
2 // 자료실 사용시
3 if($data[file_name])
4 {
5 $file_exist=$data[file_name]."파일이 등록되어 있습니다
6 <br>";$file_del="<input type=checkbox name=del_file value=1> 삭제";
7 }
8 if($data[file_name2])
9 {
10 $file_exist2=$data[file_name2]."파일이 등록되어 있습니다<br>";
11 $file_del2="<input type=checkbox name=del_file2 value=1> 삭제"; 12 }
13 if($setup[use_pds])
14 {
15 ?>
16 <tr>
17 <td align=right>Upload File </td>
18 <td><div style=line-height:160%>
19 <? echo $file_exist;?> <input type=file name=file
20 size=<?echo $size[8];?> maxlength=255 class=input>
21 <? echo $file_del; ?><br>
22 <? echo $file_exist2;?> <input type=file name=file2
23 size=<?echo $size[8];?> maxlength=255 class=input>
24 <? echo $file_del2; ?>
25 </tr>
26 <?
27 }
28 ?>
위 소스는 write_main.php3 의 일부이다. 취약성이 되는 부분은 아니고 사용자가
Write 버튼을 클릭했을때 보여주는 Write Form 이다. 13 번째 줄에서 Admin 이
해당 게시판에 File Upload 를 허용했다면 16~25 줄까지의 내용을 뿌린다. 잠깐
살펴보면
<input type=file name=file size=200000000 maxlength=255 class=input>
이 정도일 것이다. 우리는 이 필드를 이용하여 File 을 Upload 할 수 있는데,
여기서 악의적인 조취를 취하면 Server 에 특정 Command 를 실행할 수 있다.
delete_list.php3 에서 봤듯이 file 을 지울때 rm 을 이용하여 지우게 된다.
이는 shell 을 사용한다는 것이다. ; 와 | 는 연속, 연결을 의미하니까 file
name 에서 악의적인 file name 을 주면 cracker 는 원하는 일을 할 수 있다.
ex)
filename : test;/usr/bin/touch /tmp/imbeist
이런 식으로 file name 을 주어 Server 에 올린다면 mysql Database 에도
test;/usr/bin/touch /tmp/imbeist 가 올라가게 될 것이다. 그리고 해당 게시물을
다시 지운다면 delete_list.php3 에 의해서
@system("rm -rf data/test1/4444444/test;/usr/bin/touch /tmp/imbeist");
의 명령이 실행될 것이다.
(여기서 test1 과 4444444 는 임의로 만든 것이다)
그렇다면 세미콜론에 의해서 두 명령이 내려질 것이고 touch 를 이용하여
cracker 는 /tmp directory 밑에 imbeist 라는 file 을 생성시킬 수 있다.
이 것을 이용하여 term 이라든가 port 를 열어서 shell 을 실행 시킬수 있게끔
해놓는다던가 방법은 많다. Cracker 에게 있어서 이 Security Hole 은 Web hacking
에 있어서 궁극적인 목표까지 다달은 것이다.
해결책을 알아 보자.
필자가 생각하는 해결 방법은 (위의 상황으로만 프로그래밍을 해야할때)
file name 을 체크하는 것이다. file name 에는 정상적인 알파벳이나 숫자, 그리고
. 를 제외하고 나머지의 문자가 들어갈 필요가 없다. 그래서 file name 을 검사할때
만약 ../ or ; or | 같은 문자가 들어온다면 script 실행을 중지하는 것이 좋을것
같다.
if(eregi(";", $file_name))
{
echo "장난하니?.. file 이름에 ; 가 들어있습니다.";
exit;
}
if(eregi("\|", $file_name))
{
echo "장난하니?.. file 이름에 | 가 들어있습니다.";
exit;
}
(여기에서는 ; 과 | 만 처리를 하였다.)
위와 같은 방법으로 script 실행을 중지하는 것을 원치 않는다면 eregi_replace
같은 function 을 이용하여 빈칸으로 만드는 방법도 괜찮은 방법이다.