회원가입

로그인

아이디
비밀번호
ID/PW 찾기
아직 회원이 아니신가요? 회원가입 하기

웹 해킹 1/15 (system, exec, passthru 함수 사용시 주의할점)

Profile
:맥노턴
/*
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 을 이용하여 빈칸으로 만드는 방법도 괜찮은 방법이다.

Profile
:맥노턴
레벨 31
370421/
-7%
McNorton & Education Lab.
Director
댓글
0
댓글 쓰기
권한이 없습니다.

로그인

아이디
비밀번호
ID/PW 찾기
아직 회원이 아니신가요? 회원가입 하기