HO_9
HO9
HO_9
전체 방문자
오늘
어제
  • 분류 전체보기 (104)
    • Write Up (3)
    • WarGame (21)
      • The Lord of Bufferoverflow(.. (7)
      • The Lord of Sql Injection(L.. (1)
      • Pwnable.kr (1)
      • Pwnable.tw (0)
      • XSS GAME (6)
      • Pwnable.xyz (5)
    • SYSTEM HACKING (49)
      • 기법 (24)
      • 문제 풀이 (24)
    • CODING (2)
      • PYTHON (2)
    • WEB HACKING (1)
    • Plan (0)
    • PROJECT (0)
    • iOS (6)
    • ALGORITHM (0)

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

공지사항

  • .

인기 글

태그

  • JNDI
  • log4j
  • 취약점
  • 아파치

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
HO_9

HO9

SYSTEM HACKING/기법

Exploit using _rtld_global & exit()

2022. 5. 28. 21:23
728x90

정리겸 작성합니다.

 

이전에 csu_init 관련해서 작성했던적이 있다.

2020.04.26 - [SYSTEM HACKING/기법] - Return to Csu

 

Return to Csu

Return to csu -특별하게 사용할 수 있는 Gadget이 없는 경우 __libc_csu_init()이라는 함수를 이용하면  함수를 호출 할 수 있게 인자를 설정을 할 수 있다. [__libc_csu_init()] 이 사진을 보면 두가지 파트로..

hoho9.tistory.com

 

바이너리를 처음 실행하게 되면 start함수를 실행하게 된다.

해당 실행과정에서 __libc_csu_init()함수를 호출하는데 이때 .init_array 섹션을 참조하게된다.

만약 Full Relro가 아닌 경우 해당 섹션을 덮어 쓸 수가 있게된다.

동일하게 바이너리를 종료할때도 exit함수를 실행하게된다.

이때는 .fini_array 섹션을 참조하게 되는데, 동일하게 해당 섹션도 조건이 맞춰지면 overwrite 할 수있다.

 

정확하게 .fini_array를 호출하는 과정은

처음에는 exit함수를 호출하게된다.

해당 함수에서 __run_exit_handlers를 통해서 _dl_fini함수를 호출한다.

_dl_fini함수 호출은 exit_function구조체의 변수인 flavor값에 따라서 달라지게된다.

void exit (int status) {    
	__run_exit_handlers (status, &__exit_funcs, true, true);
}
/*__exit_funcs = exit.h에 exit_function구조체로 선언되어있음*/

 

extern struct exit_function_list *__exit_funcs attribute_hidden;
/*exit.h; extern을 통해서 cxa_atexit.c을 외부변수로 사용 */

 

static struct exit_function_list initial;struct exit_function_list *__exit_funcs = &initial;
/*cxa_atexit.c*/

 

struct exit_function_list{
    struct exit_function_list *next;
    size_t idx;
    struct exit_function fns[32];
};

 

struct exit_function{
    long int flavor;
    union
      {
    void (*at) (void);
    struct
      {
        void (*fn) (int status, void *arg);
        void *arg;
      } on;
    struct
      {
        void (*fn) (void *arg, int status);
        void *arg;
        void *dso_handle;
      } cxa;
      } func;
};

 

void attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
             bool run_list_atexit, bool run_dtors) {
    #ifndef SHARED
      if (&__call_tls_dtors != NULL)
    #endif
        if (run_dtors)
          __call_tls_dtors ();
    while (true) {
        struct exit_function_list *cur;
        __libc_lock_lock (__exit_funcs_lock);
        restart:
              cur = *listp;
        if (cur == NULL) {
            __exit_funcs_done = true;
            __libc_lock_unlock (__exit_funcs_lock);
            break;
        }
        while (cur->idx > 0) {
            struct exit_function *const f = &cur->fns[--cur->idx];
            const uint64_t new_exitfn_called = __new_exitfn_called;
            __libc_lock_unlock (__exit_funcs_lock);
            switch (f->flavor) {
                void (*atfct) (void);
                void (*onfct) (int status, void *arg);
                void (*cxafct) (void *arg, int status);
                case ef_free:
                        case ef_us:
                          break;
                case ef_on:
                          onfct = f->func.on.fn;
                #ifdef PTR_DEMANGLE
                          PTR_DEMANGLE (onfct);
                #endif
                          onfct (status, f->func.on.arg);
                break;
                case ef_at:
                          atfct = f->func.at;
                #ifdef PTR_DEMANGLE
                          PTR_DEMANGLE (atfct);
                #endif
                          atfct ();
                break;
                case ef_cxa:
                f->flavor = ef_free;
                cxafct = f->func.cxa.fn;
                #ifdef PTR_DEMANGLE
                          PTR_DEMANGLE (cxafct);
                #endif
                          cxafct (f->func.cxa.arg, status);
                break;
            }
            __libc_lock_lock (__exit_funcs_lock);
            if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
            goto restart;
        }
        *listp = cur->next;
        if (*listp != NULL)
            free (cur);
        __libc_lock_unlock (__exit_funcs_lock);
    }
    if (run_list_atexit)
        RUN_HOOK (__libc_atexit, ());
    _exit (status);
}

이와 같이 _dl_fini 함수를 호출하게 되면, 해당 함수 내부에서 .fini_array를 호출하게된다.

.fini_array를 원하는 값으로 overwrite하면 exit함수 실행시 원하는 ret주소로 변경이 가능하다.

 

.fini_array를 덮는경우는 relro가 꺼져있고,

함수 주소값을 변경한 이후 해당 함수를 호출하는 포인터가 없는 경우에 사용하게 되면 좋을 것 같다.

 

하지만 Full RELRO가 되어있는 경우에는 이와 같은 방법을 이용하지 못한다.

그래서 두가지 방법을 이용한 Exploit이 있는데,

첫번째로는 _rtld_global Overwrite

두번째로는 _hook Overwrite가 있다.

 

 

첫번째

_dl_fini부분을 확인하면 __rtld_lock_unlock_recursive함수가 있고 인자로 dl_load_lock을 받고있다.

해당 함수와 인자는 _rtld_global구조체를 사용한다.

해당 구조체는 쓰기 권한이 존재하는 위치에 있기 때문에 해당 함수와 인자를 덮어주게 되면

원하는 함수와 인자 값으로 변경이 가능하다.

void
_dl_fini (void)
{
#ifdef SHARED
  int do_audit = 0;
 again:
#endif
  for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
    {
      if (nloaded == 0
#ifdef SHARED
          || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
#endif
          )
        __rtld_lock_unlock_recursive (GL(dl_load_lock));
      else
        {
          /* Now we can allocate an array to hold all the pointers and
             copy the pointers in.  */
          struct link_map *maps[nloaded];
          unsigned int i;
          struct link_map *l;
 .
 .
 .
 .

 

두번째

__run_exit_handler를 보면 해당 함수의 마지막 부분에

free를 해주는 부분을 볼 수가 있다.

이를 통해서 free의 _hook을 덮어주게된다면 원하는 함수를 실행할 수 있다.

하지만 해당 free를 호출하기 위해서는 __run_exit_handler함수에서

while(cur->idx > 0)

if(*listp != NULL)

이 두가지가 성립이 되어야지 free를 실행시킬 수 있다.

 

cur->idx 부분은 구조체의 8번째 부분이니

*initial+8 부분을 0보다 크지 않게 만들어주고,

listp는 initial이므로 아무 값이나 넣어서 조건을 만족시켜주면 된다.

 

그렇게되면 free호출이 가능해진다.

 

 

 

.

.

.

 

'SYSTEM HACKING > 기법' 카테고리의 다른 글

_IO_FILE vtable overwrite & _IO_FILE Structure  (0) 2022.06.04
House of Force?  (0) 2022.01.25
Unsafe unlink in glibc 2.23, 2.27 and over 2.27  (0) 2022.01.22
Poison Null Byte in glibc 2.27  (0) 2022.01.16
Fastbin double free in Glibc 2.3.x  (0) 2022.01.01
    'SYSTEM HACKING/기법' 카테고리의 다른 글
    • _IO_FILE vtable overwrite & _IO_FILE Structure
    • House of Force?
    • Unsafe unlink in glibc 2.23, 2.27 and over 2.27
    • Poison Null Byte in glibc 2.27
    HO_9
    HO_9

    티스토리툴바