## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-M8SEVEN-CVE-2026-11837-ANSIBLE-POSIX-AUTHORIZED-KEY
# CVE-2026-11837: ansible.posix `authorized_key` λ‘컬 κΆν μμΉ
μ¬μ©μμ `~/.ssh` λλ ν°λ¦¬ λ° `authorized_keys` νμΌμ λν μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ°λ `chown`(λ° μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ°λ νμΌ μμ±)μ ν΅ν `ansible.posix.authorized_key` Ansible λͺ¨λμ λ‘컬 κΆν μμΉμ
λλ€.
μ΄λ μ κ° λ³΄κ³ νκ³ Red Hat Product Security(CNA)μμ **CVE-2026-11837** μ ν λΉν μ·¨μ½μ μ λν λΆμμ
λλ€. κΈ°μ κΈ°λ‘μΌλ‘μ μ¬κΈ°μ κ²μλλ©°, μλ‘μ΄ λ°κ²¬μ μ£Όμ₯νλ κ²μ΄ μλλλ€. μ΄ λ¬Έμ λ μ΄μ μμ μ¬νμ΄ λ€λ£¨μ§ μμ λͺ¨λμμμ CVE-2024-9902μ **μλ§€** μ
λλ€.
## 곡μ μ°Έμ‘°
* Red Hat CVE κΈ°λ‘: https://access.redhat.com/security/cve/CVE-2026-11837
* Red Hat Bugzilla κ²°ν¨: https://bugzilla.redhat.com/show_bug.cgi?id=2487424
* μν₯μ λ°λ λͺ¨λ μμ€: https://github.com/ansible-collections/ansible.posix/blob/main/plugins/modules/authorized_key.py
> Red Hatμ κ²μλ μΈμ : "Red Hatμ μ΄ λ¬Έμ λ₯Ό λ³΄κ³ ν΄ μ£Όμ Valentino Paulonμκ² κ°μ¬λ립λλ€."
## μμ½
루νΈλ‘ μ€νλλ νλ μ΄λΆμ΄ `ansible.posix.authorized_key`λ₯Ό μ¬μ©νμ¬ λ‘컬 μ¬μ©μμ ν€λ₯Ό κ΄λ¦¬ν λ, λͺ¨λμ `keyfile()` ν¬νΌλ:
* μ¬μ©μμ `~/.ssh` λλ ν°λ¦¬ λ° `~/.ssh/authorized_keys`μ μμ κΆμ μΌλ° `os.chown`(`os.lchown` μλ)μΌλ‘ λ³κ²½νκ³ ,
* μΌλ° `open(..., "w")`(`O_NOFOLLOW` μμ)μΌλ‘ ν€ νμΌμ μμ±ν©λλ€.
κΈ°λ³Έ `follow=False`λ₯Ό μ¬μ©νλ©΄ λͺ¨λμ μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ°μ κ΅μ²΄νκ±°λ κ±°λΆνμ§ μμ΅λλ€. κ²½λ‘μμ μ§μ μλνλ―λ‘ μ»€λμ κΆνμ΄ μλ λμ μ¬μ©μκ° μμ μ `~/.ssh` λ΄μ 미리 μ€λΉν λͺ¨λ μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ°λλ€. μ΄λ‘ μΈν΄ 루νΈκ° μ μ΄νλ κ²½λ‘μ μμ κΆμ κΆν μλ μ¬μ©μμκ² μ΄μ νλ λ κ°μ§ ν리미ν°λΈκ° μμ±λλ©°, μ¬μ©μλ μ΄λ₯Ό ν΅ν΄ 루νΈλ‘ κΆν μμΉν©λλ€. λ κ°μ§ λͺ¨λ HEADμμ 컬λ μ
μ λν΄ μ’
λ¨ κ° μ¬νλμμ΅λλ€.
## μν₯μ λ°λ μ½λ λ° κ·Όλ³Έ μμΈ
`keyfile()` (`plugins/modules/authorized_key.py`), κΈ°λ³Έ `manage_dir=True`, `follow=False`:
root@kitploit:~
if manage_dir:
if not os.path.exists(sshdir): # os.path.exists FOLLOWS symlinks
try:
os.mkdir(sshdir, int('0700', 8))
...
os.chown(sshdir, uid, gid) # UNCONDITIONAL, plain chown, follows symlink
os.chmod(sshdir, int('0700', 8)) # follows symlink
if not os.path.exists(keysfile): # follows symlink
...
f = open(keysfile, "w") # plain open(), no O_NOFOLLOW, follows symlink
...
try:
os.chown(keysfile, uid, gid) # UNCONDITIONAL, plain chown, follows symlink
os.chmod(keysfile, int('0600', 8)) # follows symlink
except OSError:
pass
`sshdir` λ° `keysfile`μ λμ μ¬μ©μμ passwd ν(`pwd.getpwnam(user).pw_dir`)μμ νμλλ©°, μ΄λ κΆν μλ λμ μ¬μ©μκ° μμ νκ³ μ μ΄νλ λλ ν°λ¦¬μ
λλ€. `follow` λ§€κ°λ³μ(κΈ°λ³Έκ° `False`)λ κ²½λ‘μ λν΄ `os.path.realpath()`λ₯Ό μνν μ§ μ¬λΆλ§ μ νν©λλ€. λ κ²½μ° λͺ¨λ `os.path.islink` κ²μ¬, `O_NOFOLLOW` μ΄κΈ°, `os.lchown` λλ κΈ°μ‘΄ μ¬λ³Όλ¦ λ§ν¬μ μ°κ²° ν΄μ λ° κ΅μ²΄κ° μμ΅λλ€. κΆν λλ‘(`seteuid`/`setfsuid`)μ΄ μνλμ§ μμ΅λλ€. λͺ¨λ κ²μ΄ 루νΈλ‘ μ€νλ©λλ€.
λ `os.chown` νΈμΆμ **무쑰건μ μΌλ‘** μ€νλλ©°, `if not os.path.exists(...)` κ°λ μΈλΆμ μμΌλ―λ‘ λλ ν°λ¦¬/νμΌμ΄ μ΄λ―Έ μ‘΄μ¬νλμ§ μ¬λΆμ κ΄κ³μμ΄ μ€νλ©λλ€. μ΄κ²μ΄ λ ν리미ν°λΈλ₯Ό μ λ’°ν μ μκ² λ§λλλ€.
## λ κ°μ§ ν리미ν°λΈ
λ λ€ μΌνμ© Linux VMμμ `ansible.posix` HEADλ‘ μ’
λ¨ κ° νμΈλμμ΅λλ€. `victim`μ κΆνμ΄ μλ λ‘컬 μ¬μ©μ(uid 1000)μ
λλ€. λͺ¨λμ μ΄μμμ νλ μ΄λΆκ³Ό μ νν λμΌνκ² λ£¨νΈλ‘ μ€νλ©λλ€. μΉ΄λ리(Canaries)λ λ―Όκ°ν λ£¨νΈ λμμ λμ ν©λλ€.
**λ²‘ν° 1: λλ ν°λ¦¬ μ¬λ³Όλ¦ λ§ν¬ (κΈ°μ‘΄ λ£¨νΈ μμ λλ ν°λ¦¬μ chown)**
1. `victim`μΌλ‘: `ln -s /root/AD_CANARY ~/.ssh` (`/root/AD_CANARY`λ κΈ°μ‘΄ λ£¨νΈ μμ λλ ν°λ¦¬).
2. μ΄μμκ° `victim`μ λν΄ `authorized_key` μμ
μ μ€νν©λλ€.
3. κ΄μ°°: `/root/AD_CANARY`μ μμ κΆμ΄ `root:root`μμ `victim:victim`μΌλ‘ λ³κ²½λμμ΅λλ€. `os.chown(sshdir, ...)` νΈμΆμ΄ `~/.ssh` μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ° λ£¨νΈ μμ λλ ν°λ¦¬λ₯Ό κΆν μλ μ¬μ©μμκ² λκ²Όμ΅λλ€.
**λ²‘ν° 2: λ°μ νμΌ μ¬λ³Όλ¦ λ§ν¬ (μ λ£¨νΈ κ²½λ‘ νμΌμ μμ± + chown)**
1. `victim`μΌλ‘ (`~/.ssh`κ° μΌλ° λλ ν°λ¦¬μΈ κ²½μ°): `ln -s /root/AF_CANARY ~/.ssh/authorized_keys` (λμμ΄ μ‘΄μ¬νμ§ μμ).
2. μ΄μμκ° `victim`μ λν΄ `authorized_key` μμ
μ μ€νν©λλ€.
3. κ΄μ°°: `/root/AF_CANARY`κ° μμ±λμκ³ , μμ μλ `victim:victim`, λͺ¨λ 0600μ
λλ€. `open(keysfile, "w")`κ° μ¬λ³Όλ¦ λ§ν¬λ₯Ό ν΅ν΄ λμμ μμ±νκ³ `os.chown(keysfile, ...)`μ΄ λκ²Όμ΅λλ€.
λ κ²½μ° λͺ¨λ κΆν μλ μ¬μ©μλ 루νΈκ° μ μ΄νλ κ²½λ‘μ μμ μκ° λ©λλ€. λ§ν¬λ₯Ό `/etc` μλμ λλ ν°λ¦¬(λ²‘ν° 1) λλ `/etc/cron.d/`λ `/etc/sudoers.d/` μλμ μ νμΌ(λ²‘ν° 2)λ‘ μ§μ νλ©΄ νμ€ νμ μ‘°μΉμ μν΄ λ£¨νΈλ₯Ό νλνκ² λλ©°, μ΄μ μμ μμΈ μ¬μ©μκ° λμμ λ€μ μλλ€.
## CVE-2024-9902μμ κ΄κ³
μ΄λ λμΌν μ¬λ³Όλ¦ λ§ν¬ λ°λΌκ°κΈ° ν΄λμ€λ₯Ό λ€λ£¬ CVE-2024-9902(ansible-coreμ `user` λͺ¨λ `generate_ssh_key`)μ μλ§€μ
λλ€. `authorized_key`λ λ³λμ `ansible.posix` 컬λ μ
μ μμΌλ©° ν΄λΉ μμ μ¬νμ μν΄ λ³κ²½λμ§ μμμ΅λλ€. μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ°λ `chown`/create ν¨ν΄μ΄ μ¬μ ν μ‘΄μ¬νκ³ λ³΄νΈλμ§ μμμ΅λλ€. μ΄λ μλ‘λ°κ²¬λ κ·Όλ³Έ μμΈμ΄ μλλΌ μ΄μ μμ μ¬νμ΄ λλ¬νμ§ λͺ»ν λͺ¨λμμ λμΌν νμ©λ ν΄λμ€λ‘ λ³΄κ³ λμμ΅λλ€.
## μν₯ λ° μ μ§ν μ μ 쑰건
* Ansibleμ΄ κ΄λ¦¬νλ νΈμ€νΈμμ κΆν μλ λ‘컬 μ¬μ©μμμ 루νΈλ‘μ κΆν μμΉ.
* μ΄μμκ° νΌν΄μμ κ³μ μ λμμΌλ‘ νλ `ansible.posix.authorized_key` μμ
μ μ€ννλ 쑰건(μ΄ λͺ¨λμ μΌλ°μ μΈ μ¬μ©). λ‘컬 μ¬μ©μλ μμ μ `~/.ssh`μ μ¬λ³Όλ¦ λ§ν¬λ₯Ό 미리 μ€λΉν©λλ€. νλ μ΄λΆμ μ€ννμ§ μμ΅λλ€. μ΄λ μ΄μμκ° νΈλ¦¬κ±°ν©λλ€: Red Hatμ΄ "μ λ’°ν μ μλ κ³μ μ λν΄ μ€ννμ§ λ§μμμ€"λΌλ μν μ‘°μΉμ ν¨κ» μΉμΈν CVE-2024-9902μ λμΌν νΈλ¦¬κ±° λͺ¨λΈμ
λλ€. μ μ 쑰건μ μ체 νΈλ¦¬κ±°λ‘ νκ°λμ§ μκ³ λͺ
μμ μΌλ‘ λͺ
μλ©λλ€.
## μ μλ μμ
* μ¬λ³Όλ¦ λ§ν¬λ₯Ό λ°λΌκ°μ§ μκ³ ν€ νμΌμ λ
μ μ μΌλ‘ μμ±ν©λλ€: `os.open(keysfile, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)` λ° λμ€ν¬λ¦½ν°μμ μλ; `sshdir` λλ `keysfile`μ΄ μ¬λ³Όλ¦ λ§ν¬μΈ κ²½μ° κ±°λΆ(λλ `follow=False` λ¬Έμ λ¬Έμμ΄ κ³μ½μ λ°λΌ μ°κ²° ν΄μ λ° κ΅μ²΄).
* `os.chown(...)`μ `os.lchown`μΌλ‘ λλ μμ νκ² μ΄λ¦° λμ€ν¬λ¦½ν°μμ `os.fchown`μΌλ‘ λ체νκ³ , λ§μ°¬κ°μ§λ‘ `os.chmod` λμ `os.fchmod`λ₯Ό μ¬μ©νμ¬ λ§ν¬λ₯Ό ν΅ν΄ μμ κΆκ³Ό κΆνμ΄ λ¦¬λλ μ
λμ§ μλλ‘ ν©λλ€.
* 무쑰건μ μΈ `chown`/`chmod`λ₯Ό κ²μ΄νΈνμ¬ λͺ¨λ μμ²΄κ° μμ νκ² μμ±ν κ²½λ‘μλ§ μ μ©λλλ‘ νκ³ , κΈ°μ‘΄(μ¬λ³Όλ¦ λ§ν¬ κ°λ₯) κ²½λ‘μλ μ μ©λμ§ μλλ‘ ν©λλ€.
## κ³΅κ° νμλΌμΈ
λ μ§| μ΄λ²€νΈ
---|---
2026-06-08| `some-email@example.com`μ λ³΄κ³ λ¨ (Red Hat Product Security CCκ° CNAλ‘), CVE-2024-9902μ μλ§€λ‘ κ΅¬μ±λ¨
2026-06-10| CVE-2026-11837 ν λΉ λ° κ²μλ¨; ν¬λ λ§ μλ½λ¨
## λΌμ΄μ μ€
MIT. LICENSE μ°Έμ‘°.