SQL Injection ?
- DB와 연동된 웹 애플리케이션에서 공격자가 입력폼 또는 URL 입력란에 SQL 구문을 삽입하여 DB를 조작할 수 있는 취약점
- 클라이언트 측에서 입력된 신뢰할 수 없는 데이터가 SQL 쿼리 로직의 일부로 해석되어 DB에서 실행되는 공격
DVWA 환경에서 SQL Injection 공격 실습
우선 본 실습에 앞서 실습 환경의 경우 리눅스 환경에서 DVWA 환경을 구축한 후 가장 취약한 환경인 Low 레벨 환경에서 실습을 진행하였습니다.
DVWA 웹 페이지에서 SQL Injection 탭으로 이동한 모습
User ID 입력란에 숫자(1~5)를 입력하면 입력한 번호에 매칭되는 계정의 First name 과 Surname이 출력되는 기능이 있는 것을 확인할 수 있다.
해당 기능을 구현한 소스코드를 살펴보면 SELECT first_name, last_name FROM users WHERE user_id = '$id'; 라는 SQL 구문이 DBMS로 전송되는 것을 확인할 수 있다.
이때 이전 User ID 입력란에 입력한 값은 id 라는 매개변수에 아무런 검증 조치 없이 저장되어 DBMS로 전송된다는 사실을 확인할 수 있다.
입력한 값이 id 라는 매개변수에 아무런 검증 조치 없이 저장된다는 사실을 기반으로 입력란에 where 구문을 우회할 수 있는 or 연산자와 언제나 참이되는 값(1=1)을 입력하여 전송한 결과 DB에 저장된 모든 계정의 first_name과 last_name이 출력되는 모습을 확인할 수 있었다.
해당 결과가 나타난 이유를 알아보면 우선 어떤 SQL 구문이 DBMS 로 전송 되었는지 알아야한다.
전송된 SQL 구문은 다음과 같음 => SELECT first_name, last_name FROM users WHERE user_id = '' or 1=1-- ';
해당 구문에서 OR 라는 논리 연산자는 조건 중 하나라도 참이라면 참 값을 반환하는 논리 연산자이고 뒤에 입력한 1=1 이라는 조건은 언제나 참인 조건이기 때문에 WHERE 구문에 입력된 조건 자체가 무효화 된 것과 마찬가지이기 때문에 해당 테이블에 저장된 모든 first_name 과 last_name이 출력된 모습을 확인할 수 있다.
=> 즉, SELECT first_name, last_name FROM users WHERE user_id = '' or 1=1-- '; 라는 SQL 구문과 같은 결과인 것
위와 같이 구문을 사용한 공격은 보통 로그인 폼을 SQL Injection 공격을 이용하여 우회할 경우 많이 사용되는 구문이다.
보통 로그인 폼의 경우 SELECT * FROM users WHERE user_id = '$id' and user_pw = '$pw'; 와 같은 SQL 구문을 이용하여 로그인 인증을 많이 구현하고 있는데 위 구문의 WHERE 절을 항상 참인 조건으로 만들어 SELECT * FROM users 와 같은 쿼리 효과를 만들어 로그인 자체를 우회하는 공격에 많이 이용된다. 또 이러한 방식으로 로그인 폼을 우회하여 접속을 할 경우 가장 첫 번째로 생성된 계정의 권한으로 로그인이 되는데 보통 관리자 권한의 계정인 경우가 많아 공격에 많이 활용된다고 한다.
※ 절대 허가 받지 않은 곳에 악의적으로 공격에 활용하면 안됩니다. 모든 법적 책임은 본인에게 있습니다.
이번 공격은 ORDER BY 구문을 활용하여 원본 SELECT 문이 검색하는 Columns의 개수를 알아내는 공격을 수행한 모습이다.
우선 해당 공격을 수행한 이유는 뒤에 나올 Union 구문을 이용한 공격을 수행하기 위해 우선 Columns의 개수를 알아내는 공격을 먼저 수행한 것이다.
Union 구문의 경우 합집합이라는 의미의 SQL 구문으로 1번 SELECT문 + 2번 SELECT문을 하여 결과를 출력해주는 구문인데 Union 구문을 사용하기 위해서는 첫 번째로 작성된 SELECT 구문과 두 번째로 작성된 SELECT 구문의 Columns 개수와 데이터 형식이 같아야 오류가 발생하지 않고 구문이 정상적으로 작동하기 때문에 Union 구문을 수행하기 이전에 먼저 원본 SELECT문(1번 SELECT 문)의 Columns를 알아내는 공격을 수행하는 것이다.
우선 공격한 것을 해석하기 전 ORDER BY 구문의 역할을 간략하게 알아보면 ORDER BY 구문은 입력된 Columns 기준으로 데이터를 정렬하는 명령어이다. => ORDER BY 3 : 3번째 열을 기준으로 데이터를 정렬한다는 뜻
입력된 숫자가 원본 테이블의 Columns 개수보다 클 경우 오류가 발생하는 특성을 이용하여 원본 SELECT 문이 검색하는 Columns 개수를 알아내는 것이다.
ORDER BY 구문을 이용하여 원본 SELECT문이 검색하는 Columns 개수를 확인하기 위해 숫자를 1부터 늘려가며 확인해본 결과 2를 입력하였을 때까지는 에러가 발생하지 않았으나 3을 입력하는 순간 오류가 발생하는 것을 확인할 수 있다.
즉, 원본 SELECT 문이 검색하는 Columns의 개수는 2개인 것을 확인할 수 있다.
이전에 ORDER BY 구문을 이용하여 알아낸 원본 SELECT 문이 검색하는 Columns 개수를 기반으로 Union 구문을 작성하고 database() 함수와 @@version, @@hostname 을 입력하여 DB이름, DBMS 정보, 호스트 이름을 조회하는 공격을 수행한 결과의 모습
DB 이름은 'dvwa', 사용하는 DBMS 버전은 10.6.10-MariaDB+1+b1, 호스트 이름은 kali 라는 것을 알 수 있었다.
이전에도 DB 이름을 알아내는 공격을 database()함수를 사용하여 진행하였지만 다른 방법으로도 DB 이름을 조회할 수 있다는 것을 알려주기 위한 것
DB는 데이터를 위한 데이터라고 불리는 메타데이터라는 것이 있다. MySQL을 기반으로한 DB는 INFORMATION_SCHEMA라는 DB가 바로 메타데이터인데 이곳에서 모든 데이터베이스의 구조를 알아낼 수 있다.
INFORMATION_SCHEMA라는 DB안에 SCHEMATA 라는 이름의 테이블에서 스키마 이름( 여기선 DB이름이라 생각해도 될 것 )를 조회한 결과의 사진이다.
데이터베이스에는 2개의 스키마가 있는 것을 확인할 수 있는데 이 중 dvwa 라는 이름의 데이터베이스에 원하는 정보가 있을 것으로 예상되었고 해당 데이터베이스에 접근하여 다른 여러 정보도 알아내는 공격을 계속 수행하였다.
앞에서 알아낸 데이터베이스 이름을 기반으로 해당 데이터베이스에 존재하는 모든 테이블을 조회하는 공격을 수행해본 결과이다.
dvwa 라는 이름의 데이터베이스에는 guestbook 테이블과 users 라는 테이블이 존재하는 것을 확인할 수 있었다.
이 중 users 테이블에 사용자 계정 정보가 있을 것으로 예상되어 users 테이블에 있는 Columns 정보를 조회해보았다.
※ Table 정보는 information_schema.tables 에서 조회할 수 있다.
users 테이블에 있는 Columns 정보를 조회한 결과의 모습이다.
여러 Columns이 존재하는 것을 확인할 수 있었는데 이 중 users 와 password 라는 이름의 Columns에 사용자 계정 정보와 패스워드 정보가 있을 것으로 예상되어 해당 Columns 내용을 조회하는 공격을 수행하였다.
users 테이블의 user, password 라는 이름의 Columns의 내용을 조회한 결과
모든 사용자 계정과 패스워드가 조회된 모습을 확인할 수 있었다.
이 중 패스워드의 경우는 MD5 알고리즘을 이용하여 암호화되어 테이블에 저장되어 있는 모습을 확인할 수 있었다.
하지만 해당 암호화 알고리즘의 경우는 현재는 취약한 암호화 알고리즘 중 하나이기 때문에 출력된 패스워드 중 하나를(gordonb 계정) 복호화 해보았다.
복호화를 시도한 결과 gordonb 라는 계정의 패스워드는 abc123 이라는 것을 알 수 있었다.
마지막으로 지금까지의 공격으로 탈취한 사용자 계정과 패스워드로 DVWA 웹 페이지에서 로그인한 결과 계정 탈취에 성공하여 gordonb 계정으로 로그인에 성공한 모습을 확인할 수 있었다.
SQL Injection 대응방안
- Prepared statement 구문을 사용하여 입력된 값은 모두 문자열로서만 처리되도록 구현하는 것이 가장 안전하다.
- 하지만 여러 이유로 Prepared statement 구문을 사용하여 구현하지 못하는 상황이 있을 수 있다. 그럴 경우 입력된 값이 개발자가 의도한 값인지 검증할 수 있는 로직을 구현하여 불필요한 특수 문자 등은 입력되지 않도록 구현해야 한다.
위 예시는 특정 문자가 입력될 경우 자동으로 공백으로 치환되도록 설정하고 SQL 구문이 입력란에 입력될 경우 에러 팝업창이 출력되도록 설정하여 불필요한 문자는 입력하지 못하도록 제한한 코드이다.
- WAS 설정 파일(위 예시는 php 설정 파일)에서 에러메시지는 출력 되지 않도록 설정해야 한다.
- 웹 방화벽(WAF, Web Application Firewall)을 사용하여 부적절한 문자열이 전송될 경우 차단한다.
'CERT > 웹 모의해킹 실습' 카테고리의 다른 글
[웹 해킹] Weak Session IDs / DVWA 환경 실습 / 대응 방안 (0) | 2023.06.21 |
---|---|
[웹 해킹] Blind SQL Injection / DVWA SQL Injection(Blind) 실습 / 대응 방안 / SQLMAP 사용법 (0) | 2023.06.16 |
[웹 해킹] Insecure CAPTCHA / DVWA 환경 실습 / 대응 방안 ( 캡챠 우회 공격 ) (0) | 2023.06.03 |
[웹 해킹] File Upload 공격 / DVWA 환경 실습 / 대응 방안 (0) | 2023.06.03 |
[웹 해킹] File Inclusion 공격/DVWA 환경 실습/대응 방안 (0) | 2023.05.27 |