R e d A l i e n Click

엄청난 기술을 접하면, 마치 외계인의 기술을 훔친 것과 같다고 말합니다

붉은외계인은 그러한 놀라운 기술을 탐구하고, 기술적인 도전에 맞서는 것을 의미하는 저의 또 다른 이름입니다

서로가 성장할 수 있는 건설적인 토론을 좋아합니다.

article_thumbnail

[붉은외계인] Web - SQL Injection 총 정리(예시부터 시큐어코딩까지)

2023. 12. 27.
클릭 시, 이동!

1. SQL Injection(SQLI)이란 무엇인가

 

SQL Injection의 정의

 

웹 애플리케이션의 입력 필드 및 URL 매개 변수에 악의적인 쿼리문을 삽입하여, 웹 애플리케이션과 연동된 DB와
상호작용하려는 공격기법이다 이러한 SQL Injection의 원인은 server단에서의 입력값 검증 미흡으로 발생한다

 

SQL Injection의 공격 메커니즘

 

SQL Injection의 공격 메커니즘은 아래와 같다
첫번째로 오류 발생, 두번째로 오류 수정, 마지막으로 SQL Injection이다

SQL Injection에서 가장 먼저 시도하는 것은, 현재 애플리케이션 쿼리문의 오류를 발생시키는 것이다
오류를 발생시킬 수 있다는 것은, 누군가가 웹 애플리케이션을 통하여, 쿼리문에 간섭할 수 있다는 것을 의미하기 때문이다
이러한 점을 이용하여, 오류가 발생하지 않는 악의적인 쿼리문을 삽입하는 것이 바로 SQL Injection의 메커니즘이다

 

 
오류 발생 기호
공백 입력
‘)
‘))
“)
“)
`
`)
`))

 

대표적인 오류 발생기호는 위와 같다

 

DB
주석
MySQL
#내용
-- 내용
/*내용*/
/*!내용*/
PostgreSQL
--내용
/*내용*/
MSQL`
--내용
/*내용*/
Oracle
--내용
X
SQLite
--내용
X
HQL
X
X

 

그 다음으로, 오류 수정 방법에는 이전 쿼리가 새 데이터를 받도록 데이터를 입력 하거나, 데이터 입력 끝에 주석 기호를 추가하는 방법이 있다 DB에 따른 주석은 위와 같다

 


 

2. SQL Injection(SQLI) 종류

 

대표적인 SQL Injection의 종류는 아래와 같다

 

1. Error-based SQLI
2. Blind SQLI( Boolen-based blind SQLI )
3. Time-Based SQLI

 

하지만 sqlmap 도구에서 정의하는 것을 살펴보면 두 가지가 더 추가된다

 

4. Union Query based SQLi
5. Stacked Queries based SQLI

 

 

2-1. Error-based SQLI

 

Error-based SQLI는 웹 애플리케이션이 쿼리문의 에러 여부를 출력해준다는 점을 이용하여,
Injection하는 공격 기법이다

 

 

쿼리 결과가 애플리케이션 상에 출력되기 때문에, 공격자는 Injection을 통하여 직접적으로 DB내 정보를 열람할 수 있다
하지만 흔하지 않다

 

 

2-2. Blind SQLI ( Boolen-based blind SQLi )

 

Blind SQLI는 웹 애플리케이션이, 쿼리문의 결과를 Bool값으로 출력해준다는 점을 이용하여 injection하는 공격기법이다
Error-based와 달리, 정보를 직접적으로 확인할 수 없기 때문에 상대적으로 많은 시간이 소요된다

직접적으로 참/거짓이 출력되는 것이 아니라, 쿼리문이 참일 때의 웹 페이지와, 쿼리문이 거짓일 때의 웹 페이지가 다르게 출력된다
이 점을 이용하여 참/거짓을 판별한다

 

 

2-3. Time-based SQLI

 

Time-based SQLi는 sleep과 같은 지연 함수를 쿼리문에 사용하여 injection을 하는 공격 기법이다


쿼리문 앞쪽 구문이 참일 때, 뒤에 붙은 sleep 함수가 실행된다는 점을 이용하여,
답을 유추해가며 정보를 획득한다
가장 많은 시간이 소요되는 공격 기법이다

앞에서 알아본 Error-based와 Blind SQLI이 통하지 않을 때, 가장 마지막으로 사용하는 방법이기도하다
Time-based SQLI는 서버를 지연 시키기 때문에, 대량의 공격을 할 경우
서버가 멈출 수도 있는 위험이 있다

 

 


 

 

3. SQLI 취약점 진단

상품 검색창 개요
SQLI 여부
Time-based SQLI
진단 쿼리
' and ascii(substring(database(),1,1))=103 and sleep(1) #
상세 내용
-
원인 및 취약점
검증과정 없이 사용자 입력값을 그대로 사용

 

 

