혜랑's STORY

[2020-2학기 웹] : SQL Injection - ­(GET/Search) 본문

2020 SISS 21기 활동/2학기 WEB

[2020-2학기 웹] : SQL Injection - ­(GET/Search)

hyerang0125 2020. 9. 26. 22:23

1. SQL 개념이해

- SQL(Structed Query Language)은 구조화된 질의 언어라는 의미를 가지고 있는 일종의 프로그래밍 언어로써 관계형데이터베이스를 제어하기 위해 이용된다. 이는 크게 세 종류로 구분할 수 있으며, 데이터와 그 구조를 정의하는 DDL(Data Definition Language), 데이터의 검색과 그것의 수정을 위한 DML(Data Manipulation Language), 데이터베이스 사용자의 권한을 정의하는 DCL(Data Control Language)로 나뉘어진다.

- 쿼리(Query, 질의)

 사용자가 데이터베이스 시스템에 대하여 데이터베이스를 새로 정의하거나 변경하고, 데이터를 검색, 갱신하는 등의 다양한
요구를 질의하는 것을 말한다. 정보검색 시스템에서는 입력해 넣은 검색어를 의미하기도 한다.

- 데이터 정의 언어(DDL, Data Definition Language) : 데이터베이스 '스키마'에 관련된 조작으로 테이블과 뷰, 그 외의 오브젝트를 생성하거나 데이터베이스의 기본 설정을 정의하기 위한 기능을 갖는 SQL 명령어

명령어 기능
CREATE 새로운 데이터베이스, 테이블의 생성
[사용법] CREATE DATABASE 데이터베이스명
[사용법] CREATE TABLE 테이블명(필드명 자료형, 필드명 자료형...)
ALTER 기존 테이블 구조의 변경
[사용법] ALTER TABLE 테이블명 ADD [COLUMNS} 필드명 자료형 ; 필드 추가
[사용법] ALTER TABLE 테이블명 CHANGE [COLUMNS} 기존필드명 새필드명 자료형 ; 필드 수정
[사용법] ALTER TABLE 테이블명 DROP [COLUMNS} 필드명 자료형 ; 필드 삭제
DROP 기존 데이터베이스, 테이블의 삭제
[사용법] DROP DATABASE 데이터베이스명
[사용법] DROP TABLE 테이블명

- 데이터 조작 언어(Data Manipulation LAnguage) : 테이블 데이터에 엑세스 하기 위한 목적으로 데이터를 추가, 생신, 제거하기 위한 기능을 갖는 SQL 명령어

