문제에 접속하니 Admin page 가 나타났다.
auth 버튼을 눌러보니 "access denied" 가 뜨는 것을 확인 할 수 있다.
이번문제는 admin page에서 admin이라는 것을 버튼을 눌러서 인증을 해내는 것이 목표가 될 것 같다.
다음으로 소스를 봐보자.
소스를 간단히 분석하면 다음과 같다.
1. "val" 라는 파라미터의 값을 받고 $go 변수에 저장 후 5번줄을 통해 그 값을 정규표현식을 이용하여 필터링 검증을 받는다. (2,5번줄)
2. rand(1,5)를 통해 1~5 까지 숫자중 랜덤값을 받고 if문으로 들어간다. (7~22번줄)
3. 들어간 if문의 sql 쿼리를 실행하고 그 결과(레코드)를 $data 변수에 넣는다. (8~22번줄)
4. $data[0] 즉, 결과로 받은 레코드의 lv 속성의 값이 2이면 문제가 해결된다. (28번줄)
우선 먼저 "go" 변수에 들어가면 안되는 값을 확인해보자.
[ 2 , - , + , from , _ , = , 공백 , * , / ]
5번줄을 보면 알 수 있듯이 위와 같은 값들이 들어가면 안된다. (정규표현식에 대해서 잘모르는 독자라면 공부하고 오길 바란다.)
필터링 이후를 보면 7번줄에서 랜덤값을 받기 때문에 어떤 쿼리를 실행할 지는 예측할 수 없음으로 아무거나 하나 잡고 sqli를 시도해보아야겠다.
위 쿼리를 실행한다고 가정하고 sqli 페이로드를 짜볼 것인데 union 과 select를 필터링하지 않기 때문에
이번 문제의 경우 union sqli 를 이용하여 문제를 쉽게 해결할 수 있을 것 같다!
위와 같이 공격 페이로드를 짜보았다. 이것을 이해하기 위해서는 union 과 select 의 개념에 대한 이해가 필요한데 기본적인 것은
각자 공부해오길 바란다.
필자가 설명할 내용은 select(char(50)) 부분인데
필터링에 의해 "2" 라는 값을 직접 사용할 수가 없기 때문에 char() 함수를 이용하여 "2"라는 값을 우회하여 표현하였다.
char() 함수안이 50인 이유는 "2"는 숫자(10진수)로 표현하면 50이기 때문이다. (아스키코드 표 참고)
그렇다면 select(char(50)) == select(2) 라는 의미라는 것인데 select(2)는 무슨 의미일까?
우선 union을 먼저 알아야 하는데 union의 경우, 간단히 말해서 두 개의 select 문의 레코드 결과 값을 하나의 테이블로 합치는 것을 의미한다고 생각하면 편할 것 같다.
__
lv ==> 속성
ㅡ
1
2
3
위와 같은 테이블이 있다고 가정하자. (실제 문제의 테이블은 이렇게 구성되어 있지 않고 설명을 위한 예제이다.)
페이로드를 보면 union을 기준으로 두 개의 select문이 있고 첫 번째 select 문의 경우 lv=10 인 값을 select하고 있다.
그러나 위와 같은 테이블이라면 lv=10 인 값은 없기 때문에 결과로 반환되는 레코드는 없을 것이다.
__
2 ==> 속성
ㅡ
2
이제 두 번째 select문을 보자. select(2)인데 select(2)는 위와 같이 속성, 값 모두 2인 값을 결과로 가져온다.
결과적으로 두개의 select문 결과를 합치면 다음과 같은 테이블이 결과로 완성된다.
__
lv ==> 속성
ㅡ
2
결과적으로 위와 같이 결과값이 반환되면서 $data[0]의 값은 2가 들어갈 것(23번줄)이고 결국 문제가 클리어 될 것이다!
이제 url 주소창을 이용하여 문제를 해결해보자.
클리어!! (한번에 해결이 안되고 nice try!가 뜰수도 있는데 그것은 처음에도 말했지만 7번줄의 랜덤값에 의해 우리가 의도하지 않은 sql 쿼리가 실행되어 오류가 발생했기 때문이다. 여러 번 시도하면 문제가 해결될 것이다.)
* 추가 : 사실 필자는 처음에 풀때 union sqli 가 아니라 "2"를 십진수로 바꾼 "0D50"을 값으로 넣어서 풀려고 했지만 풀리지 않았고 삽질을 했다. 왜 안 풀리는지 확인해보니 아마도 DB에 lv가 "2"인 데이터는 존재하지 않아서 풀리지 않았던 것 같다. 혹시 나처럼 삽질한 사람들은 참고바란다!