[Dreamhack-web] SQL Injection-5

박정원·2023년 3월 21일

보안공부

목록 보기
14/43

Out of DBMS

  • DBMS에서 제공하는 특별한 함수 또는 기능 등을 이용해 파일 시스템, 네트워크, 심지어는 OS 명령어 등에도 접근할 수 있음 -> SQL Injection을 단순히 데이터베이스의 정보를 획득하는 것 뿐만 아니라 파일 시스템, 네트워크, 시스템 모두 장악할 수 있음

Out of DBMS: MySQL

  • MySQL에서 파일 관련된 작업을 할 때에는 mysql 권한으로 수행되며, "my.cnf" 설정 파일의 secure_file_priv 값에 영향을 받음
    my.cnf
    [mysqld]
    secure_file_priv= "" # 미설정, 기본 설정 값으로 설정됨
    secure_file_priv= "/tmp" # 해당 디렉터리 하위 경로에만 접근 가능함
    secure_file_priv= "" # mysql의 권한이 가능한 모든 경로에 접근이 가능함
    secure_file_priv= NULL # 기능이 비활성화됨
    기본적으로 secure_file_priv의 값은 /var/lib/mysql-files/임.

load_file

  • load_file 함수는 인자로 전달된 파일을 읽고, 출력함. 이때 전달되는 파일은 전체 경로를 입력해야 하며 해당 파일에 접근 권한이 있어야 함
    # echo test1234 > /var/lib/mysql-files/test
    mysql> select load_file('/var/lib/mysql-files/test');
    --> test1234

into outfile

  • SELECT ... INTO 형식의 쿼리는 쿼리 결과를 변수나 파일에 쓸 수 있음. 만약 secure_file_priv의 값이 올바르지 않아 임의 경로에서 파일 작업을 수행할 수 있다면 웹셸을 업로드하는 등의 공격이 가능함
  1. SELECT ... INTO를 이용한 파일 작성
    SELECT ... INTO var_list # column 값을 변수에 저장
    SELECT ... INTO OUTFILE 'filename' # 쿼리 결과의 rows 값을 파일에 저장
    SELECT ... INTO DUMPFILE 'filename' # 쿼리 결과(single row)를 파일에 저장
  2. SELECT ... INTO를 이용한 웹셸 작성
    mysql> select '<?= 'ls'?>' into outfile '/tmp/a.php';

Out of DBMS: MSSQL

  • MSSQL에서는 xp_cmdshell 기능을 이용해 OS 명령어를 실행할 수 있음
    SELECT * FROM sys.configurations WHERE name = 'xp_cmdshell'
    해당 쿼리의 실행 결과에서 1이 반환되면 활성화, 0이라면 비활성화 상태를 의미함
    EXEC xp_cmdshell "net user";
    EXEC master.dbo.xp_cmdshell 'ping 127.0.0.1';
    만약 xp_cmdshell 기능이 활성화되어 있는 경우, 위와 같이 OS 명령어를 실행할 수 있음

주의 사항

DBMS 권한 문제 주의사항

DBMS 애플리케이션 작동 권한

  • 리눅스 서버에서는 이용자 별로 권한을 나누어 관리함 -> 서버에서 DBMS를 작동할 때에는 DBMS 전용 계정을 만들어 사용해야 함
  • 계정을 분리하지 않을 경우 앞서 다룬 Out of DBMS 내용과 같이 OS 명령어를 실행할 수 있게 됨

DBMS 계정 권한

  • 일반적으로 DBMS 내부에 계정과 권한이 존재함
  • 접속 계정을 분리하지 않으면 서비스에서 사용하는 DBMS 계정으로 타 데이터베이스에 접근할 수 있음 -> 서비스 및 기능 별로 계정을 생성해 사용해야 함

DBMS 문자열 비교 주의 사항

  • 각각의 DBMS는 문자열을 비교하는 방법이 서로 다름, 이로 인해 개발자의 의도와 다르게 동작하는 경우가 존재
    <?php
    // $input = "Admin"; #대소문자 구분
    // $input = "admin "; # 공백 문자로 끝나는 문자열 비교
    if($input === "admin") die("can't account lookup");
    /*
    DBMS
    uid: admin, account_info: secret
    ...
    */
    echo query("select account_info from users where uid='{$input}';");

    대소문자 구분

  • 일부 DBMS에서는 비교 연산에서 대소문자를 구분하지 않음
    mysql> select 'a' = 'A';
    1
    > select 1 from test where 'a'='A';
    1
    소문자와 대문자를 비교한 연산에서 참을 반환하는 것을 알 수 있음

DBMS 다중 쿼리 주의 사항

  • 다중 쿼리는 다음 예시와 같이 하나의 요청에 다수의 쿼리 구문을 사용하는 것을 의미함
    SELECT * from users where uid=''; INSERT users values(...);
  • 대부분의 웹 애플리케이션은 DBMS에 쿼리를 전송할 때 다중 쿼리를 지원하지 않으므로, 공격에 제약이 생김

다중 쿼리를 이용한 예시

<?php
	$db1 = new PDO('sqlite:test1.db');
    $db2 = new PDO('sqlite:test2.db');
    $query = 'select 1234;create table test(test int);';
    $db1->query($query);
    $db2->exec($query);
?>

위의 코드는 PHP의 PHP Data Objects를 사용해 다중 쿼리를 실행하는 예제코드임
PDO의 query 함수는 다중 쿼리를 지원하지 않고, exec 함수에서는 다중 쿼리를 실행함

$php test.php
$ ls -al test1.db test2.db
-rw-r--r-- 1 test test    0 Apr 29 11:21 test1.db # create table이 실행되지 않음
-rw-r--r-- 1 test test 2048 Apr 29 11:20 test2.db # create table이 실행됨

따라서 실행 결과를 보면 "test1.db"는 크기가 0임을 확인할 수 있고, "test2.db" 파일의 크기는 2048임을 볼 수 있으며, 다중 쿼리가 실행되었음을 알 수 있음

profile
보안, 프런트엔드 공부 중!

0개의 댓글