상세 컨텐츠

본문 제목

DVWA : SQL Injection - Medium level

Vulnerability Assessment/Web Application

by DarkSoul.Story 2025. 1. 6. 23:09

본문

반응형
이 문서에 포함된 어떠한 내용도 불법적이거나 비윤리적인 목적으로 보안 도구나 방법론을 사용하도록 가르치거나 장려하지 않습니다. 항상 책임감 있는 태도로 행동하세요. 여기에 설명된 도구나 기법을 사용하기 전에 개인 테스트 환경 또는 허가를 받았는지 확인하세요.

 

[ 환경 ]

DVWA v1.9
Burp Suite Community Edition v2024.11.2

 

1.  Source code analysis

[그림 1] Medium level Source code

 

이 코드는 사용자가 제출한 id를 기준으로 데이터베이스에서 사용자 정보를 조회하여 출력한다.

사용자 입력 확인

if( isset( $_POST[ 'Submit' ] ) ) {
  • POST 메소드를 이용하여 사용자가 제출한 폼에서 데이터를 처리한다.

사용자 입력값 가져오기

$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );
  • $id $_POST'id' ]; 사용자가 제출한 id 값을 가져오며, 이 값은 사용자의 입력으로, SQL 쿼리에 사용된다.
  • mysql_real_escape_string( ) : SQL 인젝션 공격을 방지하려는 목적으로, 입력값에서 SQL에 사용될 수 있는 특수문자를 이스케이프 처리한다. (완벽한 보호책은 아님)

데이터베이스 조회

$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
  • 사용자가 입력한 $id 값을 포함한 쿼리를 생성한다.
  • 예: 사용자가 1을 입력하면 쿼리는 SELECT first_name, last_name FROM users WHERE user_id = 1; 과 같이 생성된다.
  • mysql_query( ) : SQL 쿼리를 실행하며, 실행 중 오류가 발생하면 mysql_error()를 통해 디버깅 정보를 출력한다.

결과 가져오기

$num = mysql_numrows( $result );
$i   = 0;
while( $i < $num ) {
   $first = mysql_result( $result, $i, "first_name" );
   $last  = mysql_result( $result, $i, "last_name" );

    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

   $i++;
}
  • mysql_numrows(  ) : 쿼리 결과로 반환된 행(row)의 수를 가져온다.
  • while 루프 : 결과가 여러 행일 경우, 각 행의 데이터를 반복적으로 처리한다.
  • mysql_result( ) 특정 행($i)의 열 값을 가져오며, 예를들어 $i=0일 때 첫 번째 행의 first_name 값을 가져온다.
  • 사용자에게 id, first_name, last_name 정보를 출력한다.

ㅁ 보안상의 문제점

취약한 SQL 쿼리 생성

$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
  • 숫자가 아닌 값을 삽입하거나, SQL 코드를 삽입할 경우 공격이 가능하다.
  • 예: id=1 OR 1=1을 입력하면 모든 데이터가 반환된다.
SELECT first_name, last_name FROM users WHERE user_id = 1 OR 1=1;

 

mysql_real_escape_string( )의 한계

  •  mysql_real_escape_string(  )은 문자열 이스케이프 처리만 제공하며, 숫자형 값에 대한 보호는 불완전하다.
  • 예: id=1 OR 1=1처럼 숫자로 처리될 경우 이스케이프 처리가 무의미하다.

디버깅 정보 노출

  • 오류 발생 시 mysql_error()를 통해 민감한 정보(예: 데이터베이스 구조)가 노출될 수 있다.
die('<pre>' . mysql_error() . '</pre>');

 

구식 데이터베이스 함수 사용

  • mysql_* 함수는 더 이상 PHP에서 지원되지 않으며, PDO 또는 MySQLi를 사용하는 것이 권장한다.

입력값 검증 부족

  • 사용자 입력값 $id에 대한 타입 확인이나 유효성 검증이 이루어지지 않는다.
  • 예: 숫자만 허용해야 하지만 문자열 또는 특수문자가 포함된 입력도 처리된다.

 

3. Practical exercises

소스코드에서 살펴보았듯이 mysql_real_escape_string() 함수를 이용하여, SQL Injection 공격을 보호하고 있다. 그러나 SQL 쿼리가 파라미터 주의에 따옴표가 없는 SQL 쿼리로 인해 쿼리가 변경되는 것을 완전히 보호하지 못한다. Medium level에서는 기존 텍스트 상자가 드롭다운 목록으로 변경되었고, POST를 사용하여 전송하기 때문에 브라우저에서 직접 SQL Injection 공격을 진행 하기는 어렵다. Burp Suite로 전송되는 드래픽을 Intercept 해보자.

[그림 2] 텍스트 상자가 드롭다운 목록으로 변경

 

Burp Suite로 전송되는 드래픽을 Intercept 해보자. Medium level에서도 id 파라미터에 사용자가 제출한 폼에 데이터를 넣은 후에 전송하는 것을 확인할 수 있다. Low level과 다른점은 POST로 전송하고 있다는 것이다. 

[그림 3] 사용자가 제출한 폼에 대한 결과 (Burp Suite Intercept)

 

Low level에서와 동일하게 id 파라미터에 작은따옴표(')를 입력해서 전송하면, SQL 쿼리에서 구문 오류가 발생하여 오류 메시지를 출력하는것을 확인할 수 있다. 이는 여전히 id 파라미터가 SQL Injection에 취약하다는 의미이다.

[그림 4] SQL 쿼리에서 구문 오류가 발생하여 오류 메시지 출력

 

id 파라미터가 SQL Injection에 취약하다는것을 확인하였으나, 이전과 동일한 명령을 실행할 수 있다. Medium level에서는 Low level과 다르게, mysql_real_escape_string(  )함수가 문자열에 대한 이스케이프 처리만 제공하여 숫자형 값에 대한 보호는 불완전하기 때문에 Paylod는 ' OR 1=1#가 아닌 OR 1=1가 된다. 

[그림 5] SQL Injection 공격 성공

 

ㅁ 데이터베이스 버전 확인

union select null, version() #

[그림6] 데이터베이스 버전 확인

 

ㅁ 데이터베이스의 메타데이터를 조회하여, 테이블 이름 확인

UNION SELECT schema_name, NULL FROM information_schema.schemata #

[그림 7] 데이터베이스의 메타데이터를 조회하여, 테이블 이름 확인

 

ㅁ User 테이블에서 사용자 이름과 비밀번호 확인

UNION SELECT user, password FROM users #

[그림 8] User 테이블에서 사용자 이름과 비밀번호 확인

반응형

관련글 더보기