본문 바로가기

매일 해킹공부/웹 해킹

SQL Injection - 로그인 인증 우회

앞서 설명한 것처럼 인증 우회 기법은 계정에 올바른 정보를 입력하지 아니하고

sql 쿼리문을 조작하여 공격하고자 하는 대상의 인증을 획득하는 방법이다.

 

로그인 인증을 우회하려면 로그인 로직을 이해하는 것이 중요하다.

1. 사용자가 계정 정보를 서버에게 전달한다. (입력)

2. 서버가 DB에 sql 쿼리문을 전달하여 사용자가 입력한 계정 정보를 찾는다.(식별)

3. DB에서 조회한 값과 입력정보와 비교한다.(인증)

4. 결과값을 사용자에게 전달한다.

 

개인적으로 식별과 인증이 이해하기 조금 어려웠는데,

 

식별은 서버가 DB에 식별자를 요청하는 과정 이라고 볼 수 있다.

시스템이 사용자를 구분하기 위해 가지고 있는 유일한 값을 식별자 라고 한다. (예: ID, 주민번호, 사번 등)

 

인증은 사용자의 자격(해당 사용자가 맞는지)을 검증하는 단계라고 볼 수 있다.

 

Case별로 구분해 보자.

 

1. 식별과 인증을 같이 진행하는 경우

$sql = "select * from customer where id='$user_id' and pw='$user_pw'";

ID(식별자)와 PW(인증값)을 하나의 sql문에 포함하여 처리하는 방식으로,

ID와 PW값이 모두 일치하는 행의 존재 여부로 로그인 성공과 실패를 판단한다.

 

예시) 

위와 같은 정보를 가지고 있는 테이블이 디비에 있을때,

black 이라는 사용자가 로그인 성공을 한다고 가정 하면,

입력 받은 id 와 pw 를 둘다 만족하는 행이 존재하므로 로그인 성공이 된다.

 

우회 방법 - 주석을 사용한다.

select * from customer where id ='$id' # and pw='$pw' 

DB마다 주석이 다르지만 mysql에서는 #을 주석으로 사용한다.

참고 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=gglee0127&logNo=221271644309 

주석을 기준으로 앞문장에 오류가 없고 뒷문장은 어떤 값을 입력하던 주석처리 되므로 우회 가능하다.

 

이때, 입력값이 $id 와 $pw 자리에 들어가기 때문에 주석을 사용하기 위해서는 ' # 까지 아이디 부분에 입력해야한다.

select * from customer where id ='black' #' and pw ='$user_pw' 으로 작성되어 # 뒤로 주석 처리되어

비밀번호를 아무거나 입력하여도 다음과 같이 성공한 것을 확인할 수 있다.

 

2. 식별과 인증을 따로 진행하는 경우

$sql = "select pw from customer where id = '$user_id'";

ID를 기준으로 customer table내의 pw값을 조회하고 사용자가 입력한 값과 비교하여 일치/불일치를 판단한다.

 

예시)

DB에서 조회한 black이라는 사용자의 pw 값과 입력한 pw 값을 비교하여 일치하면 로그인 성공이 된다.

 

우회방법 - union 사용

union은 2개 이상의 select 문을 결합하여 결과물을 보여준다.

보통  select 문을 table내에 있는 데이터를 확인할 때 많이 사용하는데,

table명을 입력하지 않고 값만 입력할 경우, 입력한 값을 출력한다.

이 부분을 활용하여 union과 함께 사용하면 원하는 값을 출력할 수 있다.

존재하지 않는 아이디를 입력후, 지정하고자 하는 비밀번호를 입력하면 위와 같은 결과를 얻을 수 있다.

이때, select pw from customer where id = 'x' union select 'name'; 으로 작성되어

pw가 name으로 출력 되기 때문에 비밀번호에는 name 이라고 입력해야 한다.

다른 비밀번호를 입력하고 싶다면 밑줄친 부분에 원하는 글자로 넣고 비밀번호도 동일하게 입려하면 된다.

 

3. 식별과 인증을 같이 진행하는 경우 (with hash)

"select * from customer where id = '$user_id' and hash_pw = sha2('$user_pw', 256)";

이 방법은 비밀번호 부분이 hash 함수에 의하여 얻어지는 해시값으로 변경되는것 외에는 1번과 크게 다른 점이 없다.

우회방법 역시 1번과 동일하다.

 

4. 식별과 인증을 따로 진행하는 경우 (with hash)

$sql = "select hash_pw from customer where id = '$user_id'";

$result = mysqli_query($con, $sql);
$row = mysqli_fetch_array($result);

    if($row[0]==hash("sha256",$user_pw)){

이 방법은 비밀번호 부분이 hash 함수에 의하여 얻어지는 해시값으로 변경되는것 외에는 2번과 크게 다른 점이 없다.

(단, 이 경우에는 아이디 부분에는 값은 hash값을, 비밀번호는 hash처리 되지 않은 값으로 입력해야한다.)

 

5. 식별과 인증을 같이 진행하는 경우 (with 개행) 

$sql = "select * from customer where id = '$user_id'
                and pw = '$user_pw'";

이 경우는 1번과 인증/식별 방법이 1번과 다르지 않다.

다만, 우회방법에서 sql문에서 개행(enter)가 있으면 #이 통하지 않는다.

이유는 한줄 주석이기 때문이다. 

그러면 여러줄을 주석할 수 있은 /* */ 사용하면 되는것 아닌가? 라고 생각할 수 있겠지만 안된다.

이유는 데이터를 입력할 수 있는 위치가 정해져 있기 때문이다.

 

우회방법 - 논리 연산자 사용

논리 연산자는 and 연산자가 or 연산자 보다 우선순위가 높다.

흔히 or '1'='1를 사용하는데 이를 이용하여 완성해 보면 다음과 같다.

where id='$id' or '1'='1' and pw='$pw' 의 형태로 작성을 하면

where id='$id' or ('1'='1' and pw='$pw')  >>>  where id='$user_d' or 거짓이 된다.

or 조건은 둘중에 하나만 참이 되면 되므로 id 만 정상적으로 입력한다면 결과가 출력된다.

select * from customer where id = 'black' or '1'='1'

and pw = '$user_pw'; 로 비밀번호를 다르게 입력하여도 우회가 가능하다.

참고 : https://hanuscrypto.tistory.com/entry/SQL-Injection-%EB%A1%9C%EA%B7%B8%EC%9D%B8-Case-%EB%B3%84-%EC%9D%B8%EC%A6%9D-%EC%9A%B0%ED%9A%8C?category=513492