상품 검색창에 SQLI 취약점을 진단한 결과, Time-based 취약점이 발견되었다 과정을 살펴보겠다

 

 

싱글 쿼터( ' ) 를 입력하였을 때, 상품 검색창에서 오류가 발생한다는 것을 확인하였다

다음으로, 'or 1=1 # 를 입력하였을 때, 오류 수정이 된다는 것을 확인하였으나 그 반대값인 'or 1=2 #
를 입력하였을 때와는 차이가 없었다 또한 order by와 union 키워드 시도 또한 통하지 않았다

 

입력 쿼리
' and 1=1 and sleep(0.01) #

 

하지만 sleep() 함수를 사용하였을 때는 작동된다는 점을 파악하였다
고로, 상품 검색창은 Time-based SQLI 취약점이 존재하며, 이를 이용하여 취약점 진단을 진행하겠다

 

입력 쿼리
' and ascii(substring(database(),1,1))=103 and sleep(1) #

 

 

입력한 쿼리를 설명하자면, 아스키코드를 이용하여 DB Schema의 첫 글자를 알아내는 것이다
위와 같이 Burp Suite을 이용하여 연속적으로 입력하였을 때, 103에서 sleep 함수가
작동하는 것을 확인할 수 있다

 

 

상품 입력창에 103이 포함된 쿼리를 직접 입력하여 확인한 결과, sleep 함수 작동을 확인하였다
아스키코드의 103은 'g' 를 의미한다 고로, 해당 웹 애플리케이션 DB Schema의 첫 글자는 'g'인 것을 파악한 것이다

 

 

취약점이 발견된 파일의 요약 코드를 살펴보겠다

사용자 입력값은 $searchstring 변수로 바로 들어온다
그리고 쿼리문 작성을 살펴보면, 사용자 입력값은 대문자 변환 과정만 거치고, 곧바로 쿼리문 작성에 사용이 된다
즉, 입력값 검증을 하지 않는다는 것이다 이것이 원인이다

사용자 검색창에 ' or 1=1 # 를 입력할 경우, (name like '%' or 1=1 # 이렇게 입력이 되는 것이다

 

'or 1=1 #, 'or 1=2 #, order by, union 방식들이 통하지 않았던 이유는, 해당 쿼리문의 and와 괄호 때문이다


blimit<3 and category='category_info[code]' and (name like '%' or 1=1 ...)
여기서 괄호값의 name like '%' 로 인하여 무조건 출력이 된다

 

 


 

 

4. 공격 시연 - sqlmap

 

Sqlmap은 sql injection 결함을 탐지하고, 공격하는 작업을 자동화해주는 오픈 소스 침투 테스트 도구이다

MySQL, MariaDB Oracle, MSSQL 등 다양한 DB를 지원하며, Error-based, Blind, UNION Query based, Time-based, stacked queries, out-of band 등 총 6가지 공격 기법을 지원한다

 

 

SQLI 최근 공격 사례로, 중국 해커 조직인 샤오차잉의 국내 해킹 사례를 들 수 있다

2023년 1월 ~ 2월까지 국내 웹사이트를 대상으로 웹페이지 변조, 정보유출 등의 공격을 수행하였으며,
그 결과를 샤오치잉 홈페이지, 텔레그램, 해킹포럼 등을 통해 공개하였던 사건이다

여기서, 샤오치잉이 취약점 스캔 과정에서 사용하였던 도구가 바로 sqlmap과 Nuclei이다
해당 공격 시연에서는 이 sqlmap을 사용하여 진행할 것이다

 

--os-shell 옵션

 

os shell 내용을 언급하는 내용들이 없는거 같아, os shell 옵션을 적용하여 진행하였다
참고로 os-shell 옵션을 적용하기 전에, 이미 한 번 --dbs 옵션으로 공격에 성공하여 log가 저장된 상태로 진행하였다

 

 

위와 같이, -r 옵션을 이용하여 sqlmap이 알아서 인식하게끔 한 후, os-shell 명령어를 준다
메뉴얼을 보면, os-shell 옵션은 os 운영체제 위에 shell을 올리는 옵션이라고 명시되어 있다 ( ?? )

 

 

위의 그림은 os-shell이 성공한 모습이다 os 명령어에 따른 결과값을 반환해주는 것을 확인할 수 있다
해당 os-shell을 올리는 과정을, wireshark로 살펴보겠다

 

 

wireshark의 HTTP만 나열되게끔 필터를 주었을 때, 위의 그림과 같다

큰 흐름을 보자면, 실패가 발생하였지만서도 총 7번의 payload를 보낸 결과, 3개의 파일이 업로드 되었다
그리고 os 명령어를 수행한 후, 마지막으로 업로드 파일을 삭제하면서 마무리가 되는 모습이다
os명령어로 노출된 파일들은 아래와 같다

 

 

성공한 파일의 payload를 아래에서 살펴 보겠다

 

 

into outfile과, into dumpfile을 이용하여 쿼리문 내용을 파일로 저장하여 업로드를 한다
그리고 해당 파일안에 php 코드를 살펴보면 공통적으로 업로드를 하기 위한 코드이다

$_REQUEST 변수에 upload 변수가 있는지를 확인하여 그에 따라 경로를 지정하고,
php 버젼에 따라 파일 이름을 지정한다 그리고 chmod로 지정한 경로와 파일을 권한 상승 시켜준다

 

 

위에 그림은 payload로 올려진 tmpukpjc.php의 페이지이다

해당 페이지에서 업로드를하면 chmod로 권한 상승이 이루어진다
해당 페이지에서 os-shell 실행 파일을
업로드 하는 순간, 권한 상승이 되면서 실행이 되는 것이다

 

 

- 짜투리 팁들

 

1. 일단 injection 성공한 후에, 어떠한 정보라도 눈으로 표시가 된다면 Error-based


2. order by를 맹신하지 말 것
order by를 사용하여, 1 ~ 99가 될 수도 있고, 아예 안될 수도 있다 결국은 union으로 하나하나 끝까지 입력해봐야 확실하다

3. union키워드는 두 개의 쿼리문을 하나의 결과로 출력해준다 하지만 앞에 쿼리문과의 칼럼 갯수와 뒤에 쿼리문의 칼럼 갯수를 맞추어야하는 제약이 있다
ex) 'union select 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38 #

