본문 바로가기
Web/Webhacking.kr

Webhacking.kr Challenge old-51 문제 풀이

by jh117jh 2024. 1. 31.
728x90

 

오랜만에 webhacking.kr!

이번 문제는 admin page라 쓰여있는 것으로 보아 admin으로 로그인하는 문제인가 보다

 

 

중요 코드를 보면 id와 pw를 받아 id는 addslashes함수로 방어하고 pw는 md5로 암호화하는 걸 볼 수 있다.

그러고 id의 반환값이 있으면 문제가 풀린다.

 

처음엔 addslashes를 멀티바이트로 우회하는 문제인가 했는데 addslashes함수 이외에 다른 부분은 보이지 않아

pw 쪽으로 눈을 돌렸다.

 

pw는 md5로 암호화되며 md5는 단방향 암호화로 암호화된 내용을 다시 복호화할 수는 없다.

고로 md5 자체를 우회 할 수는 없다.

 

그런데 보통 md5함수를 사용할때 md5(string) 형식으로 하는 건 봤어도 md5(string, true)로 true 속성이 있는 것은 처음 봤다.

그래서 php md5함수에 대해 찾아본 결과,

 

 

md5에 true속성이 있으면 16자리의 raw binary 형식으로 반환한다.

 

이에 무슨 취약점이 있는지 파이썬 코드로 알아보자

 

 

파이썬으로 md5로 해시 된 값을 16진수, 바이너리 값으로 출력한 결과이다.

16진수로 된 값은 우리가 흔히 보는 md5인코딩의 모습이고

두 번째가 바이너리 형식으로 출력한 것이다.

중간중간 ",}와 같이 특수문자가 들어가 있는 것을 알 수 있는데

 

문제의 쿼리문 

select id from chall51 where id='{$input_id}' and pw='{$input_pw}에서 id와 pw부분을 둘 다 참으로 만들거나 뒤에 or을 붙여 참이 되는 값을 넣어야 쿼리문이 참을 반환할 것이다.

 

그렇다면 우리가 흔히 쓰는 pw에 ' or 1=1#을 넣으면 될 텐데 바이너리 형식으로 출력되는 값에서 ' or 1=1#이 출력되는 경우는 불가능에 가깝다.

 

그럼 우리는 최소한의 문자를 이용해 참으로 만들어야 되는데 

 

mysql에서는 0을 false로 보고 0이 아닌 모든 숫자(양수, 음수)를 true로 본다. 

 

하지만 문자열을 넣었을 때는 참으로 볼까?

 

 

신기하게도 문자열 앞에 0이 아닌 숫자가 있을 시 true를 반환한다.

0이나 숫자가 없을 시 false를 반환한다.

 

그렇다면 

 

select id from chall51 where id='admin' and pw='123' = 'asfsd'는 true일까 false일까?

 

연산자 순서에 의해 id='admin' and pw='123'가 false를 반환하고 그다음 =이 계산되어 false = false -> true가 반환된다.

 

그러면 

우리가 pw값으로 찾아야 할 것은 raw binary형식일 때 '='이 포함된 pw이다.

 

import hashlib

for i in range(0, 100000000):

    if b"'='" in hashlib.md5(str(i).encode()).digest(): # hashlib.md5(str(i).encode()).digest() == md5(str(i),true)

        print(f'check:{i}')

 

이 많은 결과 중 하나를 골라 pw로 입력하면 문제가 풀린다.

 

 

728x90