WWW2Exec - atexit(), TLS Storage & Other mangled Pointers
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
__atexit Structures
Caution
์์ฆ ์ด๊ฑธ ์ ์ฉํ๋ ๊ฒ์ ๋งค์ฐ ์ด์ํฉ๋๋ค!
**atexit()**๋ ๋ค๋ฅธ ํจ์๋ค์ด ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌ๋๋ ํจ์์
๋๋ค. ์ด ํจ์๋ค์ exit() ๋๋ main์ return์ ์คํํ ๋ ์คํ๋ฉ๋๋ค.
๋ง์ฝ ์ด ํจ์๋ค ์ค ํ๋์ ์ฃผ์๋ฅผ ์๋ฅผ ๋ค์ด ์์ฝ๋๋ก ๊ฐ๋ฆฌํค๋๋ก ์์ ํ ์ ์๋ค๋ฉด, ํ๋ก์ธ์ค๋ฅผ ์ ์ดํ ์ ์์ต๋๋ค. ํ์ง๋ง ํ์ฌ ์ด๋ ๋ ๋ณต์กํฉ๋๋ค.
ํ์ฌ ์คํ๋ ํจ์๋ค์ ๋ํ ์ฃผ์๋ ์ฌ๋ฌ ๊ตฌ์กฐ ๋ค์ ์จ๊ฒจ์ ธ ์์ผ๋ฉฐ, ๊ฒฐ๊ตญ ๊ฐ๋ฆฌํค๋ ์ฃผ์๋ ํจ์์ ์ฃผ์๊ฐ ์๋๋ผ XOR๋ก ์ํธํ๋๊ณ ๋ฌด์์ ํค๋ก ๋ณ์๋ ๊ฒ์
๋๋ค. ๊ทธ๋์ ํ์ฌ ์ด ๊ณต๊ฒฉ ๋ฒกํฐ๋ x86 ๋ฐ x64_86์์๋ ๊ทธ๋ฆฌ ์ ์ฉํ์ง ์์ต๋๋ค.
์ํธํ ํจ์๋ **PTR_MANGLE**์
๋๋ค. m68k, mips32, mips64, aarch64, arm, hppa์ ๊ฐ์ ๋ค๋ฅธ ์ํคํ
์ฒ๋ ์ํธํ ํจ์๋ฅผ ๊ตฌํํ์ง ์์ผ๋ฉฐ, ์
๋ ฅ์ผ๋ก ๋ฐ์ ๊ฒ๊ณผ ๊ฐ์ ๊ฐ์ ๋ฐํํฉ๋๋ค. ๋ฐ๋ผ์ ์ด๋ฌํ ์ํคํ
์ฒ๋ ์ด ๋ฒกํฐ๋ก ๊ณต๊ฒฉํ ์ ์์ต๋๋ค.
์ด ์๋ ๋ฐฉ์์ ๋ํ ์์ธํ ์ค๋ช ์ https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html์์ ํ์ธํ ์ ์์ต๋๋ค.
link_map
์ด ๊ฒ์๋ฌผ์์ ์ค๋ช
ํ ๋ฐ์ ๊ฐ์ด, ํ๋ก๊ทธ๋จ์ด return ๋๋ exit()๋ฅผ ์ฌ์ฉํ์ฌ ์ข
๋ฃ๋๋ฉด __run_exit_handlers()๊ฐ ์คํ๋์ด ๋ฑ๋ก๋ ์๋ฉธ์๋ฅผ ํธ์ถํฉ๋๋ค.
Caution
ํ๋ก๊ทธ๋จ์ด
_exit()ํจ์๋ฅผ ํตํด ์ข ๋ฃ๋๋ฉด,exitsyscall์ ํธ์ถํ๊ณ ์ข ๋ฃ ํธ๋ค๋ฌ๋ ์คํ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์__run_exit_handlers()๊ฐ ์คํ๋๋์ง ํ์ธํ๋ ค๋ฉด ๊ทธ์ ๋ํ ์ค๋จ์ ์ ์ค์ ํ ์ ์์ต๋๋ค.
์ค์ํ ์ฝ๋๋ (source):
ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
if (fini_array != NULL)
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
// This is the d_un structure
ptype l->l_info[DT_FINI_ARRAY]->d_un
type = union {
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
}
map -> l_addr + fini_array -> d_un.d_ptr๋ฅผ ์ฌ์ฉํ์ฌ ํธ์ถํ ํจ์์ ๋ฐฐ์ด์ ์์น๋ฅผ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ ์ฃผ๋ชฉํ์ธ์.
๋ช ๊ฐ์ง ์ต์ ์ด ์์ต๋๋ค:
map->l_addr์ ๊ฐ์ ๋ฎ์ด์จ์ **์์ ์ฝ๋๋ฅผ ์คํํ ์ง์์ฌํญ์ด ์๋ ๊ฐ์งfini_array**๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ํฉ๋๋ค.l_info[DT_FINI_ARRAY]์l_info[DT_FINI_ARRAYSZ]ํญ๋ชฉ(๋ฉ๋ชจ๋ฆฌ์์ ๊ฑฐ์ ์ฐ์์ ์)์ ๋ฎ์ด์จ์ ์์กฐ๋Elf64_Dyn๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ํ์ฌarray๊ฐ ๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ฐ๋ฆฌํค๊ฒ ํฉ๋๋ค.- ์ด ๊ธ์
l_info[DT_FINI_ARRAY]๋ฅผ.bss์ ์๋ ์ ์ด๋ ๋ฉ๋ชจ๋ฆฌ์ ์ฃผ์๋ก ๋ฎ์ด์จ์ ๊ฐ์งfini_array๋ฅผ ํฌํจํฉ๋๋ค. ์ด ๊ฐ์ง ๋ฐฐ์ด์ ๋จผ์ one gadget ์ฃผ์๋ฅผ ํฌํจํ๊ณ , ์ด ์ฃผ์๊ฐ ์คํ๋ ํ ์ด ๊ฐ์ง ๋ฐฐ์ด์ ์ฃผ์์map->l_addr์ ๊ฐ ์ฌ์ด์ ์ฐจ์ด๋ฅผ ํฌํจํ์ฌ*array๊ฐ ๊ฐ์ง ๋ฐฐ์ด์ ๊ฐ๋ฆฌํค๊ฒ ํฉ๋๋ค. - ์ด ๊ธฐ์ ์ ์ฃผ์ ๊ฒ์๋ฌผ๊ณผ ์ด ๊ธ์ ๋ฐ๋ฅด๋ฉด, ld.so๋ ld.so์ ์ด์ง
link_map์ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ๋ฅผ ์คํ์ ๋จ๊น๋๋ค. ์์ ์ฐ๊ธฐ๋ฅผ ํตํด ์ด๋ฅผ ๋ฎ์ด์ฐ๊ณ ๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ ๊ฐ์งfini_array๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ํ ์ ์์ผ๋ฉฐ, ์๋ฅผ ๋ค์ด one gadget์ ์ฃผ์๋ฅผ ํฌํจํ ์ ์์ต๋๋ค.
์ด์ ์ฝ๋ ๋ค์์ ์ฝ๋๊ฐ ํฌํจ๋ ๋ ๋ค๋ฅธ ํฅ๋ฏธ๋ก์ด ์น์ ์ ์ฐพ์ ์ ์์ต๋๋ค:
/* Next try the old-style destructor. */
ElfW(Dyn) *fini = map->l_info[DT_FINI];
if (fini != NULL)
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
}
์ด ๊ฒฝ์ฐ map->l_info[DT_FINI]์ ๊ฐ์ ์กฐ์๋ ElfW(Dyn) ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ๋ฎ์ด์ธ ์ ์์ต๋๋ค. ์์ธํ ์ ๋ณด๋ ์ฌ๊ธฐ์์ ํ์ธํ์ธ์.
TLS-Storage dtor_list ๋ฎ์ด์ฐ๊ธฐ in __run_exit_handlers
์ฌ๊ธฐ์์ ์ค๋ช
๋ ๋ฐ์ ๊ฐ์ด, ํ๋ก๊ทธ๋จ์ด return ๋๋ exit()๋ฅผ ํตํด ์ข
๋ฃ๋๋ฉด **__run_exit_handlers()**๊ฐ ์คํ๋์ด ๋ฑ๋ก๋ ๋ชจ๋ ์๋ฉธ์ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
_run_exit_handlers()์ ์ฝ๋:
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
bool run_list_atexit, bool run_dtors)
{
/* First, call the TLS destructors. */
#ifndef SHARED
if (&__call_tls_dtors != NULL)
#endif
if (run_dtors)
__call_tls_dtors ();
**__call_tls_dtors()**์ ์ฝ๋:
typedef void (*dtor_func) (void *);
struct dtor_list //struct added
{
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
};
[...]
/* Call the destructors. This is called either when a thread returns from the
initial function or when the process exits via the exit function. */
void
__call_tls_dtors (void)
{
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
}
๊ฐ ๋ฑ๋ก๋ ํจ์์ ๋ํด **tls_dtor_list**์์ **cur->func**์ ํฌ์ธํฐ๋ฅผ ๋๋ง๊ธ๋งํ๊ณ **cur->obj**๋ฅผ ์ธ์๋ก ํธ์ถํฉ๋๋ค.
์ด GEF์ ํฌํฌ์์ tls ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ค์ ๋ก **dtor_list**๊ฐ ์คํ ์นด๋๋ฆฌ์ PTR_MANGLE ์ฟ ํค์ ๋งค์ฐ ๊ฐ๊น๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด๋ฅผ ์ค๋ฒํ๋ก์ฐํ๋ฉด ์ฟ ํค์ ์คํ ์นด๋๋ฆฌ๋ฅผ ๋ฎ์ด์ธ ์ ์์ต๋๋ค.
PTR_MANGLE ์ฟ ํค๋ฅผ ๋ฎ์ด์ฐ๋ฉด PTR_DEMANLE ํจ์๋ฅผ 0x00์ผ๋ก ์ค์ ํ์ฌ ์ฐํํ ์ ์์ผ๋ฉฐ, ์ด๋ ์ค์ ์ฃผ์๋ฅผ ์ป๊ธฐ ์ํด ์ฌ์ฉ๋๋ **xor**๊ฐ ์ค์ ๋ ์ฃผ์์ ๊ฐ์์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ **dtor_list**์ ์ฐ๋ฉด ํจ์ ์ฃผ์์ ๊ทธ ์ธ์๋ก ์ฌ๋ฌ ํจ์๋ฅผ ์ฒด์ธํ ์ ์์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก ์ ์ฅ๋ ํฌ์ธํฐ๋ ์ฟ ํค์ xored๋ ๋ฟ๋ง ์๋๋ผ 17๋นํธ ํ์ ๋ ์ํ๋๋ค๋ ์ ์ ์ ์ํ์ธ์:
0x00007fc390444dd4 <+36>: mov rax,QWORD PTR [rbx] --> mangled ptr
0x00007fc390444dd7 <+39>: ror rax,0x11 --> rotate of 17 bits
0x00007fc390444ddb <+43>: xor rax,QWORD PTR fs:0x30 --> xor with PTR_MANGLE
๋ค์ ์ฃผ์๋ฅผ ์ถ๊ฐํ๊ธฐ ์ ์ ์ด ์ ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค.
์๋ณธ ๊ฒ์๋ฌผ์์ ์๋ฅผ ์ฐพ์๋ณด์ธ์.
**__run_exit_handlers**์ ๋ค๋ฅธ ๋ง๊ฐ์ง ํฌ์ธํฐ
์ด ๊ธฐ์ ์ ์ฌ๊ธฐ์์ ์ค๋ช
๋ฉ๋๋ค ๋ฐ ํ๋ก๊ทธ๋จ์ด **return ๋๋ exit()**์ ํธ์ถํ์ฌ ์ข
๋ฃ๋ ๋ ๋ค์ ์์กดํ๋ฏ๋ก **__run_exit_handlers()**๊ฐ ํธ์ถ๋ฉ๋๋ค.
์ด ํจ์์ ์ฝ๋๋ฅผ ๋ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
while (true)
{
struct exit_function_list *cur;
restart:
cur = *listp;
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
__libc_lock_unlock (__exit_funcs_lock);
๋ณ์ f๋ initial ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ, f->flavor์ ๊ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ํจ์๊ฐ ํธ์ถ๋ฉ๋๋ค.
๊ฐ์ ๋ฐ๋ผ ํธ์ถํ ํจ์์ ์ฃผ์๋ ๋ค๋ฅธ ์์น์ ์์ง๋ง, ํญ์ demangled ์ํ์
๋๋ค.
๋ํ, ์ต์
ef_on ๋ฐ **ef_cxa**์์๋ ์ธ์๋ฅผ ์ ์ดํ ์๋ ์์ต๋๋ค.
๋๋ฒ๊น
์ธ์
์์ GEF๋ฅผ ์คํํ์ฌ **gef> p initial**๋ก initial ๊ตฌ์กฐ์ฒด๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฅผ ์
์ฉํ๋ ค๋ฉด PTR_MANGLE ์ฟ ํค๋ฅผ leakํ๊ฑฐ๋ ์ง์ด ๋ค์, system('/bin/sh')๋ก initial์ cxa ํญ๋ชฉ์ ๋ฎ์ด์จ์ผ ํฉ๋๋ค.
์ด์ ๊ด๋ จ๋ ์์๋ ๊ธฐ์ ์ ๋ํ ์๋ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์์ ์ฐพ์ ์ ์์ต๋๋ค.
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


