들어가니 어드민 페이지가 보이고, 밑에 인증 버튼이 있네요. 클릭하니 Access_Denied!
문구만 뜹니다. 소스 코드를 확인해 봅시다.
PHP 소스 코드와 SQL 쿼리문이 보이네요. 이번 문제는 SQL Injection 문제인 것 같습니다. GET 방식으로 val
파라미터에서 값을 얻어온 뒤 preg_match
함수로 정규식을 이용해 필터링을 하네요. 그 아래에선 랜덤으로 5가지의 쿼리문 중 하나를 선택해 쿼리를 보내고, 결과가 2이면 문제가 풀리는 것 같군요.
바로 시도해볼 수 있는 방법으로 val
파라미터에 2를 넣어볼 수 있지만, 필터링에 걸리기 때문에 문제가 발생합니다. 그래서 이번엔 사칙연산 기호 중 필터링에 걸리지 않는 % 연산자를 이용해서 5 % 3 = 2인 점을 이용해 간접적으로 2가 만들어지도록 5%3
을 넣어보았습니다.
그랬더니 이번엔 query error
가 뜨네요. 이는 애초에 DB에 처음부터 lv
가 2인 값이 없다는 의미가 됩니다. 따라서 DB에서 가져오는 것이 아닌, 직접 2라는 결과가 나오도록 union
연산자를 이용해 보았습니다.
select lv from chall7 where lv=(3) union select 2
이런 식으로 쿼리문을 구성하게 된다면 앞에는 lv
가 3인 경우가 없으므로 빈 결과가 나오게 되고, 최종적으로 뒤의 2가 결과로 나오게 될 것입니다. 하지만 필터링이 있어 위 쿼리문을 그대로 사용할 수는 없습니다.
2의 경우 아까와 마찬가지로 % 연산자를 사용해 우회하고, 공백의 경우 괄호를 넣어 대신할 수 있습니다. 마지막으로 # 주석 처리를 이용해 뒷부분의 쓸데없는 부분은 버릴 수 있죠. 이를 토대로 공격 페이로드를 만들어 보면 3)union(select(5%3))%23
이 됩니다. (#의 경우 URL 인코딩을 이용해 %23으로 넣어야 들어갑니다.)
select lv from chall7 where lv=(3)union(select(5%3))#)
페이로드가 들어가면 이런 식으로 쿼리문이 만들어지게 되면서 2가 결과로 나오게 될 것입니다.
5개의 쿼리문 중 랜덤으로 선택되기 때문에 괄호가 하나만 있는 쿼리문이 선택될 때까지 몇 번 새로고침을 하다 보면 이렇게 문제가 풀리는 것을 볼 수 있습니다!