[DVWA] SQL 인젝션 공격
<SQL Injection 공격 구문>
Security Level : low
1. WHERE 구문 우회
1이라는 값을 넣으면 아이디가 1인 사용자의 정보가 출력됩니다.
SQL 인젝션 공격에 취약한지 알아보는 가장 기본적인 방법은 작은 따옴표를 입력해보는 것입니다. 취약한 페이지의 경우 아래 그림과 같이 SQL 관련 에러가 발생합니다.
소스 코드를 보면 id라는 변수는 이미 작은 따옴표로 둘러싸여져 있기 때문에 하나 더 들어오게 되면 작은 따옴표가 총 3개가 되면서 에러가 발생하게 되는 것입니다. 이렇게 SQL Query문이 잘못되어 에러가 발생하면 그 페이지는 SQL Query문을 이용하여 처리가 된다는 뜻이 됩니다. 그리고 입력한 값으로 인해 SQL Query문이 바뀌었기 때문에 SQL Query문을 조작할 수 있다는 뜻입니다.
1’ or ’1’=’1를 입력해보면 테이블에 모든 정보가 출력되었습니다.
2. 칼럼 개수 알아내기
union을 사용하기 위해서는 select문의 칼럼 개수와 union 뒤에 select문에서 요청하는 칼럼 수가 같아야만 합니다. 따라서 먼저 원래 쿼리문이 몇 개의 칼럼을 리턴하는지 알아내야 합니다. 먼저 1' union select 1# 이라고 입력합니다.
실행을 해봤더니 칼럼 수가 맞지 않는다는 에러가 발생했습니다.
1' union select 1,1#를 입력하니 에러가 발생하지 않고 ID 1의 정보와 입력했던 1, 1이 같이 출력되었습니다.
그리고 order by라는 구문으로도 칼럼 개수를 알아낼 수 있습니다. order by는 칼럼의 개수보다 큰 값을 입력하면 에러를 발생시킵니다. 먼저 1' order by 1# 입력하니 에러가 발생하지 않고 결과가 출력되었습니다.
1' order by 2# 역시 에러가 발생하지 않았습니다.
1' order by 3#을 입력하니 세 번째 칼럼은 알 수가 없다고 출력되었습니다. 이 말은 칼럼의 개수가 2개라는 것입니다.
3. UNION 공격
- 데이터베이스 명 조회
1' union select schema_name,1 from information_schema.schemata #
- dvwa 데이터베이스의 테이블 명 조회
1' union select table_schema, table_name from information_schema.tables where table_schema = 'dvwa' #
- users 테이블 칼럼 조회
1' union select table_name, column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users'#
1' union select user,password from users#
패스워드가 평문이 아닌 MD5라는 해시값을 사용하고 있는데 이 경우는 해시값을 쉽게 복원할 수 있습니다.
4. 블라인드 SQL 인젝션
1을 입력하면 아이디가 존재한다고만 알려주고 있습니다.
6을 입력했을 때는 사용자가 없다고 알려줍니다.
1' AND 1=1#라고 입력했더니 아이디가 있다고 나옵니다.
1' AND 1=2#을 입력했더니 사용자가 존재하지 않는다고 합니다. 이것으로 1은 1, 1은 2와 같은 조건이 실행되고 있다는 것을 알 수 있습니다. 이 조건으로 admin이라는 사용자가 존재하나 라는 식으로 명제를 제시하고 뒤에 AND를 붙여 명제가 참인지 거짓인지 알 수 있습니다.
참, 거짓 조건에 따라 DVWA에서는 응답 메시지가 달라집니다. 응답 시간을 확인하기 위해서 브라우저에서 F11을 눌러 개발자 창이 뜹니다. 여기서 네트워크 탭을 띄우고 5' AND SLEEP(5)#을 입력합니다. 5초 정도가 걸렸습니다.
존재하지 않는 사용자인 ID 6을 넣고 했을 때는 70ms로 응답이 바로 되었습니다.
Security Level : medium
이번에는 아이디를 입력하는 것이 아니라 정해진 값을 선택하도록 되어 있습니다.
소스 코드를 보면 low단계에서는 작은 따옴표가 있었는데 지금은 작은 따옴표 없이 id를 처리하고 있습니다. 1 or 1=1과 같이 숫자만 입력하면 결과를 출력할 수 있습니다.
Security Level : high
링크를 클릭하면 새로운 창이 뜹니다.
아이디를 입력하면 결과가 원래 페이지에 표시되는 구조입니다. 하지만 GUI의 변화로는 SQL 인젝션 공격을 막을 수 없습니다.
소스 코드를 보면 LIMIT 이라는 키워드를 이용해서 무조건 하나만 출력되도록 막고 있습니다. 하지만 id 부분 뒤에 주석 처리를 해버리면 이거 역시 SQL 인젝션 공격을 방어가 어렵습니다.
Security Level : impossible
SQL 인젝션 대응을 위해서는 입력값을 확실하게 검증해야 합니다. 소스 코드를 보면 id 파라미터의 값을 가져오고 id가 숫자인지 확인합니다. 그리고 prepare, bindParam, execute와 같은 함수를 여러 번 호출하는 형태로 쿼리문을 실행하고 있습니다. bindParam 함수로 데이터베이스는 어떤 것이 코드이고 어떤 것이 데이터인지 알 수 있고, 값을 온전히 문자열로만 처리하기 때문에 SQL 인젝션 공격을 막을 수 있습니다.