이것은 앞에 테이블 칼럼 갯수가 38개라는 것

 

 

- SQL Injection시, 사용할만한 시스템변수 Or 함수들

 

@@version
@@hostname
@@port
@@basedir : mysql 최상위 디렉토리
@@datadir : mysql 운영중에 생성하는 데이터의 기본 위치

user()
load_file() : db_user가 root일 경우, 해당 함수를 사용하여 /etc/passwd 조회가 가능함

outfile : root 사용자일 경우, > select "<?php system($_GET['cmd'];?>" into outfile /var/www/.... 이와 같이 webshell 업로드가 가능하다 업로드 조건은 아래와 같다

1. 업로드파일의 확장자가허용되어야 하며
2. 업로드 한 파일의 절대 경로가 확인 가능해야하며,
3. 실행 권한이 존재해야야 한다

 


 

5. 대응 방안

 

보안 관점에서 가장 기본적인 전제는 입력값에 대한 불신과 검증이다
여기서의 입력값은 로그인
페이지처럼 직접 입력하는 값도 의미하나, 넘어오는 parameter값 또한 해당된다
SQL Injection의 원인은 궁극적으로 입력값에 대한 검증 미흡으로 발생한다

 

5-1. mysqli_real_escape_string

 

현재 사용중인 PHP 버전은 5.2.4이기 때문에 mysql_real_escape_string 함수를 사용하였다
이 함수는 PHP7.0 이상에서는 더 이상 사용되지 않으며, 7.0 이상에서
mysqli_real_escape_string 함수가 사용되니 참고할 것

 

 

mysqli_real_escape_string 함수의 경우는 인자로 db_connection까지 입력해야한다

 

- 5-2. white list

 

Whilte list는 허용되는 문자 list를 의미한다 White list를 제외하고는 모두 금지시키는 대응 방법이기 때문에,
black list 방식보다 더 타이트한 대응 방법이다

 

 

preg_match 함수는 whitelist로 사용할 변수와, 점검할 변수를 매개변수로 넣어주면 된다
여기서 preg_match는 정규 표현식을 사용하여 매개변수를 넣어야 한다

 

 

- 5-3. DB 계정 권한 제한

모든 시스템 및 DB 보안에는 ‘최소 권한’ 원칙을 기본으로 하고 있기 때문에, 권한이 제한된 계정으로 따로 분리를 해주어야 한다

 

 
권한 부여 &
계정 생성
grant select, insert, upate, delete on 스키마이름.* to 사용자이름@localhost identified by ‘1234’;

 

웹 애플리케이션이 root 사용자로 DB에 접속할 경우, 제한없는 DB사용으로 인하여 SQLI 공격이 성공하였을 때
자료들을 삭제하는 등 큰 피해를 입힐 수 있기 때문이다

 

'Web' 카테고리의 다른 글

[붉은외계인] Web - reverse_tcp와 방화벽 정책과의 관계  (0) 2023.12.07