명령어 기능
INSERT 새로운 데이터의 삽입(입력)
[사용법] INSERT [INTO] 테이블명 [(필드명, 필드명, ...)] VALUES (필드값, 필드값, ...)
UPDATE 기존 데이터의 수정(갱신)
[사용법] UPDATE 테이블명 SET 필드명=필드값[필드명 = 필드값, ...] [WHERE 검색조건]
DELETE 기존 데이터의 삭제
[사용법] DELETE FROM 테이블명 [WHERE 검색조건]
SELECT 데이터의 검색
[사용법] SELECT [DISTINCT] 필드명 FROM 테이블명 [WHERE 검색조건][ORDER BY 필드명 [ASC or DESC][GROUP BY 필드면[,필드명, ...]][HAVING 검색조건]

 

2. SQL Injection이란?

 SQL 인젝션은 코드 인젝션의 한 기법으로 클라이언트의 입력값을 조작하여 서버의 데이터베이스를 공격할 수 있는 공격방식을 말한다. 주로 사용자가 입력한 데이터를 제대로 필터링, 이스케이핑하지 못했을 경우에 발생한다. 

- 공격 종류 및 방법

    ① Error based SQL Injection (논리적 에러를 이용한 SQL Injection)

    ② Union based SQL Injection (Union 명령어를 이용한 SQL Injection)

    ③ Blind SQL Injection (Boolean based SQL / Time based SQL)

    ④ Stored Procedure SQL Injection (저장된 프로시저에서의 SQL Injection)

    ⑤ Mass SQL Injection (다량의 SQL Injection)

- 대응방안

① 사용자 입력 값에 대한 검증; 공백으로 치환하지 않는다. (ex. 공격자가SESELECTLECT라고 입력 시 중간의 SELECT가 공백으로 치환이 되면 SELECT라는 키워드가 완성된다. 공백 대신 공격 키워드와는 의미 없는 단어로 치환되어야 한다.)

② Prepared Statement 구문 사용; 사용자의 입력 값이 데이터베이스의 파라미터로 들어가기 전에 DBMS가 미리 컴파일하여 실행하지 않고 대기한다. 그 후 사용자의 입력 값을 문자열로 인식하게 하여 공격쿼리가 들어간다고 하더라도, 사용자의 입력은 이미 의미없는 단순 문자열이기 떄문에 전체 쿼리문도 공격자의 의도대로 작동하지 않는다.

③ Error Message 노출 금지

④ 웹 방화벽 사용

 

3. 실습 (모든 난이도 low)

# MISSION. 영화 정보가 들어있는 데이터베이스에 저장된 사용자들의 아이디와 비밀번호를 획득하기

주어진 미션을 수행할 화면

(1)  SQL Injection이 통하는지 아닌지 확인해보고, SQL Injection이 된다면 데이터베이스의 서버 종류가 무엇인지 확인하기

아래 코드를 통하여 페이지 소스코드가 "/bWAPP/sqli_1.php" 에 저장되어 있다는 사실을 알 수 있다.

 sqli_1.php에 저장되어 있는 " SELECT * FROM movies WHERE tilte LIKE '%" . sqli($title) . "%' "가 서버에 질의하는 쿼리에 해당한다. 이때 ' % " . sqli($title) ." '는 " . sqli($title) ."을 포함하는 단어를 뜻한다. 

데이터베이스에서는 작은따옴표(')로 문자열을 구분한다. 따라서 '만 입력했을 경우 쿼리 문법에 오류가 생기면서 오류 메시지가 출력되고, 그 메시지를 통하여 데이터베이스의 서버를 알아낼 수 있다.

데이터베이스의 서버를 알아내는 화면

이 활동을 통해 데이터베이스의 서버가 MySQL이라는 것을 알아낼 수 있었다.

(2) 모든 영화자료를 출력하기

 모든 영화자료를 출력하기 위해서는 SELECT문의 조건을 참으로 만들면 된다. 즉, SELECT * FROM movies WHERE tilte LIKE 'OR 1=1--' 를 입력하면 모든 영화자료를 출력할 수 있다.

모든 영화자료를 출력하기

(3) 데이터베이스에서 호출하는 칼럼 수가 몇 개인지 알아내기

이 문제를 해결하기 위해서는 UNION based SQL Injection을 이용하면 된다. UNION 사용시 주의점으로 "칼럼명이 같아야한다. (같지 않을 경우 AS를 사용하여 같게 만들어주면 된다.)" 와 "칼럼별 데이터타입이 같아야 한다."가 있다. 이 주의점을 이용하여 UNION에서 호출하는 칼럼의 수를 늘려가면, 데이터베이스에서 호출하는 칼럼 수가 몇 개인지 알아낼 수 있다.

유니온에서 호출하는 칼럼의 수가 데이터베이스에서 호출하는 칼럼수와 다를 때

데이터베이스에서 호출하는 칼럼의 수는 "7개"이다.

유니온에서 호출하는 칼럼의 수가 데이터베이스에서 호출하는 칼럼수와 같을 때

(4) 데이터베이스에 존재하는 모든 테이블 명을 출력하기

- 테이블과 필드의 정의

information_schema.schemata 데이터베이스와 관련된 정보를 가진 테이블
schema_name 모든 데이터베이스의 이름 값을 가진 필드
information_schema.tables 테이블과 관련된 정보를 가진 테이블
tables_name 모든 테이블의 이름 값을 가진 필드
information_schema.columns 필드와 관련된 정보를 가진 테이블
column_name 모든 필드의 이름 값을 가진 필드

즉, ' UNION SELECT ALL 1, table_name,3,4,5,6,7 from information_schema.tables# 를 입력하여 서버에 존재하는 모든 테이블을 알아볼 수 있다.

서버에 존재하는 모든 테이블명 출력

(5) 사용자 정보가 있을 것 같은 테이블의 칼럼 명을 출력하기

 (4)의 활동을 통하여 서버의 존재하는 모든 테이블 중 사용자 정보가 있을 것 같은 [users]테이블을 발견하였다. ' UNION SELECT ALL 1,column_name,3,4,5,6,7 from information_schema.columns where table_name='users'# 쿼리를 이용하여 users 테이블의 칼럼명을 확인해보도록 하자.

users 테이블의 칼럼명

(6) 사용자의 id, password, email 정보 등을 출력하기

' UNION SELECT ALL 1,concat(id,login),password,email,secret,6,7 from users# 쿼리를 이용하면 쉽게 사용자의 id, password, email 정보 등을 출력할 수 있다.