안녕하세요 Retain0입니다. 이번 시간에는 " DVWA "라는 취약한 웹 애플리케이션을 통한 SQL injection 공격을 해보도록 하겠습니다.
SQL injection 이란
- 웹 어플리케이션에서 입려 되는 사용자의 입력값을 조작하여 해당 서버의 데이터베이스를 공격하는 기법으로 주로 사용자가 입력한 값을 제대로 검증하지 못할떄 발생합니다. 이를 통해 DB내의 정보 즉 사이트 내에 회원정보를 갈취하고 DB내용을 변조할 수도 있으며 관리자급 권한을 획득할 수도 있습니다. OWASP top 10 중에서도 빈도수가 가장 높은 공격에 속하는데 입력값 검증을 하지 않을 시 아주 간단한 구문 하나만으로도 취약점을 찾아내어 큰 타격을 줄 수도 있습니다.
SQL injection 의 대표적인 종류들
- Error Based : 논리적 에러를 이용한 SQL injection 공격으로 가장 많이 쓰고 대중적인 공격입니다. 조작된 쿼리 입력을 통해 에러 메시지를 노출시키는데 그 안에 주로 DB에 관한 정보를 담아 노출시키게 됩니다.
- Union Based : Union 키워드는 두 개의 쿼리문에 대한 결과를 통합해서 하나의 테이블로 보여주게 하는 키워드입니다. 정상적인 쿼리문에 Union 키워드를 사용하여 삽입시 원하는 쿼리문을 실행 실수 있게 됩니다.
- Boolean Based : 특정한 값이나 데이터를 전달받지 않고, 단순히 참과 거짓의 정보만 알 수 있을 때 사용합니다.
- Time Based : 서버의 특정한 응답 대신 참 혹은 거짓의 응답을 통해서 데이터베이스의 정보를 유추하는 기법입니다. 사용되는 함수는 MySQL 기준으로 " SLEEP " 과 " BENCHMARK " 가 있습니다.
① Low
현재 실습환경에서는 1~5까지의 사용자 ID가 있습니다. 사용자의 입력값을 검증하지 않는다는 가정하에 해당 사용자의 ID를 입력하는 폼에 " ' " 작은따옴표를 입력해서 MySQL 에러를 일으켜 보도록 하겠습니다.
(사진 2)를 보시면 MySQL 에러가 뜬것을 확인하실 수가 있습니다. 해당 구문이 나올 경우 SQL injection에 취약하다는 것을 의미하며 추가적으로 공격을 진행할 수 있게 됩니다.
(사진 3)을 보시면 user_id='$id', '"라고 적혀져 있는 부분이 있습니다. $id라는 변수는 이미 작은따옴표로 둘러 쌓여져 있기 때문에 작은 따옴표 하나만 입력하게 되면 WHERE user_id=''' 3개가 되기 때문에 에러가 발생하게 된 것입니다.
(사진 4) WHERE 구문 우회 기법인 1' OR '1'='1을 입력해보면 ID가 1을 포함한 DB에 있는 모든 ID 값과 name을 도출시키게 됩니다. or 구문으로 '1'='1' 참값이 되었기에 모든 계정을 도출시키게 된 겁입니다.
(사진 5) union 구문인 1' union select 1# 을 입력해서 컬럼갯수를 알아내 보도록 하겠습니다. 컬럼갯수가 정확히 맞지 않는 이상 구문 에러가 발생할 것입니다.
1' union select 1#
1' union select 1,1# 을 입력하여 컬럼수를 올려본결과 합집합의 의미를 담고 있는 union 구문으로 인해 우리가 따로 select로 추가했던 First name : 1 / Surname : 1 도 출력된것을 확인할 수가 있습니다.
1' union select 1,1#
컬럼수를 하나 더 높여서 1' union select 1,1,1# 을 입력해보면 다시 구문에러가 발생합니다. 즉 컬럼이 2개 사용되고 있다는것을 알수가 있습니다.
union 구문 말고도 order by 구문을 통해서도 컬럼 갯수를 알아낼 수가 있습니다. order by 구문의 사용 목적은 특정한 컬럼을 기준으로 정렬할 때 사용하는 키워드입니다. 즉 컬럼의 갯수보다 큰 값을 찾아내게 되면 정렬을 할 수 없기 때문에 에러를 발생시키게 될 것입니다.
(사진 8) order by 절을 사용해본 결과 에러가 발생하지 않고 정상적으로 출력되었습니다. 그럼 에러가 발생할 때까지 숫자를 증가시키도록 입력해야 합니다.
1' order by 1#
1' order by 3#
1' order by 3# 에서 에러 페이지가 노출되었습니다. 이것을 토대로 해당 컬럼은 2개를 사용한다는 것을 알 수 있게 됩니다.
union 구문과 order by 구문의 차이점이라면 union 구문의 경우 컬럼의 갯수가 정확히 맞을 때까지 하나씩 대입해봐야하 하지만 order by 절을 사용하면 컬럼의 갯수가 입력값보다 큰지 안 큰지 유무를 통해 확인할 수있기떄문에 금방 알아낼 수 있습니다.
1' union select schema_name,1 from information_schema.schemata#
MySQL 은 information_schema라는 데이터베이스에서 정보 등을 관리하고 있습니다. schema_name 구문을 통해 데이터베이스의 이름을 조회해본 결과 모든 DB 이름들이 도출된 것을 확인할 수가 있습니다.(admin, information_schema, dvwa)
1' union select table_schema, table_name from information_schema.tables where table_schema = 'dvwa' #
DB명을 획득하였으니 이제 상위의 구문을 통해 Table 명을 획득해 보도록 하겠습니다. (사진 11)을 보시다시피(admin, guest book, users)라는 3개의 테이블들이 조회되었습니다.
1' union select table_name, column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users'#
" users "라는 Column 정보를 획득하기 위해 상위의 구문을 사용하였습니다. 결과적으로 (admin, user_id, first_name, user, password 등의 계정 정보에 대한 컬럼이 확인되었습니다.
1' union select user,password from users#
상위 구문을 통해 최종 사용자 아이디와 패스워드를 추출하였습니다. 패스워드 부분은 " Hash " 값으로 암호화되어 있습니다. 추가적으로 암호를 획득하기 위해선 " hash-identifier "을 통해 종류를 파악하고 암호화를 깨트리도록 추가 조취를 취해야 합니다.
1' and 1=1#
OR
SELECT user from users whwere id='1' and 1=2#
참과 거짓 값을 구분할 수 있는 SQL 쿼리문 삽입을 통해 숫자 형태의 데이터까지 파악할 수 있는 기법입니다.
1' and 1=1#이라는 참 값과 1' and 1=2# 거짓 값 입력을 통해 해당 웹 어플리케이션에서 보여지는 결과가 틀리면 Blind SQL injection에 취약하다고 볼 수 있습니다. 만일 대상 백그라운드에서 SQL 쿼리문이 실행되고 있다면 SELECT user from users where id='1' and 1=1# 이 될 것입니다.
Blind SQLi 의경우 상위처럼 결과를 화면을 통해 직접적으로 획득할 수는 없으나 존재하느냐 없느냐의 식으로 뒤에 and를 사용해 해당 구문이 참인지 아닌지 파악하는 용으로 사용됩니다.
Blind SQLi 에 대한 대응방법을 우회할 수 있는 기법입니다. 즉 참과 거짓 값을 구분하려는데 응답 결과가 동일하다면 이럴 땐 " 응답 시간의 차이 "를 주면 성공할 수 있습니다. 예를 들어 참일 경우 sleep이나 wait for을 삽입하여 응답을 몇 초 늦게 오도록 해주는 것입니다.
1' and sleep(5)#
상위의 구문을 삽입해 본 결과 하단의 검정 박스를 보시다시피 5020ms 즉 5초 정도 응답이 있다가 반응하는 것을 확인할 수 있습니다.
6' and sleep(5)#
거짓 값 인 상위의 구문을 입력해본 결과 전 과는 다른 응답 시간의 차이를 주고 있는 것을 확인하실 수가 있습니다.
이를 토대로 id 가 1이라는 사용자가 존재한다는 것을 알 수가 있고 id 가 6인 사용자는 존재하지 않는다는것을 알수 있습니다.
sqlmap -u "http://192.168.0.20/dvwa/vulnerabilities/sqli/?id=1&submit=submit#" --cookie="security=low; PHPSESSID=jhvvikku5tqods1h6bb9car73l"
SQLi 공격을 수행하는데 제일 많은 사랑을 받고 있는 대중화된 도구이며 아직까지 많은 실무자들도 애용할 정도로 강력한 도구입니다.
-u : 타겟 주소를 넣기 전에 사용되는 옵션으로 로그인이 된 상태에서 진행하게 될 시 --cookie=COOKIE 옵션을 사용하여 쿠키 정보를 추가적으로 입력해줘야 sqlmap 도 로그인이 된 것처럼 진행함
--cookie : 쿠키값 입력 (F12를 눌러 console 탭 하단에 " document.cookie "를 입력하면 편하게 확인 가능
(사진 20) 3719개의 http 요청을 자동으로 보냈으며 위에서 수동으로 입력했던 union, orderby, Blind, Time 등 의 기법들을 무작위로 삽입하여 결과를 얻어냅니다. 추가적으로 하단에 MySQL 버전, 웹서버 버전 등 을 파악할 수 있습니다.
② Mideum
(사진 21) Low 레벨에서 사용한 방식 그대로 하면 에러 메시지만 도출될 뿐 추가적인 정보를 획득할 수가 없습니다. 소스코드를 확인해 본 결과 user_id=$id;"; 부분이 Low 방식과 틀립니다. id부분에 ' 작은따옴표 가 없는 걸 보니 숫자만 입력받겠다고 설정한 것으로 확인됩니다.
(사진 22)를 보시다시피 프록시도구를 통해 잡은 후 구문 삽입을 작은따옴표 없이 제거하여 삽입해 보도록 하겠습니다.
Mideum 소스코드를 파악하고 작으따옴표를 제거 후 쿼리문을 입력해보니 정상적으로 결과가 도출된 것을 확인할 수가 있습니다.
1 union select user,password from users#
합집합의 의미를 가진 union 구문 사용에서도 마찬가지입니다. 작은따옴표를 제거해주면 정상적으로 원하는 결과를 획득하실 수 있습니다.
위의 구문을 통해 user_id와 password를 도출할 수 있습니다.
③ High
" Click here to change your ID 링크를 클릭해본 결과 Submit이라는 입력 폼이 새로 생겼습니다. 여기에 값을 대입하면 전송되어 저장되는 형태인 것 같습니다. 우선 소스코드를 확인해보도록 하겠습니다.
id='$id'=LIMIT 1, "; 부분이 있습니다. LIMIT 1이라는 것을 통해 출력되는 레코드의 수를 1개로 조절하여 여러 값들이 나오지 않게끔 하고 있습니다. 하지만 $id 뒤에 " # "을 붙이게 되면 #뒷부분은 모두 주석처리가 되기 때문에 이러한 제한을 우회할 수가 있습니다.
1' or '1'='1'#
상위의 구문을 입력해주면 뒷부분은 전부 주석처리가 되기 때문에 LIMIT 제한을 우회하여 모든 값을 추출시킬 수 있게 됩니다.
1' union select user,password from users#
상위의 구문 마지막에 " # "을 붙임으로써 모든 계정의 값들을 추출시킬 수 있게 됩니다.
◆ 대응방안
(사진 30)을 보시면 현재 dvwa에서는 id 가 1,2,3,4,5 형식으로 되어있습니다. 그렇기에 입력되는 ID 가 숫자인지 아닌지를 먼저 구분해야 하며 문자를 입력해야 할 경우 허용되는 문자만 사용할 수 있도록 제한을 걸어둬야 합니다. 해당 서비스에 필요한 데이터 형식을 제대로 숙지하고 있지 못할 경우 다양한 우회 기법을 통해 SQLi를 성공시킬 것입니다.
또한 " Check the database " 하단을 보시면 prepare , bindParam, excute 같은 함수를 여러 번 호출하는 형식으로 쿼리문을 실행시키고 있습니다. Low 나 Mideum, High 레벨의 경우 입력값을 받은 다음에 바로 MySQL_query로 호출하고 있는데 런 식의 방식들을 동적 쿼리라고 합니다.
한마디로 동적 쿼리보단 impossible 레벨처럼 " 파라미터 쿼리 " 에서는 prepare 함수에다가 미리 쿼리 문의 형태를 작성해두며 id부분에서만 bindparam을 해주는데 이럴 경우 DB에서는 어떤 것이 쿼리이고 문자인지를 구분할 수 있기 때문에 우리가 입력했던 SQL injection 구문들을 막을 수 있습니다.
이외에도
java 기반의 " preparestatment " 와. NET 기반의 " sqlCommand, OleDbCommand "을 통해서도 대응할 수가 있습니다.
'IT Security > DVWA(Damn Vulnerable Web App)' 카테고리의 다른 글
[DVWA] XSS(Cross Site Scripting) (0) | 2020.05.12 |
---|---|
[DVWA] Weak Session ID (0) | 2020.05.11 |
[DVWA] insecure CAPTCHA (0) | 2020.04.23 |
[DVWA] File Upload Vulnerability (0) | 2020.04.21 |
[DVWA] File inclusion (0) | 2020.04.20 |