UNION [2]

DATE : 2023/11/29

UNION [1]에 이어서 로그인 우회를 시도해보자!!

우리가 UNION 연산자를 이용한 Query를 입력했다고 상상해보면

ID : hanhxx' union select 'mario1','mario2
PASS : ???

맨 앞에 작성한 "hanhxx" 라는 값은 첫 번째 SELECT문으로 들어가게 된다.

그렇게 되면 hanhxx의 정보와 mario1, mario2가 합쳐진 결과가 만들어 지게 되고

if($db_pass == $user_pass) { ... } else { ... }

비밀번호를 비교하는 과정에서는 먼저 수행되어 결과를 도출한 hanhxx의 비밀번호로

비교 연산이 실행될 것이다.

이는 결국 hanhxx의 비밀번호를 오류 없이 입력했을 경우,

hanhxx 계정으로 로그인하는 것일 뿐 우회를 위한 Query로 사용할 수는 없다.

그.래.서

비밀번호를 비교하는 과정에서 ROW가 여러 개면 맨 위에 있는 ROW의 비밀번호로만

비교 연산에 사용되기 때문에

첫 번째 SELECT문의 ID 값을 비워버리고 (= 거슬리는 첫 번째 row 없애자!)

UNION으로 우리가 원하는 값을 비밀번호 연산 과정에서 사용하도록 만들자! 는 것이다. 💡

현재 사용자가 hanhxx라고 할 때, hanhxx는 mario 계정으로 로그인 시도를 하는 상황이라 생각해보자.

자신의 계정이 아니기 때문에 mario의 비밀번호를 모르는 hanhxx는 로그인을 우회할 필요가 있어 보인다.

ID : ' union select 'mario','hanhxx1234
PASS : hanhxx1234

고민 끝에 입력한 ID & PASSWORD는 위와 같았다.

식별과 인증이 분리되어 실행되는 로직이기 때문에, 우선 hanhxx가 입력한 ID로 SELECT문이 실행되었다.

SELECT문의 결과를 확인해보면, hanhxx가 입력한 값만 그대로 나오는 걸 볼 수 있다!!

이는 Query의 결과가 하나이기 때문에 hanhxx가 입력한 자신의 비밀번호가

결과로 반환 된 ROW의 비밀번호로 들어가게 되고

동시에 로그인할 때 입력한 비밀번호 또한 hanhxx 자신의 것이기 때문에

결국 hanhxx가 입력한 비밀번호와 Query 결과로 얻어온 비밀번호가 일치하게 됨으로써

로그인에 성공할 수 있게 된다.

즉, 자신의 비밀번호를 이용해 mario의 계정으로 로그인 우회를 성공한 것이다!


이렇게 해서 식별과 인증을 따로 실행하는 로그인 로직에서의 우회 방법을 살펴보았다.

전체적인 과정을 정리하면 다음과 같다 :

(1) union operator를 사용해 총 2개의 SELECT문이 실행될 수 있게 구성한다.

(2) UNION 앞에 작성된 select문의 결과가 나오지 않도록 id를 공백 처리한다.

(3) UNION 뒤에 작성된 select문에는 자신이 로그인하고자 하는 id & 사용할password를 입력

(4) (3)에서 사용한 password를 로그인 시 입력한다.

or, and 연산자를 이용한 경우의 Query 보다는 좀 더 어려울 수 있지만

UNION 연산자를 활용하는 방법이 있다는 걸 확실하게 얻어가자 🤗

Last updated