Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQL Injection #85

Open
khyunjiee opened this issue Sep 12, 2021 · 1 comment
Open

SQL Injection #85

khyunjiee opened this issue Sep 12, 2021 · 1 comment

Comments

@khyunjiee
Copy link
Collaborator

SQL Injection

SQL 인젝션이란?

SQL 인젝션은 웹 사이트의 보안상 허점을 이용해 특정 SQL 쿼리문을 전송해 공격자가 원하는 데이터베이스의 중요한 정보를 가져오는 해킹 기법이다.

대부분 클라이언트가 입력한 데이터를 제대로 필터링하지 못하는 경우에 발생한다.

공격의 쉬운 난이도에 비해 피해가 상당하기 때문에 보안 위협 1순위로 불릴만큼 중요한 기법이다.

SQL 인젝션의 종류와 공격 방법

Error based SQL Injection

논리적 에러를 이용한 SQL 인젝션

가장 많이 쓰이고, 대중적인 공격 기법이다.

SELECT * FROM Users WHERE id = 'INPUT1' AND password = 'INPUT2'
SELECT * FROM Users WHERE id = ' ' OR 1=1 -- 'AND password = 'INPUT2'
--> SELECT * FROM Users

첫번째 쿼리문은 일반적으로 로그인 시 많이 사용되는 SQL 구문이다.

해당 구문에서 입력값에 대한 검증이 없음을 확인하고, 악의적인 사용자가 임의의 SQL 구문을 주입했다.

주인된 내용은 ' OR 1=1-- 으로 WHERE 절에 있는 ' 를 닫아주기 위한 ' 와 OR 1=1 라는 구문을 이용해 WHERE절을 모두 참으로 만들고, —를 넣어주어서 뒤의 구문을 주석 처리를 해준 것이다.

매우 간단한 구문이지만 결론적으로 Users 테이블에 있는 모든 정보를 조회하게 됨으로써 가장 먼저 만들어진 계정으로 로그인에 성공하게 된다.

보통 관리자 계정을 맨 처음으로 만들기 때문에 관리자 계정으로 로그인할 수 있게 되며, 악의적인 사용자는 관리자의 권한을 이용해 또 다른 2차피해를 발생시킬 수 있게 된다.

UNION based SQL Injection

UNION 명령어를 이용한 SQL 인젝션

UNION은 여러개의 SQL문을 합쳐 하나의 SQL 문으로 만들어주는 방법이다.

정상적인 쿼리문에 Union 키워드를 사용해 인젝션에 성공하면, 원하는 쿼리문을 실행할 수 잇게 된다.

Union Injection을 성공하기 위해서는 두 테이블의 컬럼 수가 같아야 하고, 데이터 형이 같아야 한다는 두 가지의 조건이 있다.

SELECT * FROM Board WHERE title like '%INPUT%' OR contents like '%INPUT%'
SELECT * FROM Board WHERE title LIKE '% ' 
UNION SELECT null, id, password FROM Users 
-- %' AND contents '% UNION SELECT null, id, password FROM Users -- %'

첫번째 쿼리문은 Board라는 테이블에서 게시글을 검색하는 쿼리문이다.

입력값을 title과 content 컬럼의 데이터랑 비교한 뒤 비슷한 글자가 있는 게시글을 출력한다.

여기서 입력값으로 Union 키워드와 함께 컬럼 수를 맞춰서 SELECT 구문을 넣어주게 되면 두 쿼리문이 합쳐져서 하나의 테이블로 보여지게 된다.

현재 인젝션한 구문은 사용자의 id와 password를 요청하는 쿼리문이다.

인젝션이 성공하게 되면, 사용자의 개인정보가 게시글과 함께 화면에 보여지게 된다.

password를 그대로 DB에 저장하지는 않겠지만 인젝션이 가능하다는 점에서 이미 그 이상의 보안위험에 노출되어 있다.

이 공격도 역시 입력값에 대한 검증이 없기 때문에 발생한다.

Blind SQL Injection

Boolean based Blind SQL 인젝션

Blind SQL Injection은 데이터베이스로부터 특정한 값이나 데이터를 전달받지 않고 단순히 참과 거짓의 정보만 알 수 있을 때 사용한다.

로그인 폼에 SQL Injection이 가능하다고 가정했을 때, 서버가 응답하는 로그인 성공과 로그인 실패 메시지를 이용해 DB의 테이블 정보 등을 추출한다.

즉, 쿼리를 삽입하였을 때 쿼리의 참과 거짓에 대한 반응을 구분할 수 있을 때 사용되는 기술이다.

SELECT * FROM Users WHERE id = 'INPUT1' ANS password = 'INPUT2'
SELECT * FROM Users WHERE id = ' abc123' and 
ASCII(SUBSTR((SELECT name FROM information_schema.tables 
WHERE table_type='base table' limit 0,1),1,1)) > 100 --

위 쿼리는 Blind Injection을 이용해 DB의 테이블명을 알아내는 방법이다.

인젝션이 가능한 로그인 폼을 통해 악의적인 사용자는 임의로 가입한 abc123이라는 아이디와 함께 뒤의 구문을 주입한다.

해당 구문은 MySQL에서 테이블 명을 조회하는 구문으로 limit 키워드를 통해 하나의 테이블만 조회하고, SUBSTR 함수로 첫 글자만, 그리고 마지막으로 ASCII를 통해 ascii 값으로 변환한다.

만약 조회되는 테이블 명이 Users 라면 'U' 가 조회될 것이고, 뒤의 100이라는 숫자와 값을 비교하게 된다.

거짓이면 로그인 실패, 참이 될 때까지 뒤의 100이라는 숫자를 변경해가면서 비교한다.

