본문 바로가기

웹 해킹

웹 해킹 공부일기장 4 - 2 (SQL Injection 정리)

이때까지 SQL Injection으로 인증우회, 데이터 추출하는 방법에 대해 알아보고 공부하였습니다.

 

데이터를 추출하는 방법에는 UNION SQL Injection, Error Based SQL Injection, Blind SQL Injection

이렇게 3가지 기법을 알아보았습니다.

SQL Injection으로 데이터를 추출하는 것은 결국 우리가 원하는 select 문을 실행하게 하는 것입니다.

각 기법의 특징이 다르기 때문에 주어진 상황에 맞는 기법들을 사용하여야 합니다.

 

SQL Injection 기법 총 정리

 

1. UNION SQL Injection

유니온 SQLI는 select를 한번더 사용할 수 있게 해주며 select한 두 개의 결과 테이블을 합쳐 결과를 가져와 출력시키는 기법입니다. 이때 데이터베이스에 존재하는 원하는 데이터를 가져올 수 있습니다.

그렇기 때문에 select한 결과가 우리가 볼 수 있게 출력이 되어야합니다.

 

1) 사용 가능한 경우

  • 질의 결과가 화면에 출력될 경우

 

2) 사용하는 문법

  • union 문법 (select 결과를 합침.)
  • order by 절 (select 결과를 정렬함. 컬럼 또는 인덱스로 정렬)

3) process(절차)

  • SQL Injection 포인트 찾기 (SQL 질의 결과가 화면에 출력되는 지 확인)
  • 컬럼 개수 구하기 (order by [index] 사용)
  • 어떤 컬럼이 출력되는 지 확인 (union select [1,..., n])
  • 공격 format 만들기
  • 데이터베이스 이름 출력
  • 테이블 이름 출력
  • 컬럼 이름 출력
  • 데이터 추출

 

2. Error Based SQL Injection

에러 베이스 SQLI 는 에러 메시지가 화면에 출력되는 경우 에러메시지에 우리가 원하는 데이터를 포함시켜 출력시키게 만드는 기법입니다.

그렇기 때문에 이 경우도 에러 메시지가 출력이 되어야 사용할 수 있습니다.

 

1) 사용 가능한 경우

  • SQL 에러가 발생하며 에러 메시지가 출력되는 경우
  • SQL 문법 에러가 아닌 로직 에러를 발생시킬 수 있는 경우

 

2) 사용하는 문법

  • extractvalue 함수 (두번째 인자인 XPATH 부분에 올바르지 않은 XPATH 표현식을 넣어 에러 발생)
  • updatexml 함수 (두번째 인자인 XPATH 부분에 올바르지 않은 XPATH 표현식을 넣어 에러 발생)
  • concat 함수 (인자로 받은 문자를 합쳐줌. 앞에 ':'를 합쳐줘서 올바르지 않은 XPATH 표현식을 만들어 줌)

updatexml 함수를 간단히 설명하면 3개의 인자를 받고, 첫번째에는 xml, 두번째는 xpath 표현식, 세번째는 변경할 xml 을 넣어주면

첫번째 xml에서 xpath 표현식에 해당하는 부분을 세번째 인자로 넣은 xml로 변경시켜줍니다.

 

3) process (절차)

  • SQL Injection 포인트 찾기 (에러 메시지가 출력되는 지 확인)
  • 에러 발생시키는 함수 확인 (에러 발생시키는 함수 사용 가능한 지 확인)
  • 공격 format 만들기 (원하는 SQL 문을 입력하면 공격을 성공할 수 있게 기본적인 틀 만들기)
  • 데이터베이스 이름 출력
  • 테이블 이름 출력
  • 컬럼 이름 출력
  • 데이터 추출

 

3. Blind SQL Injection

참과 거짓의 결과가 다른 곳에서 원하는 데이터의 값에 대하여 참인지 비교하여 결과를 보고 데이터값을 추출하는 기법.

SQL Injection이 가능한 모든 곳에서 사용이 가능하지만, 한글자씩 알아낸다는 특징으로 오래걸리기 때문에 UNION SQLI와 Error Based SQLI 를 사용하지 못하는 곳에 사용하는 것이 좋음.

 

1) 사용 가능한 경우

  • SQL Injection이 일어나는 모든 경우
  • 참과 거짓에 따라 응답이 다른 경우

2) 사용하는 문법

  • ascii, ord 함수 (원하는 문자를 아스키 숫자로 표현하여 보다 빠르게 문자를 찾기 위함)
  • substr 함수 (문자에서 원하는 부분만 선택하는 함수로 한글자씩 선택해 비교)
  • 이진 탐색 (숫자로 비교하여 중앙값보다 큰지 작은지 비교하여 전체의 값을 찾는 것보다 빠르게 문자를 찾기 위함)

