Overwrite _rtld_global exploit tech
main 함수가 종료되면 __libc_start_main+231 -> __GI_exit() -> __run_exit_handlers() -> _dl_fini()
등 여러 함수와 그 안에 있는 구조체의 포인터를 거치는데,
_dl_fini에서 불러오는 _dl_rtld_lock_recursive() 함수와 인자를 덮어쓰면 실행흐름 조작이 가능한 exploit tech이다.
_dl_rtld_lock_recursive가 없어요.
glibc 2.34 이후 버전에서 _rtld_global 구조체의 레이아웃이 변경되어 오프셋을 쉽게 못 가져온다.
최신 버전에서 exploit 하는 방법은 아래 사이트로 들어가서 소스 코드를 분석하거나 직접 디버깅하면서 __rtld_lock_recursive로 추정되는 오프셋의 값을 바꿔보는 수밖에 없다.
https://elixir.bootlin.com/glibc/glibc-2.34/source/elf/rtld.c#L315
본인이 exploit 하고 싶은 ELF의 어느 버전의 라이브러리와 매칭되는지 확인하자
glibc 구조체 비교 2.27 vs 2.35
더보기
Ubuntu 18.04 (glibc 2.27) | Ubuntu 22.04 (glibc 2.35) |
pwndbg> p _rtld_global $1 = { _dl_ns = {{ _ns_loaded = 0x7ffff7ffe170, _ns_nloaded = 4, _ns_main_searchlist = 0x7ffff7ffe428, _ns_global_scope_alloc = 0, _ns_unique_sym_table = { lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, entries = 0x0, size = 0, n_elements = 0, free = 0x0 }, _ns_debug = { r_version = 0, r_map = 0x0, r_brk = 0, r_state = RT_CONSISTENT, r_ldbase = 0 } }, { _ns_loaded = 0x0, _ns_nloaded = 0, _ns_main_searchlist = 0x0, _ns_global_scope_alloc = 0, _ns_unique_sym_table = { lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 39 times>, __align = 0 } }, entries = 0x0, size = 0, n_elements = 0, free = 0x0 }, _ns_debug = { r_version = 0, r_map = 0x0, r_brk = 0, r_state = RT_CONSISTENT, r_ldbase = 0 } } <repeats 15 times>}, _dl_nns = 1, _dl_load_lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, _dl_load_write_lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, _dl_load_adds = 4, _dl_initfirst = 0x0, _dl_cpuclock_offset = 60430389095796, _dl_profile_map = 0x0, _dl_num_relocations = 92, _dl_num_cache_relocations = 3, _dl_all_dirs = 0x7ffff7ffec90, _dl_rtld_map = { l_addr = 140737351856128, l_name = 0x555555400238 "/lib64/ld-linux-x86-64.so.2", l_ld = 0x7ffff7ffce68, l_next = 0x0, l_prev = 0x7ffff7fee000, l_real = 0x7ffff7ffd9f0 <_rtld_global+2448>, l_ns = 0, l_libname = 0x7ffff7ffe030 <_dl_rtld_libname>, l_info = {0x0, 0x0, 0x7ffff7ffcee8, 0x7ffff7ffced8, 0x7ffff7ffce78, 0x7ffff7ffce98, 0x7ffff7ffcea8, 0x7ffff7ffcf18, 0x7ffff7ffcf28, 0x7ffff7ffcf38, 0x7ffff7ffceb8, 0x7ffff7ffcec8, 0x0, 0x0, 0x7ffff7ffce68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff7ffcef8, 0x0, 0x0, 0x7ffff7ffcf08, 0x0 <repeats 12 times>, 0x7ffff7ffcf58, 0x7ffff7ffcf48, 0x0, 0x0, 0x7ffff7ffcf78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff7ffcf68, 0x0 <repeats 25 times>, 0x7ffff7ffce88}, l_phdr = 0x7ffff7dd3040, l_entry = 0, l_phnum = 7, l_ldnum = 0, l_searchlist = { r_list = 0x0, r_nlist = 0 }, l_symbolic_searchlist = { r_list = 0x0, r_nlist = 0 }, l_loader = 0x0, l_versions = 0x7ffff7fee900, l_nversions = 6, l_nbuckets = 17, l_gnu_bitmask_idxbits = 3, l_gnu_shift = 8, l_gnu_bitmask = 0x7ffff7dd32d8, { l_gnu_buckets = 0x7ffff7dd32f8, l_chain = 0x7ffff7dd32f8 }, { l_gnu_chain_zero = 0x7ffff7dd3338, l_buckets = 0x7ffff7dd3338 }, l_direct_opencount = 0, l_type = lt_library, l_relocated = 1, l_init_called = 1, l_global = 1, l_reserved = 0, l_phdr_allocated = 0, l_soname_added = 0, l_faked = 0, l_need_tls_init = 0, l_auditing = 0, l_audit_any_plt = 0, l_removed = 0, l_contiguous = 0, l_symbolic_in_local_scope = 0, l_free_initfini = 0, l_rpath_dirs = { dirs = 0x0, malloced = 0 }, l_reloc_result = 0x0, l_versyms = 0x7ffff7dd3914, l_origin = 0x0, l_map_start = 140737351856128, l_map_end = 140737354129776, l_text_end = 140737351992656, l_scope_mem = {0x0, 0x0, 0x0, 0x0}, l_scope_max = 0, l_scope = 0x0, l_local_scope = {0x0, 0x0}, l_file_id = { dev = 0, ino = 0 }, l_runpath_dirs = { dirs = 0x0, malloced = 0 }, l_initfini = 0x0, l_reldeps = 0x0, l_reldepsmax = 0, l_used = 1, l_feature_1 = 0, l_flags_1 = 0, l_flags = 0, l_idx = 0, l_mach = { plt = 0, gotplt = 0, tlsdesc_table = 0x0 }, l_lookup_cache = { sym = 0x7ffff7dd3480, type_class = 1, value = 0x7ffff7fee000, ret = 0x7ffff79e7110 }, l_tls_initimage = 0x0, l_tls_initimage_size = 0, l_tls_blocksize = 0, l_tls_align = 0, l_tls_firstbyte_offset = 0, l_tls_offset = 0, l_tls_modid = 0, l_tls_dtor_count = 0, l_relro_addr = 2266752, l_relro_size = 2432, l_serial = 0, l_audit = 0x7ffff7ffde60 <_rtld_global+3584> }, audit_data = {{ cookie = 0, bindflags = 0 } <repeats 16 times>}, _dl_rtld_lock_recursive = 0x7ffff7dd40e0 <rtld_lock_default_lock_recursive>, _dl_rtld_unlock_recursive = 0x7ffff7dd40f0 <rtld_lock_default_unlock_recursive>, _dl_make_stack_executable_hook = 0x7ffff7de6ea0 <__GI__dl_make_stack_executable>, _dl_stack_flags = 6, _dl_tls_dtv_gaps = false, _dl_tls_max_dtv_idx = 1, _dl_tls_dtv_slotinfo_list = 0x7ffff7fee990, _dl_tls_static_nelem = 1, _dl_tls_static_size = 4160, _dl_tls_static_used = 144, _dl_tls_static_align = 64, _dl_initial_dtv = 0x7ffff7fefe40, _dl_tls_generation = 1, _dl_init_static_tls = 0x7ffff7ddf780 <_dl_nothread_init_static_tls>, _dl_wait_lookup_done = 0x0, _dl_scope_free_list = 0x0 } |
pwndbg> p _rtld_global $1 = { _dl_ns = {{ _ns_loaded = 0x7ffff7ffe2e0, _ns_nloaded = 4, _ns_main_searchlist = 0x7ffff7ffe5a0, _ns_global_scope_alloc = 0, _ns_global_scope_pending_adds = 0, libc_map = 0x7ffff7fbb160, _ns_unique_sym_table = { lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, entries = 0x0, size = 0, n_elements = 0, free = 0x0 }, _ns_debug = { base = { r_version = 0, r_map = 0x0, r_brk = 0, r_state = RT_CONSISTENT, r_ldbase = 0 }, r_next = 0x0 } }, { _ns_loaded = 0x0, _ns_nloaded = 0, _ns_main_searchlist = 0x0, _ns_global_scope_alloc = 0, _ns_global_scope_pending_adds = 0, libc_map = 0x0, _ns_unique_sym_table = { lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 39 times>, __align = 0 } }, entries = 0x0, size = 0, n_elements = 0, free = 0x0 }, _ns_debug = { base = { r_version = 0, r_map = 0x0, r_brk = 0, r_state = RT_CONSISTENT, r_ldbase = 0 }, r_next = 0x0 } } <repeats 15 times>}, _dl_nns = 1, _dl_load_lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, _dl_load_write_lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, _dl_load_tls_lock = { mutex = { __data = { __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 1, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = '\000' <repeats 16 times>, "\001", '\000' <repeats 22 times>, __align = 0 } }, _dl_load_adds = 4, _dl_initfirst = 0x0, _dl_profile_map = 0x0, _dl_num_relocations = 94, _dl_num_cache_relocations = 3, _dl_all_dirs = 0x7ffff7fbb000, _dl_rtld_map = { l_addr = 140737353887744, l_name = 0x555555400238 "/lib64/ld-linux-x86-64.so.2", l_ld = 0x7ffff7ffce80, l_next = 0x0, l_prev = 0x7ffff7fbb160, l_real = 0x7ffff7ffdaf0 <_rtld_global+2736>, l_ns = 0, l_libname = 0x7ffff7ffe280 <_dl_rtld_libname>, l_info = {0x0, 0x0, 0x7ffff7ffcf00, 0x7ffff7ffcef0, 0x7ffff7ffce90, 0x7ffff7ffceb0, 0x7ffff7ffcec0, 0x7ffff7ffcf30, 0x7ffff7ffcf40, 0x7ffff7ffcf50, 0x7ffff7ffced0, 0x7ffff7ffcee0, 0x0, 0x0, 0x7ffff7ffce80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff7ffcf10, 0x0, 0x0, 0x7ffff7ffcf20, 0x0 <repeats 13 times>, 0x7ffff7ffcf70, 0x7ffff7ffcf60, 0x0, 0x0, 0x7ffff7ffcf90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff7ffcf80, 0x0 <repeats 25 times>, 0x7ffff7ffcea0}, l_phdr = 0x7ffff7fc3040, l_entry = 0, l_phnum = 11, l_ldnum = 0, l_searchlist = { r_list = 0x0, r_nlist = 0 }, l_symbolic_searchlist = { r_list = 0x0, r_nlist = 0 }, l_loader = 0x0, l_versions = 0x7ffff7fbbb60, l_nversions = 8, l_nbuckets = 37, l_gnu_bitmask_idxbits = 3, l_gnu_shift = 8, l_gnu_bitmask = 0x7ffff7fc3440, { l_gnu_buckets = 0x7ffff7fc3460, l_chain = 0x7ffff7fc3460 }, { l_gnu_chain_zero = 0x7ffff7fc34f0, l_buckets = 0x7ffff7fc34f0 }, l_direct_opencount = 0, l_type = lt_library, l_relocated = 1, l_init_called = 1, l_global = 1, l_reserved = 0, l_main_map = 0, l_visited = 1, l_map_used = 0, l_map_done = 0, l_phdr_allocated = 0, l_soname_added = 0, l_faked = 0, l_need_tls_init = 0, l_auditing = 0, l_audit_any_plt = 0, l_removed = 0, l_contiguous = 0, l_symbolic_in_local_scope = 0, l_free_initfini = 0, l_ld_readonly = 0, l_find_object_processed = 0, l_nodelete_active = false, l_nodelete_pending = false, l_property = lc_property_unknown, l_x86_feature_1_and = 0, l_x86_isa_1_needed = 0, l_1_needed = 0, l_rpath_dirs = { dirs = 0x0, malloced = 0 }, l_reloc_result = 0x0, l_versyms = 0x7ffff7fc3c12, l_origin = 0x0, l_map_start = 140737353887744, l_map_end = 140737354130136, l_text_end = 140737354064661, l_scope_mem = {0x0, 0x0, 0x0, 0x0}, l_scope_max = 0, l_scope = 0x0, l_local_scope = {0x0, 0x0}, l_file_id = { dev = 0, ino = 0 }, l_runpath_dirs = { dirs = 0x0, malloced = 0 }, l_initfini = 0x0, l_reldeps = 0x0, l_reldepsmax = 0, l_used = 1, l_feature_1 = 0, l_flags_1 = 0, l_flags = 0, l_idx = 0, l_mach = { plt = 0, gotplt = 0, tlsdesc_table = 0x0 }, l_lookup_cache = { sym = 0x7ffff7fc38d8, type_class = 1, value = 0x7ffff7fbb160, ret = 0x7ffff7d90e60 }, l_tls_initimage = 0x0, l_tls_initimage_size = 0, l_tls_blocksize = 0, l_tls_align = 0, l_tls_firstbyte_offset = 0, l_tls_offset = 0, l_tls_modid = 0, l_tls_dtor_count = 0, l_relro_addr = 230944, l_relro_size = 6624, l_serial = 0 }, _dl_rtld_auditstate = {{ cookie = 0, bindflags = 0 } <repeats 16 times>}, _dl_x86_feature_1 = 0, _dl_x86_feature_control = { ibt = cet_elf_property, shstk = cet_elf_property }, _dl_stack_flags = 6, _dl_tls_dtv_gaps = false, _dl_tls_max_dtv_idx = 1, _dl_tls_dtv_slotinfo_list = 0x7ffff7fbbc20, _dl_tls_static_nelem = 1, _dl_tls_static_used = 144, _dl_tls_static_optional = 512, _dl_initial_dtv = 0x7ffff7d87160, _dl_tls_generation = 1, _dl_scope_free_list = 0x0, _dl_stack_used = { next = 0x7ffff7ffe0c8 <_rtld_global+4232>, prev = 0x7ffff7ffe0c8 <_rtld_global+4232> }, _dl_stack_user = { next = 0x7ffff7d86a00, prev = 0x7ffff7d86a00 }, _dl_stack_cache = { next = 0x7ffff7ffe0e8 <_rtld_global+4264>, prev = 0x7ffff7ffe0e8 <_rtld_global+4264> }, _dl_stack_cache_actsize = 0, _dl_in_flight_stack = 0, _dl_stack_cache_lock = 0 } |
그러면 실습환경을 맞춰야지
CTF나 워게임에서 _rtld_global overwrite 문제가 나왔는데, glibc 버전이 구버전이라면 실습 환경을 맞춰주는게 편하다.
또한 도커가 제공될테니 본인의 우분투 버전을 낮추면 된다. (도커로)
Docker Ubuntu 18.04 로 내리기
더보기
Dockerfile
FROM ubuntu:18.04
ENV PATH="${PATH}:/usr/local/lib/python3.6/dist-packages/bin"
ENV LC_CTYPE=C.UTF-8
RUN apt update
RUN apt install -y \
gcc \
git \
python3 \
python3-pip \
ruby \
sudo \
tmux \
vim \
wget
# install pwndbg
WORKDIR /root
RUN git clone https://github.com/pwndbg/pwndbg
WORKDIR /root/pwndbg
RUN git checkout 2023.03.19
RUN ./setup.sh
# install pwntools
RUN pip3 install --upgrade pip
RUN pip3 install pwntools
# install one_gadget command
RUN gem install one_gadget
# install patchelf
WORKDIR /root
RUN apt install -y dh-autoreconf
RUN git clone https://github.com/NixOS/patchelf
WORKDIR /root/patchelf
RUN git checkout 0.17.2
RUN ./bootstrap.sh
RUN ./configure
RUN make
RUN make check
RUN sudo make install
WORKDIR /root
실행하기
$ CONTAINER_NAME=my_container; \
docker build . -t ubuntu1804; \
docker run -d -t --privileged --name=$CONTAINER_NAME ubuntu1804; \
docker exec -it -u root $CONTAINER_NAME bash
'Computer Security > System Hacking' 카테고리의 다른 글
glibc version에 따른 mitigations & heap exploitation (0) | 2024.07.07 |
---|---|
[ptmalloc] 리눅스 동적할당 heap 하게 공부하자 (2) : Boundary Tag, Binning편 (0) | 2024.07.03 |
[ptmalloc] 리눅스 동적할당 heap 하게 공부하자 (1) : chunk편 (0) | 2024.07.03 |
[Sandbox] 샌드박스 보안 이해하기 : 보호 기법과 우회 방법 + Linux (0) | 2024.06.30 |
[Privilege Escalation] pwnable 관점에서 chroot jail 탈옥하기 (0) | 2024.06.29 |