[OWASP Top 10 2021] 03 - Injection (주입)

·2025년 8월 8일
1

OWASP Top 10 2021

목록 보기
3/10

03 - Injection

https://owasp.org/Top10/A03_2021-Injection/

개요

OWASP Top 10 2021 중 3위로 올라간 Injection (주입)이다.

  • 애플리케이션의 94%가 어떤 형태로든 주입 공격을 테스트했으며. 최대 발생률은 19%, 평균 발생률은 3%, 발생 횟수는 27만 4천 회이다.
  • 거의 모든 유형의 인젝션 (SQL Injection, NoSQL Injection, OS Command Injection 등) 공격이 포함된다.
  • 2021년부터는 OWASP가 XSS를 Injection의 한 종류로 포함시켰다.
  • 신뢰할 수 없는 입력값이 코드, 쿼리, 명령어 등으로 해석되거나 실행될 수 있는 경우 발생한다.

구체적 발생 예시

  • 사용자 입력이 검증, 필터링, 정제되지 않았을 때 발생하기 쉽다.
  • 동적 커리(코드 실행 중 쿼리 문장을 만들어 내는 방식)나 파라미터가 없는 호출(쿼리 안에 입력값이 직접 들어가서 실행되는 것)을 그대로 실행하는 경우 발생한다.
  • ORM(Object Relational Mapping, 객체 지향 언어에서 DB를 쉽게 다루기 위해 중간에 자동으로 SQL을 만들어주는 기술이다.) 기반 검색에서 악의적인 데이터가 그대로 사용될 때 발생한다.

공격 시나리오 예시

String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + "'";
  • 이 입력에서 id파라미터에 ' OR '1'='1 등을 넣으면 모든 레코드가 노출 가능하다.
Query HQLQuery = session.createQuery("FROM accounts WHERE custID='" + request.getParameter("id") + "'");
  • Hibernate(java에서 가장 많이 쓰이는 ORM 라이브러리) 기반 ORM에서 다음과 같이 취약한 HQL을 사용하는 경우도 공격자가 id값을 조작하면 데이터베이스를 조회 또는 조작할 수 있다.

방지 방법

  • 안전한 API 사용 또는 파라미터화된 쿼리 활용
    • 입력값을 쿼리에 직접 집어넣지 말고, 미리 자리를 지정해두고(?등 활용) 그 자리에 넣는 방식으로 처리한다.
    • ORM 도구도 도움이 되지만, 스토어드 프로시저 형태로도 데이터 병합이 발생할 수 있어 주의가 필요하다.
  • 서버 측 화이트리스트(허용된 값만 통과시키는 방식) 기반 입력 검증
    • 하지만 모든 상황에 허용값을 정의하기 어렵고, 예상 못한 우회 방법이 있을 수 있다. 화이트리스트 만으로는 충분하지 않을 수 있으니 주의한다.
  • 동적 쿼리 사용 시 특수문자 이스케이핑(문법을 깨트리는 특수기호를 문자로 취급하게 만드는 작업)
    • 단, 테이블명이나 컬럼명 등 구조적 요소는 이스케이프가 불가능하기에, 이런 구조를 사용자가 직접 조작하는 것은 여전히 위험하다.

실습 환경

  • DOKER
  • DVWA (SQL Injection)

문제 설명

웹 애플리케이션의 ID 입력란에 SQL Injection 페이로드를 삽입하여, 데이터베이스 users 테이블에 저장된 모든 레코드를 화면에 출력한다.

공격 과정 요약

low

 $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
  • 소스 코드를 확인해보면 파라미터 없는 호출을 이용하여, 사용자의 입력을 그대로 대입하고 있다.
  • ' OR 1=1; # 을 입력하여 SQL Injection 공격을 시도한다.
  • 이는 $id에 그대로 삽입되는 것으로, SELECT first_name, last_name FROM users WHERE user_id = '' OR 1=1; #'; 가 된다.
  • 성공적으로 테이블에 저장된 레코드를 확인할 수 있다.

medium

  • 직접 USER ID를 입력할 수 있던 LOW와 다르게, MEDIUM은 아예 입력창이 없다.
  • 따라서 Burp Suite 를 이용하여 직접 GET 파라미터를 조작해야 한다.
  • Burp Suite 애서 요청 바디를 확인해 보면 id=1&Submit=Submit 데이터가 존재한다.
  • 값을 바꿔 id=1 OR 1=1 #&Submit=Submit 을 입력해 주었더니 성공적으로 테이블에 저장된 레코드를 확인할 수 있다.

high

  • here to change your ID 하이퍼링크를 타고 들어가면 새로운 창이 열리고, 그 안에서 id를 서치해볼 수 있는 형식이다.
 $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
  • 하지만 이 소스코드에서 확인할 수 있듯, 여전히 사용자의 입력을 별 다른 검토 없이 바로 id에 집어넣는 형식임을 알 수 있다.
  • LIMIT 1을 이용해 한 줄만 출력이 되게끔 하였지만, 이 역시도 주석(-- , #)을 입력하면 효력이 없어진다.
  • ' OR 1=1; # 을 입력하여 SQL Injection 공격을 시도한다.
  • 성공적으로 테이블에 저장된 레코드를 확인할 수 있다.

발생한 보안 문제

  1. 사용자 입력값의 검증 및 필터링 부재
  • 사용자가 입력한 값이 쿼리에 그대로 삽입되었지만, 별 다른 검사나 필터링이 없었다.
  • 이로 인해 공격코드가 그대로 SQL 구문에 반영되어, 쿼리 로직을 조작할 수 있었다.
  • 화이트리스트 방식이나 이스케이프 처리도 없었기에 취약했다.
  1. 클라이언트 측의 한계
  • Medium과 High 레벨에서는 입력창을 없애거나 세션 변수로 값을 전달하는 등 공격 경로를 간접적으로 숨기는 시도를 하였다.
  • 하지만 공격자는 Burp Suite 같은 프록시 툴을 활용해 HTTP 요청을 직접 조작할 수 있어 입력창 없이 파라미터를 변조할 수 있다.
  • 또한 새션 변수로 값을 전달하여도 세션 값에 대한 검증 및 이스케이프가 없었기에, 공격은 그대로 가능하였다.

배운 점

  • 사용자 입력 값을 검증 하지 않는다면, 일반 사용자도 간단한 입력만을 통해 중요한 정보를 얻을 수 있음을 알게 되었다.
  • mysqli_real_escape_string 등의 이스케이프 함수 만으로도 완벽하지 않음을 알게 되었다.
  • DB에 저장된 정보들은 현대 데이터 시대에 가장 중요한 정보들임으로, 더욱 더 안전하게 보호될 수 있도록 실무에서 확실한 보안을 해야겠다고 다짐하였다.
profile
CTF 풀이 및 실습 중심 학습을 기록합니다.

0개의 댓글