지난 번에 설치한 웹 해킹을 실습할 수 있는 DVWA로 이런 저런 테스트를 하고 있다.
그 테스트 중 두번째가 SQL인젝션인데.. 일단 SQL인젝션 취약점이 발견되면 DB에 저장되어 있는 기업의 주요 기밀은 물론 고객의 개인정보 등 매우 치명적인 정보가 유출될 가능성이 크다.
SQL 인젝션 (SQL Injection) 이란
SQL인젝션은 이용자에게 입력받은 다양한 조건 혹은 정보를 이용해 DB에서 정보를 조회해 이용자의 웹 브라우저에 출력하는 과정에서 발생할 수 있는 소스코드의 취약점을 공격하는 해킹기술이다.
웹서버에서는 이용자의 브라우저에 화면을 출력하는 HTML 및 Java Script 등과 이용자에게 보이지 않는 서버 수준에서 DB에 접속하거나 다른 작업을 위해 수행되는 JSP, PHP 등 서버사이드 프로그램들이 실행되는데 서버사이드 프로그램에서 이용자에게 입력받아 브라우저로 부터 전달받은 정보를 DBMS에 전달할 때 이용자가 입력한 값을 제대로 검증하지 않아 발생하는 취약점을 공격하는 기법이 SQL인젝션이다.
[ 이곳에서 학습한 공격을 일반 웹사이트를 대상으로 시험할 경우 해킹시도로 간주되어 법적 책임을 지게 될 수 있습니다. ]
DVWA의 SQL 인젝션 실습 화면
DVWA에는 SQL 인젝션을 실습할 수 있는 페이지가 제공된다. DVWA에 접속해 왼쪽의 SQL Injection 메뉴를 선택하면 다음과 같은 페이지가 출력된다.
SQL Injection 실습페이지
User ID를 선택하고 Submit 버튼을 누르면 해당 ID의 계정 정보를 보여준다. 다음은 User ID를 2를 선택하고 Submit 버튼을 누른 화면이다.
버프스위트로 POST 요청 조작 실습
그렇다면 SQL인젝션을 시도해보자.
먼저 브라우저의 Proxy를 설정하고 Bup Suite를 실행한 뒤 SQL 인젝션 페이지에 접속한다. 위 화면은 취약점 수준이 Medium으로 설정하면 나온다. 버프스위트의 “Proxy” 탭의 “Intercept” 탭에서 “Intercept is on”으로 설정하고 위 화면에서 “Submit” 버튼을 누른다.
Submit 버튼을 누르고 버프스위트를 보면 “Proxy”탭과 “Intercept” 탭의 색이 바뀌어 있다. 뭔가 브라우저의 요청을 가로채고 대기 중이라는 의미다.
“Raw” 탭을 보면 아래 내용과 같이 가로챈 POST 요청이 보인다.
화면 아래에 id=1 이 보인다. 앞의 화면에서 User ID를 1로 선택한 뒤 Submit 버튼을 눌렀기 때문에 웹서버로 이용자가 선택한 id=1과 Submit 버튼을 눌렀다는 것을 전달하는 요청이다. 버프스위트가 그 요청을 중간에서 가로채어 웹서버로 전달하지 않고 대기중인 것이다.
id= 뒷부분을 위 화면과 같이 [ 1 or 1=1 ]로 바꾸고 “Forward” 버튼을 누른다. 만약 이 조작을 웹서버에 작성되어 있는 서버사이드 프로그램에서 걸러내지 못하고 그대로 DBMS에게 전달이 되면 어떤 결과가 나타날까..??
아래 결과처럼 표시가 된다.
원래는 ID가 1인 admin 의 정보만 보여야 하지만 Gordon 부터 Bod까지 더 많은 이름들이 출력된다. 이 자체가 취약점이다.
이 부분이 이해가 가지 않는다면 관계형데이터베이스에 대해 공부를 더 해야한다. SQL은 관계형데이터베이스의 데이터를 조회하고 저장하고 수정하고 삭제할 수 있는 언어다. 이 SQL을 이해하지 않고는 SQL Injection을 논할 수 없다.
어쨌든 ID가 1이거나 1=1 이 참이므로 이름이 저장된 테이블의 정보를 모두 가져와 출력하는 것이다. 이것이 끝일까? 여기까지 하고 끝이라면 너무 시시하지 않는가?
아니다. SQL인젝션 공격은 이제 시작이다. 일단 이 페이지에서 SQL 인젝션이 가능함을 알았고 이 페이지에서 보여주고자 하는 것 이상의 정보를 DB에서 조회해 출력할 수 있다는 것을 알았다. 몇가지 더 시연을 해보면…
먼저 몇개의 컬럼을 출력할 수 있는지 확인해봐야 한다. 언뜻봐서는 2개 혹은 3개의 데이터를 DB에서 조회해 출력하는 것으로 보인다.
앞으로 돌아가 특정 ID를 선택하고 다시 Submit 버튼을 누른다. 그리고 다시 id를 다음과 같이 조작한다.
뒷 부분에 [ order by 1 ] 을 추가했다.
이 페이지에서 조회하는 데이터 중 첫번째 컬럼으로 정렬하라는 의미다. 에러가 발생하지 않으면 다시 order by 2로 바꿔보고 1씩 증가하면서 에러가 발생하는지 확인한다. 아마도 2개까지 표시가 될 듯하고 3이 되면 다음과 같이 에러가 발생한다.
즉 2개 까지 추가적인 정보를 출력할 수 있는 것이다.
이제 다음과 같이 수정해본다.
union 문을 추가했다. ( union 이 뭔지 모르겠다면 SQL을 공부하러 갔다 오길 바란다.)
그리고 MySQL의 DB이름들을 조회할 수 있는 SQL을 추가했다. [ SELECT schema_name, 2 From information_schema.schemata# ] 맨뒤의 #은 그 뒷부분의 SQL을 주석으로 처리해버리기 위해 추가한 것이다. (이 #은 SQL Injection High Level 에서도 필요하다. High Level에서는 소스를 보면 알겠지만 LIMIT 1 로 조회되는 ID를 1개로 제한을 걸어 #이 없으면 해킹에 필요한 모든 정보를 얻을 수 없다.)아마 없어도 문제가 생기진 않을 것이다. 2는 그냥 의미없이 추가한 것이다. DB 목록이 저장되는 information_schema.schemata에서 필요한 정보가 있다면 해당 컬럼을 추가하면 된다.
이제 DB의 목록이 출력된다.
phpmyadmin 도 보이고 dvwa, bWAPP DB도 보인다. DB명을 알았으므로 특정 DB의 테이블 목록도 조회가 가능하며 그 테이블 중 중요 정보가 저장된 것 같은 테이블의 데이터도 조회해 볼 수 있다. 단, 한번에 2개의 컬럼까지만 가능할 가능성이 높다.
그리고 이 페이지에서 DB에 접속하는 계정의 권한에 다라 DBMS 자체의 계정 정보도 조회가 가능하다.
다음과 같이 ID를 조작한다.
이 SQL은 MySQL DBMS의 user 계정 정보와 계정의 암호화된 비밀번호를 조회하는 SQL이다.
[ SELECT USER, AUTHENTICATION_STRING FROM MYSQL.USER ]가 추가로 보인다.
예상한 대로 MySQL 자체의 사용자 계정명과 암호화 되었지만 비밀번호가 보인다. 이 계정은 DB를 관리하는 관리자들이 사용하는 계정이고 웹서버에서 DB에 접소할 때 사용할 수도 있는… 즉 이용자에게 노출되어어서는 안되는 계정정보다.
그 외에도 해커가 알고 있는 지식의 범주만큼 더 다양한 공격이 가능하다.