loading . . . [ํ๋ฃจํ์ค] CVE-2025-4802 : GLIBC์ ์ ์ setuid ๋ฐ์ด๋๋ฆฌ์์ ๋ฐ์ํ๋ ์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก ์ทจ์ฝ์ - hackyboiz ## URL
* https://cyberpress.org/critical-glibc-flaw/
## Target
* 2.27๋ถํฐ 2.38๊น์ง์ GNU C Library๋ฅผ ์ฌ์ฉํ๋ ํ๊ฒฝ
## Explain
### background
์ผ๋ฐ์ ์ผ๋ก ๋ฆฌ๋
์ค์์ setuid/setgid ๊ถํ์ด ์ ์ฉ๋ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์คํํ๋ฉด ์ปค๋์ `execve()` ๋ด๋ถ์์ secure execution์ด๋ผ๋ ํน์ ๋ชจ๋๋ฅผ ํ์ฑํํฉ๋๋ค. ์ด ๊ณผ์ ์์ ์ปค๋์ `bprm->secureexec = 1`์ ์ค์ [1]ํ๊ณ ELF ๋ณด์กฐ ๋ฒกํฐ์ `AT_SECURE = 1` ๊ฐ์ ์ฝ์
[2]ํฉ๋๋ค.
> **linux-6.17.9/security/commoncap.c**
int cap_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file)
...
/* Check for privilege-elevated exec. */
if (id_changed ||
!uid_eq(new->euid, old->uid) ||
!gid_eq(new->egid, old->gid) ||
(!__is_real(root_uid, new) &&
(effective ||
__cap_grew(permitted, ambient, new))))
bprm->secureexec = 1; // [1]
...
> **linux-6.17.9/fs/binfmt_elf.c**
static int
create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
unsigned long interp_load_addr,
unsigned long e_entry, unsigned long phdr_addr)
...
NEW_AUX_ENT(AT_SECURE, bprm->secureexec); // [2]
...
`AT_SECURE`๊ฐ `1`์ด๋ฉด glibc๋ secure mode๋ก ์ ํํ์ฌ ๋ด๋ถ์ ์ผ๋ก `__libc_enable_secure = 1`์ ์ค์ [3]ํ๊ณ `LD_LIBRARY_PATH`, `LD_PRELOAD`, `LD_AUDIT`๊ณผ ๊ฐ์ ์ํํ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ฌด์[4]ํ๊ฒ ๋ฉ๋๋ค.
> **glibc-2.35/elf/dl-support.c**
void
_dl_aux_init (ElfW(auxv_t) *av)
...
case AT_SECURE:
seen = -1;
__libc_enable_secure = av->a_un.a_val; // [3]
__libc_enable_secure_decided = 1;
break;
...
> **glibc-2.35/elf/rtld.c**
static void
dl_main (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
ElfW(Addr) *user_entry,
ElfW(auxv_t) *auxv)
...
dl_main_state_init (&state);
...
static void
dl_main_state_init (struct dl_main_state *state)
{
audit_list_init (&state->audit_list);
state->library_path = NULL;
state->library_path_source = NULL;
...
static void
process_envvars (struct dl_main_state *state)
...
case 12:
/* The library search path. */
if (!__libc_enable_secure // [4]
&& memcmp (envline, "LIBRARY_PATH", 12) == 0)
{
state->library_path = &envline[13];
state->library_path_source = "LD_LIBRARY_PATH";
break;
}
...
ํด๋น ํํฐ๋ง์ ํ๋ก์ธ์ค์ ์ด๊ธฐํ ๋ฃจํด์์ ์ํ๋๋ฉฐ ์ด๋ก ์ธํด ์ผ๋ฐ ์ฌ์ฉ์๊ฐ setuid ๋ฐ์ด๋๋ฆฌ์ ์์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ์ ๋ฌํจ์ผ๋ก์จ root ๊ถํ์ ํ๋ํ๋ ๊ฒฝ๋ก๊ฐ ์ฐจ๋จ๋ฉ๋๋ค.
### root cause
ํด๋น ์ทจ์ฝ์ ์ ๊ฒฝ์ฐ glibc์ `__libc_enable_secure` ๊ฐ์ ์ด์ฉํ ํ๊ฒฝ ๋ณ์ ํํฐ๋ง ๋ก์ง์ด ๋์ ๋ก๋์ ์ด๊ธฐํ ํจ์์ธ `dl_main()` ์์๋ง ์ ์ฉ๋์ด ์์๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ์์ต๋๋ค.
์ ์ ๋งํฌ๋ ๋ฐ์ด๋๋ฆฌ๋ ๋์ ๋ก๋๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ `_dl_non_dynamic_init()` ํจ์๋ฅผ ํตํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ์ค์ [5]ํ๋๋ฐ ํด๋น ํจ์์์๋ `__libc_enable_secure` ๊ฐ์ ๋ฐ๋ฅธ ํ๊ฒฝ ๋ณ์ ํํฐ๋ง์ด ๋ฏธํกํ์ต๋๋ค.
> **glibc-2.35/elf/dl-support.c**
void
_dl_non_dynamic_init (void)
{
...
/* Initialize the data structures for the search paths for shared
objects. */
_dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH", // [5]
/* No glibc-hwcaps selection support in statically
linked binaries. */
NULL, NULL);
...
์ด๋ก ์ธํด ์ปค๋์ด secure execution ๋ชจ๋๋ฅผ ํ์ฑํํ๋๋ผ๋ `dlopen()`๋ฑ์ ํจ์ ํธ์ถ์์ ํ๊ฒฝ ๋ณ์ ๊ธฐ๋ฐ์ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๊ฒ ๋์ด ๊ณต๊ฒฉ์๊ฐ `LD_LIBRARY_PATH` ํ๊ฒฝ ๋ณ์์ ์ ์ด ๊ฐ๋ฅํ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ค์ ํ๋ฉด setuid ๋ฐ์ด๋๋ฆฌ๊ฐ ๊ณต๊ฒฉ์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ก๋ํ ์ ์๊ฒ ๋ฉ๋๋ค.
### patch
ํจ์น ์ปค๋ฐ `5451fa962cd0a90a0e2ec1d8910a559ace02bba0`์์ `__libc_enable_secure` ๊ฐ์ ํตํด ํ๊ฒฝ ๋ณ์๋ฅผ ํํฐ๋ง[6]ํ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ๋ก๋[7]ํ๋๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.
> **glibc-2.39/elf/dl-support.c**
void
_dl_non_dynamic_init (void)
{
_dl_main_map.l_origin = _dl_get_origin ();
_dl_main_map.l_phdr = GL(dl_phdr);
_dl_main_map.l_phnum = GL(dl_phnum);
/* Set up the data structures for the system-supplied DSO early,
so they can influence _dl_init_paths. */
setup_vdso (NULL, NULL);
/* With vDSO setup we can initialize the function pointers. */
setup_vdso_pointers ();
if (__libc_enable_secure) // [6]
{
static const char unsecure_envvars[] =
UNSECURE_ENVVARS
;
const char *cp = unsecure_envvars;
while (cp < unsecure_envvars + sizeof (unsecure_envvars))
{
__unsetenv (cp);
cp = strchr (cp, '\0') + 1;
}
}
...
/* Initialize the data structures for the search paths for shared
objects. */
_dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH", // [7]
/* No glibc-hwcaps selection support in statically
linked binaries. */
NULL, NULL);
...
## Reference
* https://www.man7.org/linux/man-pages/man3/getauxval.3.html
* https://ubuntu.com/security/CVE-2025-4802
* https://cyberpress.org/critical-glibc-flaw/
* https://articles.manugarg.com/aboutelfauxiliaryvectors
* https://patchwork.yoctoproject.org/project/oe-core/patch/[email protected]/#28605
- hack & life https://hackyboiz.github.io/2025/12/03/millet/cve-2025-4802/