취약점 분석 2023-03-28
'22 12월 해킹 연구팀 TEAM82에서 유명 WAF(Web Application Firewall)에서 JSON을 이용하여 Injection이 가능하다는 것을 확인하였다.
WAF는 SQL Injection 공격을 쉽게 탐지하지만 SQL 구문에 JSON을 포함하게 되면 우회할 수 있게 된다.
Team82 연구에 따르면 Palo Alto Networks, Amazon Web Services, Cloudflare, F5 및 Imperva의 5개 주요 글로벌 공급업체에서 판매한 WAF에서 JSON Injection공격에 취약한 것으로 알려졌다.
해당 취약점은 현재는 패치 된 상태이다.
공격자들은 JSON Injection을 통해 WAF를 우회하고 추가 취약점을 이용해 데이터를 유출할 수 있다. 우리는 작년에 해당 기사를 접하고 나서 자사 WAF 대상으로 테스트한 결과를 공개하기로 하였다.
주요 데이터 베이스에서는 10년이 넘는 기간 동안 JSON을 지원했다. JSON은 데이터 저장 및 전송의 주요 형식 중 하나이다. SQL에서도 다른 어플리케이션에서 데이터와 상호 작용을 하기위해서는 JSON 지원이 필요하다.
현재 모든 주요 관계형 데이터 베이스에는 JSON 구문을 지원한다. 관계형 데이터 베이스에는 MSSQL, PostgreSQL, MySQL 등이 포함된다.
모든 버전의 데이터 베이스에서 사용가능한 것은 아니고 아래의 표에 표기된 버전 이상의 데이터 베이스에서 JSON기능이 지원된다.
|
JSON Support |
Enabled by Default |
Year Json Added |
Json Parser Used |
PostgreSQL |
YES |
YES |
v9.2 (2012) |
Proprietary |
MySQL |
YES |
YES |
v5.7.8 (2015) |
Proprietary |
SQLite |
YES |
YES |
v3.38.0(2022) |
Proprietary |
SQL Server |
YES |
YES |
SQL Server (2016) |
Proprietary |
SQL에서 JSON을 사용하면 어플리케이션이 SQL API 내에서 데이터를 가져오고, 데이터 베이스 내에서여러 소스를 결합하는 등 다양한 작업을 수행하고 JSON 형식으로 변환이 가능하다.
CREATE TABLE users(
id integer AUTO_INCREMENT primary key,
user VARCHAR(200),
password VARCHAR(200),
info JSON
);
Insert into users(user, password, info) values('admin', 'admin', '{"age":44,"name":"aaa”}');
데이터 또한 JSON형식으로 name : value 형식으로 입력하였다.
PostgreSQL: '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb Is the left JSON contained in the right one? True.SQLite: '{"a":2,"c":[4,5,{"f":7}]}' -> '$.c[2].f' = 7 Does the extracted value of this JSON equals 7? True.MySQL: JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name') = 'Aztalan' Does the extracted value of this JSON equals to ‘Aztalan’? True.
그럼 각 데이터 베이스에 해당 공격 쿼리를 전송하면 공격이 가능한가?
그렇지 않다. 해당 공격을 성공하기 위해서는 WAF가 탐지하지 못하는 SQL 구문을 찾아야한다.
즉, WAF에서 탐지 못하는 SQL 구문이 존재할 경우 취약 구문에 JSON 구문을 붙여 연달아 구문을 전송 하여 WAF를 우회하여 명령을 전달하는 방식인 것이다.
좀 더 쉽게 예를 들어 설명해 보겠다.
우리가 SQL Injection으로 알고 사용하고 있는 공격 구문인 1’ or ‘1’=’1 --을 입력했을 때 일반적인 WAF에서는 아래 그림과 같이 차단한다.
' or JSON_EXTRACT('{"id": 1, "user": "admin"}', '$.user')' or JSON_CONTAINS(info,'$.age')' and JSON_ARRAY(name, age, email)