티스토리 뷰

포스팅에 앞서 내용이 틀릴 수도 있으며, 해당 부분 지적은 감사히 받겠습니다.
13번 문제이다.

필자가 가장 선호하는 sql injection문제이며 배점은 모든 old challenge 중에 가장 높은 100점이다.
문제를 풀어보자.

 

제출 값은 1일 때 result가 1, 1을 제외한 어떤 값이든 0을 반환한다.
우리는 여기서 if() 문을 사용해서 blind sql injection을 수행할 수 있다.
하지만 문제를 풀다가 여러 가지 필터링된 문자들을 찾을 수 있었다.
필터링된 문자열
and, union, ascii, 공백, limt, where, = 등등 더 많은 필터링 문자열들이 있다.
일단 간단한 쿼리를 넣어 db의 버전을 찾아보자.
쿼리 : ?no=if(len(1)in(1),1,0)

1의 길이가 1일은 참이지만 결과는 0을 출력한다.
여기서 len() 함수가 먹히지 않는다는 걸 추론할 수 있다.
그럼 length()로 바꿔보자.

정상적으로 1이 출력되었다.
따라서 mysql 환경이란 걸 알 수 있다.
mysql의 메타데이터 접근을 통해 문제를 풀어보자.
현재 작동하는 리스트에서 database()를 찾아보자.
먼저 database()의 개수이다.
쿼리 : ?no=if((select(count(database()))from(information_schema.processlist))in(1),1,0)

1개이다.
그럼 database()의 이름을 추출해보자.
쿼리 : ?no=if(ord(substr((select(database())from(information_schema.processlist)),1,1))in(1),1,0)

실수로 database()의 길이을 먼저 추출하지 않았지만, 7자리에서 더 진전이 없기에 database()의 값은 'chall13'이다.
이제 테이블 명을 추출해보자.
일단 테이블의 개수부터 추출하자.
쿼리 : ?no=if((select(count((if((select(table_schema)in(database())),table_name,null))))from(information_schema.tables))in(2),1,0)

테이블의 개수는 2개이다.
이제 각 테이블의 길이를 추출해야 한다.
하지만 우리는 limit 문자열이 필터링 당해 사용할 수 없다.
min()과 max()를 사용하여 칼럼 별 가장 작은 값, 큰 값 하나씩 출력할 수 있다.
문제에서 의도한 것처럼 개수를 2개를 주었기 때문에 우리는 모든 테이블 이름을 추출할 수 있다.
길이부터 알아보자.

쿼리 : ?no=if(length((select(min(if((select(table_schema)in(database())),table_name,null)))from(information_schema.tables)))in(13),1,0)

min()의 길이는 13이다.

쿼리 : ?no=if(length((select(max(if((select(table_schema)in(database())),table_name,null)))from(information_schema.tables)))in(4),1,0)

max()의 길이는 4이다.
길이만 가지고 우리에게 필요한 데이터를 구별할 수 없기에 둘 다 이름을 추출해보자.

min()의 값과 max()의 값 모두 출력되었다.
flag의 이름을 가진 테이블이 필요해 보이기에 flag의 칼럼만 찾는다.
flag_ab733768 칼럼의 개수를 알아보자.

2개이다.
마찬가지로 min()과 max()를 사용하여 모두 추출해보자.
길이는 귀찮으니 생략하겠다.


flag_3a55b31d와 no가 출력되었다.
flag를 필요한 데이터로 가정하겠다.
이제 flag_3a55b31d의 칼럼의 개수를 추출해보자.

2개이다.
각 길이를 알아보자.

min()의 값은 4이다.

max()의 값은 27이다.
사실 둘 다 인젝터 만들어서 찾았다.
max() 같지만 일단 둘 다 출력해보자.

min()은 flag이다.

max()값이 나왔다.
아마 이게 우리가 찾던 값 같다.
입력해보자.

문제 해결
시행착오
1. mysql 메타데이터 접근 시 우선적으로 database()를 찾아야겠다. 바로 스키마 데이터에서 테이블 이름을 불러오는 건 많은 데이터가 있을 수 있어, 값이 웹에 표시되는 게 아니라면 database()를 통한 스키마 데이터 접근이 유용하다.
2. 공백이 필터링되어 소괄호 사용 시 함수 전체를 묶어주어야 한다. ex) select(count(table_schema))
3. where절 필터링 시, if문을 통해 값을 출력시켜 select 문의 칼럼으로 값을 줄 수 있다.

   ex) select(if((select table_schema in(database())),1,0))from information_schema.tables

'SQL injection > webhacking' 카테고리의 다른 글

Webhacking 15번  (0) 2022.04.05
Webhacking 14번  (0) 2022.04.05
Webhacking 12번  (0) 2022.04.04
Webhacking 11번  (0) 2022.03.21
Webhacking 10번  (0) 2022.03.21
댓글