3) process (절차)

  • SQL Injection 포인트 찾기 (참과 거짓의 조건에 따라 응답에 차이가 있는지 확인)
  • select 문이 사용가능한지 확인 (함수를 사용하며 select 사용가능한지 확인)
  • 공격 format 만들기 (원하는 SQL 문을 입력하면 공격을 성공할 수 있게 기본적인 틀 만들기)
  • 데이터베이스 이름 출력
  • 테이블 이름 출력
  • 컬럼 이름 출력
  • 데이터 추출

이렇게 한달동안 배운 SQL Injection에 대해 정리를 해보았고, 마지막으로 SQL Injection에 대한 대응 방안도 알아보겠습니다.

 

우리는 공격을 하려고 SQL Injection을 배운 것이 아닌 SQL Injection 취약점이 있다는 것을 찾고 취약점을 막기위해 위와 같은 기법으로 해킹을 시도한 것이기 때문에 대응 방법도 당연히 알아야합니다.

 

 

SQL Injection 대응 방법

1. prepared statement 사용

prepared statement는 준비된 문장이라는 뜻으로

미리 쿼리를 준비해놓고 준비된 쿼리 틀안에 매개변수를 넣어 SQL이 실행되는 방식입니다.

 

즉, select * from member where id=? 식으로 쿼리를 만들어 놓고

?에 원하는 매개변수를 넣어 SQL이 실행됩니다. (?는 약속 입니다. 매개변수를 넣고 싶은 곳에 ? 입력)

 

이렇게 하면, 01001010_____10011010 이런식으로 미리 쿼리를 컴파일 해놓은 것을 저장해놓았다가

매개변수를 넣고 실행을 하면 빈칸에 원하는 값이 들어가 실행이 됩니다.

그래서 어떠한 값! sql 문법이라도 하나의 문자열로 인식하여 SQL Injection이 실행되지 않습니다.

//php prepared statement 예시

// MySQL 서버 정보
$servername = "your_servername";
$username = "your_username";
$password = "your_password";
$dbname = "your_dbname";

// MySQLi 연결 생성
$conn = new mysqli($servername, $username, $password, $dbname);

// 연결 확인
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// 사용자 입력을 받는 대신 매개변수를 사용하는 Prepared Statement
$sql = "SELECT * FROM your_table WHERE column_name = ?";
$stmt = $conn->prepare($sql);

// 매개변수 값
$parameter = "some_value";

// 매개변수를 바인딩
$stmt->bind_param("s", $parameter);

// Prepared Statement 실행
$stmt->execute();

// 결과 가져오기
$result = $stmt->get_result();

// 결과를 배열로 변환
$rows = $result->fetch_all(MYSQLI_ASSOC);

// 연결 종료
$stmt->close();
$conn->close();

// 결과 출력
print_r($rows);

 

사실 prepared statement는 미리 쿼리를 컴파일해서 저장해놓기 때문에 쿼리를 실행할 때마다 컴파일하는 방식보다 속도가 빠릅니다.

그래서 만들어진 것이지만, 미리 컴파일하는 부분에서 우리가 입력한 값이 단순 문자열로 인식되기때문에 SQL Injectioin을 원천적으로 

막을 수 있습니다.

 

이렇게 간단한 방법으로 SQL Injection을 막을 수 있습니다.

그렇기 때문에 속도도 빠르게 해주며 SQL Injection을 원천적으로 막을 수 있기때문에 거의 모든곳에서 prepared statement를 사용하고 있습니다.

 

엥?? 그럼 이때까지 사용할 수도 없는 SQL Injection을 왜 배운 것일까요?

1) 잘 못 쓴 경우 SQL Injection 취약점이 생길 수 있습니다.

  • 매개변수 유형과 일치하지 않는 경우
  • 사용자 입력을 적절하게 처리하지 않은 경우

그렇기 때문에 prepared statement를 올바르게 사용하여야 합니다.

 

2) prepared statement를 사용을 못하는 곳이 있습니다.

  • order by 절
  • table 이름, column 이름

위의 경우에는 prepared statement를 사용하지 못하기 때문에 사용자의 입력이 해당 경우에 들어갈 것 같은 곳은 반드시 확인해봐야합니다.

 

2. white list filtering 사용

필터링은 일단 단어를 제어할 때 사용하는 것으로,

필터링의 종류에는 화이트 리스트 필터링 & 블랙 리스트 필터링이 있습니다.

 

화이트 리스트 필터링: 특정 단어만 사용할 수 있게 하는 것

블랙 리스트 필터링: 특정 단어를 사용 못하게 하는 것

 

블랙리스트 필터링은 특정 단어를 사용 못하게 하는 것으로 생각지도 못한 단어로 SQL Injection을 가능하게 할 수 있기 때문에 확실하게 해당 부분에서 화이트 리스트 필터링을 사용하여 우리가 생각한 범위 내에서 해당 단어만 사용할 수 있게 해야합니다.

 

즉, prepared statement를 사용하지 못하는 컬럼, 테이블 같은 곳에 우리가 생각한 올바른 입력값만 사용 가능하게 만들어야 합니다.