기능 분석
<body>
<div class="container">
<h1>🔒 Evalgelist - Try secure eval function</h1>
<div class="warning">
<strong>⚠️ Security Notice:</strong> This system uses advanced filtering to prevent malicious code execution.
Only safe PHP functions are allowed.
</div>
<form method="GET" action="">
<div class="input-group">
<label for="code">Enter PHP function name to validate:</label>
<input type="text" id="code" name="input" placeholder="e.g., phpinfo, strlen, time">
</div>
<button type="submit">🔍 Validate Function</button>
</form>
<?php
if (isset($_GET['input'])) {
echo '<div class="output">';
$filtered = str_replace(['$', '(', ')', '`', '"', "'", "+", ":", "/", "!", "?"], '', $_GET['input']);
$cmd = $filtered . '();';
echo '<strong>After Security Filtering:</strong> <span class="filtered">' . htmlspecialchars($cmd) . '</span>' . "\n\n";
echo '<strong>Execution Result:</strong>' . "\n";
echo '<div style="border-left: 3px solid #007bff; padding-left: 15px; margin-left: 10px;">';
try {
ob_start();
eval($cmd);
$result = ob_get_clean();
if (!empty($result)) {
echo '<span class="success">✅ Function executed successfully!</span>' . "\n";
echo htmlspecialchars($result);
} else {
echo '<span class="success">✅ Function executed (no output)</span>';
}
} catch (Error $e) {
echo '<span class="error">❌ Error: ' . htmlspecialchars($e->getMessage()) . '</span>';
} catch (Exception $e) {
echo '<span class="error">❌ Exception: ' . htmlspecialchars($e->getMessage()) . '</span>';
}
echo '</div>';
echo '</div>';
}
?>
</body>
코드와 함께 분석해보면, 입력값에 대한 필터링이 이루어지고 있다. 그리고 `.();` 을 붙여서 eval을 시켜주는 모습이다.
$와 소괄호를 필터링하면서 인자를 받아서 사용하는 함수는 사용을 못하고 있다.
테스트를 해보면 phpinfo만 붙이면 서버에서 `.();`를 붙여서 phpinfo();가 실행되고 있다.
취약점 분석
version: '3'
services:
evalgelist:
build: ../
environment:
FLAG: "R3CTF{g00d_j0b_my_fr13nd}"
ports:
- 8080:80
restart: unless-stopped
flag는 환경 변수에 저장되고 있다.
#!/bin/sh
rm -f /docker-entrypoint.sh
user=$(ls /home)
if [ "$DASFLAG" ]; then
INSERT_FLAG="$DASFLAG"
export DASFLAG=no_FLAG
DASFLAG=no_FLAG
elif [ "$FLAG" ]; then
INSERT_FLAG="$FLAG"
export FLAG=no_FLAG
FLAG=no_FLAG
elif [ "$GZCTF_FLAG" ]; then
INSERT_FLAG="$GZCTF_FLAG"
export GZCTF_FLAG=no_FLAG
GZCTF_FLAG=no_FLAG
else
INSERT_FLAG="flag{TEST_Dynamic_FLAG}"
fi
echo $INSERT_FLAG | tee /flag
chmod 744 /flag
php-fpm & nginx &
echo "Running..."
tail -F /var/log/nginx/access.log /var/log/nginx/error.log
우리는 flag 환경변수가 저장되는 것을 확인했다. 따라서 elif ["$FLAG"]에서 true가 되어 R3CTF{g00d_j0b_my_fr13nd}가 /flag로 저장되는 것을 알 수 있다. 그럼 우리는 /flag에 접근하면 될 것이다.
1. include DIRECTORY_SEPARATOR . flag;#
2. include [__FILE__][0][0] . flag; time
1. include DIRECTORY_SEPARATOR . flag;#
- include
include는 파일을 포함시키고 실행시킨다. 에러와 함께 flag가 나오는 것을 볼 수 있는데 php 구문인줄 알았으나 그렇지 않아서 발생하는 에러이다.
- DIRECTORY_SEPARATOR
`/`를 의미하는 php 내장 상수이다. PATH_SEPARATOR나 PHP_VERSION 등도 있다.
- .
`.`을 통해 문자열을 이어줄 수 있다.
- flag
앞선 문자열들과 합쳐져서 `include /flag`가 된다.
- #
주석으로 동작한다.
주석으로 동작하기 때문에 위와 같이 # 뒤에 아무런 값이나 입력해도 아무런 에러가 발생하지 않는 것을 확인할 수 있다.
2. include [__FILE__][0][0] . flag; time
여기서는 [__FILE__][0][0]과 time에 대해서만 설명하겠다.
- [__FILE__][0][0]
__FILE__은 현재 파일의 위치를 나타내는 매직 상수이다. 이것 외에도 __DIR__도 있다. __DIR__을 사용해도 동일하게 flag를 얻을 수 있다.
배열이니 뒤에 [0]을 붙여서 첫 번째 요소를 가져오자.
그럼 현재 경로가 담긴 요소가 나온다. 여기서 또 대괄호를 이용해서 각 문자열에 접근할 수 있다.
위와 같이 `/`를 얻을 수 있다. 만약 1을 사용하면 `/var`의 v를 얻을 수 있다.
__DIR__을 사용해도 똑같은 결과를 얻을 수 있다.
같은 것을 확인할 수 있다.
- time
에러가 발생하지 않게 아무런 내장 함수를 사용한 것이다. #을 사용해도 되고 큰 상관 없다.
R3CTF{g00d_j0b_my_fr13nd}
짜잔
'분류 전 > CTF' 카테고리의 다른 글
[L3ak CTF 2025] BrainCalc 풀이 (0) | 2025.07.15 |
---|---|
[L3ak CTF 2025] Flag L3ak 풀이 (0) | 2025.07.15 |
[cubectf] Legal Snacks 풀이 (1) | 2025.07.08 |
[IERAE CTF 2025][WEB] Warmdown 풀이 (0) | 2025.06.22 |
[2024 IS_LAB CTF] meta-data 풀이 (0) | 2024.02.07 |