Socket programming for fun and profit ------------------------------------- Article by darknite[@brigade.dhs.org] ** Section 0. Introduction, starting words. First of all, this is no article for experts since I'm no expert myself on either TCP/IP or C. So all of those allready familiar with the basics of socket programming may stop reading right now. And btw, I am not responsible for any actions taken due to the information within this article. If you can't take responsibility for your own actions, what makes you think anyone else can? The reason for me writing this article was both to learn and to give some usefull and creative information to all hackers/wannabes around the globe. Because even if every hacker doesn't write their own programs, they should be able to do so and understand the basics of them. After finnishing this article we should have a working portscanner and simple windows 95 netbios nuker. This article assumes some basic C programming skills from the reader along with some basic knowledge and understanding of the TCP/IP protocol. If you for some reason wish to contact me feel free to e-mail me at darknite@brigade.dhs.org or visit IRCNet, since I'm allways screened on both #hack and #hack.se. I would also like to give a big hug to plasmoid/thc for his oppinions and tips. Written for and by the hacker community. All rights reserved. ** Section 1. Finding the host. First of all, we'll have to ask ourselves "How does a portscanner work?". (Just for the sake of the article.) Well, the first thing a portscanner does is to check the number of arguments given to the program. Since I suppose you all know how to do that in C I will skip the code for it. After that it will take the hostname, (argv[1]), to see if it's valid. We will use the gethostbyname(3) to process the given argument. (see below) struct hostent *host = gethostbyname(argv[1]); The definition of hostent is found in , (as is the definition for gethostbyname()), and looks like this: /* * Structures returned by network data base library. All addresses are * supplied in host order, and returned in network order (suitable for * use in system calls). */ struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses from name server */ #define h_addr h_addr_list[0] /* address, for backward compatiblity */ }; This means that our IP number for the host given in argv[1] is stored in host->h_name. Let's write a little test program: <++> getip.c #include void main(int argc, char **argv) { struct hostent *victim; if (argc<2) { printf("use with host as argument.\n"); exit(-1); } victim = gethostbyname(argv[1]); if (!victim) { herror(argv[1]); exit(-1); } printf("%u.%u.%u.%u\n",(unsigned char)victim->h_addr[0] ,(unsigned char)victim->h_addr[1] ,(unsigned char)victim->h_addr[2] ,(unsigned char)victim->h_addr[3]); } <--> As you can see, all four segments of the IP number is stored into a separate byte. So, now we have the target host's adress. What should we do next? ** Section 2. Establish connections. A brief description of what really happens when you connect via TCP/IP to a remote host could be in place. First of all, you initiate a socket, lets call it "S". This socket allocates a free port on your computer. (It is the endpoint of the connection.) Once you have initiated a socket on your computer, you can tell that socket to connect to a port on a host. Let's say we would want to connect to the website at l0pht.com, here is what would happen. (Skipping nslookup.) Initiate socket S. (Get a free port, lets say you got 2222) Use S to connect to www.l0pht.com port 80. In theory your connection would look like: S --> www.l0pht.com:80 but in reality this is just: yourhost:2222 --> www.l0pht.com:80 So what we need to do is to create a socket and tell it where to connect. A portscanner connects to every port between a specified range on a host to see which ports(services) are opened and which ones are closed. Let's start to take a look at how to code this. To create the socket we will use the function socket(2). Here's the definition of socket(2): int socket(int domain, int type, int protocol); It returns an integer above zero(which is the socket handler), upon succes or -1 if it fails to create a socket. Example usage of socket(2) is S=socket(AF_INET,SOCK_STREAM,0). The AF_INET is the ARPA internet protocol and the one we will use. The type we will be using is SOCK_STREAM which provides a two-way connection based byte stream. The protocol argument will not be used and is therefor set to 0, due to that most of the times there only exists one protocol to support the particular socket type within the protocol family. The required header files for socket(2) and connect(2) is and . After the socket is created we will use the connect(2) to establish the connection to the target host. The definition for connect(2): int connect(int sockfd, struct sockaddr *serv_addr, int addrlen ); sockfd is the socket descriptor/handler. (S in our example) Instead of the sockaddr struct we will use the sockaddr_in struct, (so also include ). sockaddr_in looks like this: /* Structure describing an Internet (IP) socket address. */ #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ struct sockaddr_in { short int sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ /* Pad to size of `struct sockaddr'. */ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; }; struct in_addr { __u32 s_addr; }; By what you can see above, the sin_addr.s_addr is just an unsigned 32bit number to represent the IP number(for example 0x7F000001 is 127.0.0.1). So how do we convert the result in host->h_addr given by gethostbyname(3)? Easy, we'll just cast the host->h_addr with *(long *)(host->h_addr).Finally, don't forget to use the htons(3) to convert it to revers byte order on x86. And the addrlen argument is just sizeof(sockaddr). We will have to cast our sockaddr_in variable to a sockaddr struct when passing it to connect(2). And of course, one final thing, don't forget to close down your socket. Use close(2) with your socket as argument. Like: close(s) (The definition of close(2) is found in ** Section 3. The portscanner code. You should without problem be able to write a portscanner now. Included is a sample source for a simple but working portscanner. (Note that this portscanner establishes a 3 way handshake connect which is very slow.) <++> portscan.c #include #include #include #include #include #include #include #define START 1 #define STOP 1024 void main(int argc, char **argv) { int s,port; struct hostent *host; struct sockaddr_in victim; printf("PortScan v1.0 - 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); for (port=START; port<=STOP; port++) { victim.sin_port=htons(port); 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))) printf("port: %i\n",port); if (close(s)) { printf("Error closing socket.\n"); exit(-1); } } } <--> ** Section 4. Closing words. As I have said before, I am no expert on socket programming nor TCP/IP communication. But I beleive this should be enough for anyone to get started with socket programming and to write some handy tools. Since I only use Linux, everything in this article have been tested under Linux only, but I beleive that it should work fine on all other UN*X systems too. (You might have noticed that when introducing a new function I have included the man section number for that function, use man as frequently as possible.) Good luck with your programming. Best regards: Darknite, 1998. 2600 Magazine, Volume 15, Number 3, Fall 1998