티스토리 뷰

반응형

이번 세션은 Injection 취약점 중 SQL Injection에 대한 내용이다.

세션 내용은 기본적인 Query 지식을 시작으로 간단한 SQL Injection 내용을 순으로 다루고 있다.

 

앞 부분에서 다루고 있는 Query에 대한 내용은 간단히 질문에 해당하는 쿼리구문을 입력만 하면 되는 문제들이므로 넘어가고, 후반부의 SQL Injection 부분을 다뤄본다. 첫 번째 문제는 주어진 쿼리구문이 SQL Injection이 발생하도록 3개의 셀렉트 박스에서 값을 선택해서 실행해보도록 디자인 되어 있다.

 

쿼리구문이 항상 참이 되도록 아래와 같이 선택하여 문제를 통과한다.

  • Smith'
  • or
  • '1'='1

 

 

두 번째는 직접 쿼리를 입력하도록 좀 더 어렵게 퀴즈가 나왔다. 

이때 두 필드 중 한개의 필드에서만 인젝션이 가능하다고 나와 있으니, 우선 어떤 필드를 이용해야 할지 확인해본다.

 

우선 각 항목별로 특수기호 등을 포함하여 오류를 유도해본다. 이때 구문에러 내용을 확인하여 어떤 필드를 사용할지 확인해 본다.

Login_Count 필드에 특수기호 추가
User_Id 필드에 특수기호 추가

 

 

이제 두 번째 필드가 SQL Injection에 이용될 수 있는 것을 확인하였으니, 이제 Injection 구문을 추가해보면 이번 퀴즈도 통과다.

  • Login_Count : 1
  • User_Id : 1 or 'a'='a'

 

지금부터는 공격 사례를 들어 퀴즈를 제공하고 있다.

이번 퀴즈에서는 SQL Injection을 통해 타인의 Salary 정보를 확인하는 것이다.

 

이전에 진행했던 것과 큰 차이가 없이, Where 절이 무조건 True가 나오게 하여 모든 데이터가 나오도록 필드를 입력한다.

  • 3SL99A' or '1'='1

 

다음은 나의 Salary를 가장 높도록 데이터베이스를 변경하기 위한 SQL Injection 공격을 시도해야 한다.

 

현재 기능은 조회 기능이므로 값을 변경하기 위한 UPDATE 구문을 사용하기 위해서, 멀티 쿼리가 실행될 수 있도록 필드를 구성한다.

  • 3SL99A'; update employees set salary=90000 where userid=‘37648

 

마지막 퀴즈는 지금까지 진행했던 Injection 공격 흔적을 제거하는 내용이다.

 

우선 기록된 내용에 Injection 공격구문이 포함되어 있지 않은 일반 쿼리가 조회되었음으로 로그기록을 변경하도록 쿼리를 변조해 본다.

  • '; update access_log set ACTION = 'SELECT * FROM employees WHERE last_name = "Smith" AND auth_tan = "3SL99A”’ where 'a'='a

 

이 방법이 아닌 것으로 보여, 지문을 다시 확인해보니 데이터를 변조하는 것이 아닌 삭제를 요청하는 것으로 보인다.

  • '; delete from access_log where 'a' = 'a

 

 

하지만 질문에서는 레코드 삭제가 아니라 아예 테이블을 삭제해버리는 것을 희망하는 것으로 보인다.

  • '; drop table access_log; select * from access_log where 'a'='a

 

이로서 모든 퀴즈를 통과하였다.

 

 

이제 마지막 퀴즈에 대한 소스코드를 한번 확인해보자.

src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10.java

 

여기서 외부 입력값(action_string)을 쿼리에 문자열 결합으로 다이나믹 쿼리를 생성하고 있으며, 입력값 또한 별도의 필터링 적용없이 사용되고 있다. 이는 전형적인 SQL Injection에서 취약한 쿼리이다. 기본적으로 SQL Injection이 발생하는 취약코드는 외부 입력값을 검증없이 다이나믹 쿼리에 적용하는 것이다.

 

이를 안전하게 사용하기 위해서 대표적으로 아래와 같은 방법 등이 사용된다. 

  1. JPA와 같은 ORM을 사용하여 입력값이 자동으로 파라미터화 및 바인딩되도록 구성
  2. 쿼리 실행 객체를 Statement 대신 PreparedStatement를 사용하고, 이때 입력값을 적절한 Set 메서드를 사용하여 쿼리 생성
  3. 외부 입력값 내 쿼리를 변조할 수 있는 특수기호 또는 예약어가 포함되어 있는지 필터링을 적용하여 입력값 검증

여기서 조심해야 할 것은 ORM을 사용하더라도 여전히 다이나믹 쿼리를 지원하므로 다이나믹 쿼리를 사용하지 않아야 하고, 만약 외부 입력값을 포함하여 다이나믹 쿼리를 사용해야 한다면 입력값을 필터링 후에 사용되어야 한다.  그리고 PreparedStatement를 사용하더라도, 문자열 결합을 통해 쿼리를 생성해버리면 무의미해지게 되므로, 반드시 외부 입력값을 Set 메서드로 바인딩해야 한다. 상황에 따라 입력값이 다이나믹 쿼리에 포함되어야만 하는 경우가 있는데, 이 때는 필터링을 적용하는 방법을 주로 사용한다. 하지만, 서비스 목적 달성을 위해 어떤 키워드에 대해서 필터링 할 것인지는, 비즈니스 목적에 맞춰 필터링을 커스터마이징 해야 한다. 되도록 정규식으로 정할 수 있는 룰을 만드는 것이 중요하다.

 

 

 

반응형
댓글
반응형
최근에 올라온 글
Total
Today
Yesterday