반응형

* 매직해시(Magic Hashes)란 ?

 - 비교 연산을 할 때 Type Juggling을 이용하여 서로 다른 값이 같은 값으로 인식되도록 하는 특수한 동작

 - 항상 가능한 것이 아니라 특수한 경우('0e'로 시작하는 문자열일 때)에 가능

 - 사전 지식으로 Type Juggling과 특수 숫자포맷에 대해 이야기하겠다.


* Type Juggling이란? 

 - PHP는 변수 정의에 명백한 타입 선언을 요구하지 않는다. 

 - 변수 타입은 그 변수가 사용되는 상황에 맞게 결정된다. (=auto casting)

 - 만약 문자열 값이 $var에 할당되었다면, $var는 string 타입이다.

 - 만약 숫자 값이 $var에 할당되었다면, $var는 integer 타입이다.

(ex)

<?php

$foo = "0"; // $foo is string (ASCII 48)
$foo += 2; // $foo is now an integer (2)
$foo = $foo + 1.3; // $foo is now a float (3.3)
?>


(참고)Type Casting?

 - Type juggling과 비슷한 개념

 - 변수 타입을 강제적으로 바꿔주는 것

(ex)

$foo = '1';
echo gettype($foo); // outputs 'string'
settype($foo, 'integer');
echo gettype($foo); // outputs 'integer'



* 특수 숫자포맷

 - 16진수 : 0xC (10진수 값으로 12)

 - 8진수 : 0o11 (10진수 값으로 9)

 - 지수 : 3e2 (10진수 값으로 3 * 10 ^ 2 = 300)


* 매직해시 

  위에서 말한 '0e'로 시작하는 문자열이란 특수 숫자포맷에서 본 지수 형태와 동일하다. 즉, '0e'로 시작하는 문자열에 뒤에가 모두 숫자일 경우에는 PHP 상에서 float 형태로 인식한다는 것이다.


1) 0e 뒤에 모두 숫자일 경우




 -> string 형태로 지정을 해주었지만 PHP는 Type juggling을 통해 float 형태로 바꾼 뒤 비교를 진행하였고 

0e1234 = 0 * 10 ^ 1234 = 0

0e5678 = 0 * 10 ^ 5678 = 0

결국 PHP는 둘다 0이라고 생각하여 비교를 했을 때 같다고 true값을 반환

(type casting이 된 것이 아니므로 연산 후에도 각 변수의 타입은 string으로 유지)


2) 0e 뒤에 문자가 들어갈 경우



 -> 위의 경우와 달리 $ex1 변수에 a를 하나 추가하였다. 이 경우 PHP는 Type Juggling을 하여도 다른 타입으로 변경할 수 없고 string으로만 남을 수 밖에 없다. 따라서 두 문자열의 비교 결과 달라서 false를 출력하는 것이다.


* 대처방법

1) 암호화 함수 이용 ex) md5(), sha1() 등

 - 이 경우 해커가 매직해시를 노리고 '0e1234' 식으로 입력한다고 하더라도 암호화로 인해 방어가 가능

 - 하지만 이 암호화를 통한 결과가 '0e'로 시작하고 뒤가 모두 숫자일 경우가 발견됨

md5 : 240610708 => 0e462097431906509019562988736854

sha1 : 10932435112 => 0e07766915004133176347055865026311692244

(더 많은 암호화 기법에 따른 매직 값을 알고 싶을 경우 https://www.whitehatsec.com/blog/magic-hashes/ 참고)


2) 더 발전된 암호호 함수 사용

 - 암호화 결과물의 시작이 $이나 *인 함수 사용

 - PHP 5.5 버전 이후에서는 password_hash 함수를 제공한다. -> 결과값이 $로 시작할 뿐더러 매번 암호화할 때마다 값이 달라진다.


3) 형변환하지 않는 비교 (===) 사용

 - 비교 연산자를 == 대신 ===를 사용한다면 Type Juggling을 진행하지 않아 매직해시는 통하지 않는다.


* 이를 이용한 문제 풀이 (비박스 환경의 SQL Injection(Login Form/User)

소스코드

 - form이 설정되어 있다면 login과 password를 가져오고 password의 경우 sha1 암호화를 거친 결과를 $password 변수에 저장한다.

 - $login 변수값 만으로 데이터를 가져와 $sql 변수에 넣는다.


 - 비교문장에서 sha1으로 암호화된 값 $password와 DB 상에 존재하는 login과 관련된 패스워드 $row['password']를 ==를 통해 비교한다.

 - 따라서 DB 상의 password와 입력한 password의 hash값이 비교 결과 같다면 풀리는 것이다. 만약 매직해시를 이용하여 sha1으로 암호화했을 때 '0e+숫자'형태가 되는 매직 숫자를 넣어주고 login에 해당하는 password가 0e+숫자이거나 0이거나 그에 해당하는 값이면 로그인이 된다.


* 공격 순서

1. '를 입력해보고 SQL Injection 취약점이 존재하는지 확인

2. ' union select 1# -> ' union select 1,2# -> ... -> ' union select 1,2,3,4,5,6,7,8,9#을 진행하여 컬럼 수가 9인 것을 확인

3. password에는 sha1 암호화의 결과가 0e+숫자 형태로 나오는 10932435112 을 입력해주고 union 뒤의 select 문에서 password에 해당하는 칼럼을 찾는다. (0을 넣어가면서)

4. 3번째에 0을 넣었을 때 로그인 되는 것을 보아 3번째 컬럼이 패스워드 관련 컬럼임을 알 수 있다. 

-----------------------------------------------------------------------------------------

참조 ) 

- Type Juggling (http://designmywebpage.blogspot.kr/2013/06/type-juggling-and-type-casting.html)

https://blog.lael.be/post/1238

- https://www.whitehatsec.com/blog/magic-hashes/

- Password_hash (http://webinformation.tistory.com/82)

반응형

'Hacking > Web' 카테고리의 다른 글

A7 - 기능 수준의 접근 통제 누락  (0) 2017.02.18
A6. 민감 데이터 노출  (0) 2017.02.16
A3. 크로스 사이트 스크립팅  (0) 2017.02.09
addslashes(), mysql_real_escape_string() 우회  (9) 2017.02.01
A1-injection  (0) 2017.02.01
블로그 이미지

rootable

,