참이 나오는 것을 통해 단기간 내에 테이블 명을 알아낼 수 있다.

Time based SQL

어떤 경우에는 응답의 결과가 항상 동일해 해당 결과만으로 참과 거짓을 판별할 수 없는 경우가 있을 수 있다.

이런 경우 시간을 지연시키는 쿼리를 주입(Injection)하여 응답 시간의 차이로 참과 거짓 여부를 판별할 수 있다.

사용되는 함수는 MySQL 기준 SLEEP 과 BENCHMARK 이다.

SELECT * FROM Users WHERE id = 'INPUT1' AND password = 'INPUT2'
SELECT * FROM Users WHERE id = ' abc123' OR 
(LENGTH(DATABASE())=1 AND SLEEP(2)) 
-- ' AND password = 'INPUT2'

위 쿼리문은 Time based SQL Injection을 사용해 현재 사용하고 있는 데이터베이스의 길이를 알아내는 방법이다.

로그인 폼에 주입되었으며 임의로 abc123이라는 계정을 생성한다.

악의적인 사용자가 해당 구문을 주입하면, LENGH 함수는 문자열의 길이를 반환하고, DATABASE 함수는 데이터베이스의 이름을 반환한다.

주입된 구문에서, LENGTH(DATABASE()) = 1 가 참이면 SLEEP(2) 가 동작하고, 거짓이면 동작하지 않는다.

이를 통해 숫자 1 부분을 조작해 데이터베이스의 길이를 알 수 있다.

만약 SLEEP 이라는 단어가 치환 처리되었다면, 다른 방법으로 BENCHMARK 나 WAIT 함수를 사용할 수 있다.

Stored Procedure SQL Injection

저장된 프로시저에서의 SQL Injection

저장 프로시저(Stored Procedure)은 일련의 쿼리들을 모아 하나의 함수처럼 사용하기 위한 것이다.

공격에 사용되는 대표적인 저장 프로시저는 MS-SQL에 있는 xp_cmdshell로 윈도우 명령어를 사용할 수 있게 된다.

단, 공격자가 시스템 권한을 획득해야 하므로 공격난이도가 높으나 공격에 성공한다면 서버에 직접적인 피해를 입힐 수 있는 공격이다.

Mass SQL Injection

다량의 SQL Injection 공격

기존 SQL Injection과 달리 한번의 공격으로 다량의 데이터베이스가 조작되어 큰 피해를 입히는 것을 의미한다.

보통 MS-SQL을 사용하는 ASP 기반 웹 애플리케이션에서 많이 사용되며, 쿼리문은 HEX 인코딩 방식으로 인코딩해 공격한다.

보통 데이터베이스 값을 변조해 데이터베이스에 악성스크립트를 삽입하고, 사용자들이 변조된 사이트에 접속 시 좀비 PC로 감염되게 한다.

이렇게 감염된 좀비 PC들은 DDos 공격에 사용된다.

SQL 인젝션 대응방안

입력 값에 대한 검증

SQL Injection에 사용되는 기법과 키워드는 엄청 많다.

따라서 사용자의 입력 값에 대한 검증이 필요하다.

서버 단에서 화이트리스트를 기반으로 검증해야 하며, 블랙리스트를 기반으로 검증하게 되면 차단리스트를 많이 등록해야 하고, 하나라도 빠지면 공격에 성공하게 된다.

공백으로 치환하는 방법도 많이 쓰이는데, 이 방법도 취약한 방법이다.

예시로 SESELECTLECT 라고 입력 시 중간의 SELECT가 공백으로 치환되면 SELECT 라는 키워드가 완성된다.

공백 대신 공격 키워드와를 의미 없는 단어로 치환되어야 한다.

Prepared Statement 구문 사용

Prepared Statement 구문을 사용하게 되면, 사용자의 입력 값이 데이터베이스의 파라미터로 들어가기 전 DBMS가 미리 컴파일하여 실행하지 않고 대기한다.

그 후 사용자의 입력 값을 문자열로 인식하여 공격쿼리가 들어간다고 해도, 사용자의 입력은 이미 의미 없는 단순 문자열이기 때문에 전체 쿼리문도 공격자의 의도대로 작동하지 않는다.

Error Message 노출 금지

공격자가 SQL Injection을 수행하기 위해서는 데이터베이스의 정보(테이블, 컬럼 명)가 필요하다.

데이터베이스 에러 발생 시 따로 처리하지 않는다면, 에러가 발생한 쿼리문과 함께 에러에 관한 내용을 반환해주기 때문에 공격자에게는 힌트가 될 수 있다.

따라서 데이터베이스에 대한 오류가 발생할 때는 사용자에게 보여줄 수 있는 페이지를 제작하거나 메시지박스를 띄우도록 해야 한다.

웹 방화벽 사용

웹 공격 방어에 특화되어있는 웹 방화벽을 사용하는 것도 하나의 방법이다.

웹 방화벽은 소프트웨어형, 하드웨어형, 프록시형 세 가지 종류로 나눌 수 있다.

소프트웨어형은 서버 내에 직접 설치하는 방법이고, 하드웨어형은 네트워크 상에서 서버 앞 단에 직접 하드웨어 장비로 구성하는 것이며 마지막으로 프록시형은 DNS 서버 주소를 웹 방화벽으로 바꾸고 서버로 가는 트래픽이 웹 방화벽을 먼저 거치도록 하는 방법이다.

@khyunjiee
Copy link
Collaborator Author

SQL 인젝션을 설명해보세요.
SQL 인젝션을 방어할 수 있는 기법은 어떤 것이 있나요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant