문제분석 & 풀이
md5 함수에 대한 언급이 있다.
md5 함수 취약점에 관한 문제인 것 같다.
password를 입력하는 칸과 코드가 있다.
코드 분석
1. 전송한 password를 이스케이프 처리 (22번줄, sqli를 방지하기 위해 사용)
2. sql 쿼리를 실행하고 결과 레코드를 $row에 저장 (23번줄)
3. 결과가 존재하면 flag를 화면에 출력 (24~26번줄)
DB에 저장된 password를 맞추면 해결된다.
그러나 DB에 저장된 password를 알 수 없고 sql 인젝션으로 DB에 있는 데이터를 알아내야한다.
코드분석 2번에서 실행하는 쿼리는 다음과 같다.
select * from admin_password where password='".md5($ps,true)."'
입력한 password를 md5로 해싱하고 DB에 row가 있는지 검색한다.
select * from admin_password where password='1'or'1'='1'
만약, md5($ps,true) 결과를 위와 같이 만들 수 있다면 쿼리는 참이 되고 flag를 획득할 수 있다. (쿼리가 참인 이유는 where문에서 or 로 조건이 2가지로 나뉘는데, 뒷 부분에서 '1'='1'이 참이어서 조건이 참이 된다.)
문제는 md5 함수 실행결과를 payload 형태로 생성하는 것이 관건이다.
힌트에서 md5 함수에 대해 언급했으므로 md5 함수에 관련된 취약점을 조사했다.
md5('value', true);
md5()는 string, boolean 타입인 2개의 인자를 가진다.
md5()의 2번째 인자는 필수가 아니고 default로 false가 들어간다.
○ 예제1 false
false가 들어가는 경우는 hex 형태의 32자리 md5 해시가 생성된다.
○ 예제2 true
true가 들어가면, 해시를 바이트 형태로 생성한다.
코드에서는 2번째 인자가 true로 사용됐고 바이트 형태로 해시가 생성된다.
그렇다면 바이트로 생성되는 해시결과를
1'or'1'='1
로 만든다면, 조건이 참이되는 쿼리가 완성되고 flag를 얻을 수 있다.
직접 md5 해싱하는 코드를 작성해서 결과가 1'or'1'='1가 출력되는 입력값을 찾고 전송해보자.