이번주차부터 웹 해킹 기법에 대해 공부를 시작해보겠습니다.
이번주에 해볼 해킹 기법은 SQL Injection입니다.
SQL Injection
SQL이 무엇인지는 웹 개발에서 데이터베이스를 연결하며 데이터베이스를 사용하기위해 배웠습니다.
SQL은 데이터베이스를 정의할 수 있으며, 안에 있는 데이터를 조작하며 제어할 수 있습니다.
Injection은 무엇일까요? 이제부터 해킹 기법 중 이름에 Injection이 들어간다면 주입하기, 끼워넣기로 해석하면 됩니다.
즉, SQL Injection은 SQL 구문을 끼워넣는다고 보면됩니다. SQL Injection을 SQLI 로 표현하겠습니다. (너무 길어서...ㅠㅠ)
SQLI를 사용하게 되면 원래 작동해야하는 방식이 아닌 우리가 특정 문자를 끼워넣어 완전 다른 SQL구문이 실행되게 할 수 있어
올바른 데이터가 아닌 데이터베이스에서 다른 데이터를 추출할 수 있고, 인증도 우회해볼 수 있습니다.
이번 시간에는 인증 우회에 대해 집중적으로 알아보겠습니다.
웹 개발하면서 로그인 로직을 배워보았는데 식별과 인증을 동시에 하는 로직일 경우
$userId // 사용자로부터 입력받은 아이디
$userPw // 사용자로부터 입력받은 비밀번호
SELECT * FROM users id='$userid' and pw='$userPw';
위와 같이 입력받은 아이디와 비밀번호를 통해 SQL 쿼리를 만들어 둘다 만족하는 user의 데이터를 가져옵니다.
이때 사용자가 입력한 값을 통해 쿼리문을 만들기 때문에 만약 원래 입력해야하는 아이디가 아닌 SQL구문을 아이디에 입력하면 원래 우리가 작동하고 싶은 방식아닌 다른 방식으로 작동하게 될 것입니다.
실습
$enteredId = $_POST['id'];
$enteredPw = $_POST['pw'];
$hashedPassword = hash('sha256', $enteredPw);
$query = "select * from users where id='$enteredId' and password='$hashedPassword'";
$users = mysqli_query($db_conn, $query);
$user = mysqli_fetch_array($users);
if (isset($user)) {
echo "SQL = $query <br>"; // SQL 쿼리문 출력
$i = 1;
do {
$userName = $user["name"];
$userId = $user["id"];
$userPw = $user["password"];
$userEmail = $user["email"];
// 가져온 데이터 출력
echo "$i. name: $userName, id: $userId, pw: $userPw, email: $userEmail <br>";
$i++;
} while($user = mysqli_fetch_array($users));
echo '로그인 성공';
} else {
echo '로그인 실패';
}
이렇게 로그인을 하게 되면 실행되는 쿼리문과 결과가 출력되며 로그인 성공 여부를 출력하는 페이지를 만들었습니다.
패스워드가 이상한 이유는 해시때문!!!
그럼 이 페이지를 통해 SQLI 를 실제로 해보며 결과도 함께 확인 해보겠습니다.
위와 같이 입력 시 admin 정보를 출력하며 로그인 성공이 뜨게 됩니다.
왜???!!! 어떻게 되는 걸까요?
"select * from users where id='$enteredId' and password='$hashedPassword'";
// 입력값 포함한 쿼리문
"select * from users where id='admin' #' and password='아무거나'";
아이디 부분에 admin' # 을 넣어 강제로 #은 주석처리하는 문자로 뒤의 글자는 그냥 문자로 처리하여 SQL구문으로 처리하지 않기 때문에 그냥 무시하고 아이디가 admin 인 데이터를 찾습니다.
그렇기 때문에 가장 중요한 것은 우리가 임의로 ' 문자를 삽입하여 강제로 id='admin'으로 만들어 올바른 SQL구문으로 만들어 주는 것입니다.
만약 주석처리를 하지 못한다면 어떻게 할 수 있을지도 보겠습니다.
이것도 마찬가지로 비밀번호를 아무거나 입력해도 로그인 되는 것을 확인할 수 있습니다.
이 쿼리문은 어떻게 우리가 원한 admin으로 로그인 된 걸까요??
"select * from users where id='$enteredId' and password='$hashedPassword'";
// 입력값 포함한 쿼리문
"select * from users where id='admin' or '1'='1' and password='아무거나'";
일단 먼저 알아야할 것은 or 와 and 입니다. 이 두연산은 논리연산자로 참(1)과 거짓(0)을 연산하게 됩니다.
or는 앞 부분과 뒷 부분 중 하나라도 참이면 결과가 참이 반환됩니다.
and는 앞 부분과 뒷 부분 둘다 참이어야 결과가 참이 반환됩니다.
A or B
A | B | 결과 |
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
A and B
A | B | 결과 |
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
"select * from users where id='admin' or '1'='1' and password='아무거나'";
부분에서 id='admin' or '1'='1' 은 아이디가 admin인 데이터가 있기 때문에 참 '1'='1'은 두값이 같기때문에 참 이므로 결과가 참입니다.
그리고 true and password='아무거나' 를 계산하는데 앞 부분은 참이지만 password가 아무거나 입력한 값이 없기 때문에 결과는 거짓이므로 총 결과는 거짓이 됩니다.
그런데 어떻게 거짓인데 우리가 원한 admin 계정으로 로그인이 된 것일까요??
그것은 +,-,*,/ 연산자에 우선순위가 있듯이 and 와 or 도 우선순위가 있습니다. and를 우선으로 계산합니다.
그럼 다시 확인해보겠습니다.
"select * from users where id='admin' or '1'='1' and password='아무거나'" 부분이 and가 우선으로 계산되기 때문에
"select * from users where id='admin' or ('1'='1' and password='아무거나')"; 이렇게 계산한다는 의미가 됩니다.
and 먼저 계산해보면 앞 부분은 참이지만 뒷 부분은 거짓이기 때문에 총 결과는 거짓이됩니다. 그리고 or를 계산하면
아이디가 admin인 데이터가 있기때문에 참 or false가 되므로 결과는 참이됩니다. 앞 부분이 참이니 뒤에 것은 볼필요도 없지요...
그렇기 때문에 결과적으로 id가 admin인 데이터를 찾아라라는 쿼리를 만들게 됩니다.
여기도 중요한 부분이 admin' or '1'='1 마지막에 '를 안 붇혀 줌으로써 이미 서버에서 설정한 문자열을 생각하여 올바른 SQL 쿼리문을 작성하는 것이 중요합니다.
여기까지가 진짜진짜 기본이되는 SQL Injection 이었습니다.
다음에는 실제 챌린지를 풀어보며 추가로 인증우회를 알아보겠습니다.
'웹 해킹' 카테고리의 다른 글
웹 해킹 공부 일기장 2 - 과제 (0) | 2023.12.01 |
---|---|
웹 해킹 공부 일기장 2 - 1 (SQL Injection 데이터 추출) (0) | 2023.11.30 |
웹 해킹 공부 일기장 1 - 과제 (챌린지) (0) | 2023.11.27 |
웹 해킹 공부 일기장 1 - 과제 (0) | 2023.11.26 |
웹 해킹 공부 일기장 1 - 2 (인증 우회) (4) | 2023.11.24 |