728x90
반응형

 선행 학습 필요 개념

Order by 절

SELECT문으로 검색된 데이터를 오름차순(ASC)이나 내림차순(DESC)으로 정렬시킬 때 사용한다.

Default 값은 Ascending(오름차순)으로 ASC는 생략해도 되며, 문자는 알파벳 순서로 출력된다.

ORDER BY절에 선택된 컬럼이 여러 개일 경우 앞(왼쪽)에 정의된 컬럼을 기준으로 먼저 분류한 후, 이후에 나열된 순서대로 분류한다.

 

Order by가 SQL Injection에서 쓰이는 경우는 컬럼(속성)의 수를 확인하기 위함이다.

예를 들어 컬럼이 두 개인 테이블에 쿼리문을 확인해보자

1) select * from table_name where name="a" order by 2; (정상 출력)

2) select * from table_name where name="a" order by 3; (에러 출력)

 

공격요소

웹 페이지 게시판에서 정렬기능을 이용할 수 있는 부분이 있다.

위에 GET요청을 보게되면 hostname 기준으로 정렬을 시도하는 것을 확인할 수 있다.

 

공격 과정

1) 컬럼(속성) 수 체크

order by=숫자 를 입력해가면서 컬럼갯수를 확인한다.

 

2) 쿼리 입력을 통한 참, 거짓 판별

order by 절 이후 order by()처럼 괄호안에 서브쿼리 입력이 가능하지만, 단일행 결과만 입력이 가능하다.

예) select * from table_name order by (select 1) (정상 출력)

예) select * from table_name order by (select * from table_name) (에러 출력)

이러한 특징을 이용하여 Blind SQL Injection 시도 가능하다.

True 결과값 order by 내 서브 쿼리가 true가 되면 다중 쿼리를 출력하게 되므로, 해당 order by절은 에러를 발생하게 된다.

예) select * from table_name order by (select name from table_name where 1=1); (에러 출력)

False 결과값 리턴 (mysql에서 empty는 단일행으로 취급) order by 내 서브 쿼리가 false가 되면 단일 쿼리를 출력하게 되므로, 해당 order by 절은 정상적으로 출력하게 된다.

예) select * from table_name order by (select name from table_name where 1=2); (정상 출력)

 

3) Blind SQL Injection을 통한 데이터 추출

테이블명, 컬럼명을 알고 있는 상황에서의 데이터 추출 쿼리

첫 번째 글자가 b라고 가정하면

select * from table_name order by (select 1 from table_name where (substring((select name from table_name limit 1),1,1)='a'));
--> 에러 미발생

select * from table_name order by (select 1 from table_name where (substring((select name from table_name limit 1),1,1)='b'));

--> 에러 발생( ERROR 1242 (21000): Subquery returns more than 1 row )

 

CASE WHEN 조건문

사용법

CASE WHEN 조건절 THEN 참일 때 값 ELSE 거짓일 때 값 END 컬럼명

 

LIKE 연산자

SQL LIKE 연산자는 WHERE 절 안에서 쓰이는데, 열에서 어떤 특정한 패턴에 부합하는 부분을 찾으려 할 때 쓴다.

LIKE 연산자는 두 가지의 와일드카드 문자를 쓴다

1) % : 0, 1, 혹은 하나 이상의 char

2) _ : 한개의 char

사용법 (AND, OR를 사용할 수 있다)

SELECT 컬럼 FROM 테이블명 WHERE 컬럼 LIKE 패턴;

 

 

※ WebGoat SQL Injection(mitigation) 문제

이 지정에서 ORDER BY 필드를 통해 SQL 인젝션을 수행하십시오. webgoat-prd 서버의 IP 주소를 찾으십시오. 완전한 IP 주소가 너무 오래 걸릴 수 있다고 추측하여 마지막 부분을 알려줍니다 : xxx.130.219.202

Hostname을 클릭하게 되면 GET 요청에 column에 hostname이 담겨 전송되는 것을 확인할 수 있다.

ORDER BY에서 CASE문과 서브쿼리를 이용하여 조건 검사를 해보자.

우선 서브쿼리를 통해 조건문이 잘 동작하는 지 확인해보자

URL에 servers?column을 통해 테이블 명은 servers로 추축할 수 있으며, 버프 스위트를 리피터 기능을 이용해보자.

select Hostname, IP, MAC, Status, Description
from servers
where ??
order by (case when length('tset')=4 then id else ip end)

해당 쿼리문을 url에 넣기 전에 띄어쓰기->+ , =->%3d로 변환 후 실행해보자

test의 길이가 4이면 id 값 기준으로 정렬되게 하고, 틀리면 ip를 기준으로 정렬하게 하였으며 결과 값은 참이기 때문에 정상적으로 id를 기준으로 정렬되는 것을 확인할 수 있다.

 

이제 exists문을 사용해보도록 하자. select * from에서 레코드 값이 있다면 exists는 참이 된다. 어떠한 값도 가져오지 못하면 거짓이 된다. 우리는 ip를 확인해야되는 서버 webgoat-prd가 존재하는지 확인해보자.

id 값으로 정렬되는 것을 보니 webgoat-prd가 존재하는 것을 알 수 있다.

 

다음은 webgoat-prd의 ip를 확인하기 위해 substr함수를 이용하는 쿼리를 작성해본다. ip값의 1번째 글자가 1이면 id로 정렬 1이 아니면 ip로 정렬하게 된다.

쿼리 결과 id를 기준으로 정렬된 것으로 보아 ip의 첫번째 글자는 1로 확인할 수 있었다.

 

이제 Injection을 수행할 파이썬 코드를 작성해 보자

해당 코드의 결과는 다음과 같다.

이제 webgoat-prd의 ip를 완성해 제출해보도록 하자.

그 외의 방법으로는 서브쿼리를 이용해 webgoat-prd의 IP 주소를 가져오고, LIKE를 활용하여 한 글자씩 알아낸다.

쿼리문 : case when (select ip from servers where hostname='webgoat-prd' ) like '2%25' then hostname else id end

LIKE로 검사한 결과 참인 경우 LIST가 hostname으로 기준으로 정렬되고, 거짓인 경우 id를 기준으로 정렬된다.

자동화를 위한 파이썬 코드는 다음과 같다.

728x90
반응형

+ Recent posts