Translation Works Service Banner Fingerprinting In C
--- Nightcat
I. Introduction:
My translation series of articles, I am very worried that there is an error in the wrong place, but I still have to do it. I translated by my understanding. If my understanding is wrong, maybe I don't understand the part. If you accidentally translate, it will inevitably give you more misleading, so I attach the original text behind the article. Please read the comparison of the original text! The most important thing is to understand, don't just look at my words.
Second. Text: Service Banner's Identification
Introduction to 1.0
This article is a supplement to the Modular's TCPSCAN article series, covering how to use C programming to identify the Banner's identification. At the same time, it is assumed that you have already understood the TCPSCAN series of articles and have knowledge of HTTP and FTP agreements. The complete original code given in the article is separate, the purpose is to read the reader to add such a original code to your own program! The smallest library function required by all functions includes:
#include
2.0 SSH / SMTP fingerprint recognition
Before you start writing code, let's take a look at the manually identified Banner fingerprint, let us use the simplest service SSHD so far. Because it is necessary to complete it, just two steps. Connect to the target host, the service banner automatically returns to us to us.
This process can be visible:
****************************************** ********* ******** ************ * connect to daemon * ===> * daemon shows banner * ===> * get the banner * ************** ****** ************* **************************************
You can get the return Banner with a Telnet to SSH daemon.
Snow: ~ # Telnet Truncode.org 22 TRYING 207.44.194.142 ... connection to truncode.org. escape character is '^]'. ssh-1.99-openssh_3.1p1 ^] Telnet> Quit Connection Closed. Snow: ~ #
You can see when you connect to the target host, this SSH DAEMON automatically returns the version of Banner: "SSH-1.99-OpenSSH_3.1p1". This process is also easy to apply to the SMTP service Banner judgment.
Now you can connect to the 25-port of the target host:
Snow: ~ # Telnet Euronet.nl 25 TRYING 194.134.0.10 ... Connected to Euronet.nl. Escape Character is '^]'. 220 pop1.euronet.nl esmtp postfix ^] telnet> Quit Connection Closed. Snow: ~ # There is no other way to identify these two services. Because the identification of these two services is the same, I only discuss the code of the SSH DAEMON identification function. You can specify the port as SMTP. Below is a code instance that identifies SSH DAOMON:
Char * grab_sshb (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * // * remote address structure * / char * BUF_S; / * buffer string pointer * // * buffer string pointer * / Char * BNR_S; / * banner string pointer * // * banner string pointer * / int sockfd; / * socket file descriptor * // * Socket file descriptor * /
BUF_S = (char *) Malloc (250); // Established Socket SockFD = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
rmtaddr.sin_family = AF_INET; rmtaddr.sin_port = htons (t_port); rmtaddr.sin_addr.s_addr = inet_addr (t_addr); // connection if (connect (sockfd, (struct sockaddr *) & rmtaddr, sizeof (struct sockaddr)) =! 0) {Close (SOCKFD); Return NULL;} // Accept byte IF (RECV (SockFD, BUF_S, 250, 0) <= 0) {Close (SockFD); Return Null;}
BNR_S = (char *) Malloc (strn); strncpy (BNR_S, BUF_S, STRLEN (BUF_S) -1);
Close (SOCKFD); Free (BUF_S); Return BNR_S;}
This original code is quite concise, we can return the same process as the previous visualization: Connect to the target host, receive the BANENR returned by the target host, and copy the banner of the query, close the connection.
3.0 http / ftp identification
This technology is slightly difficult than SSH and SMTP, because we truthfully want to perform some information interaction with the server. A variety of easy parts is to provide some additional characters to stimulate this technology. We started HTTP service Identify, this service cannot be automatically rendered after anything is connected. It is necessary to send a request: "Head / http / 1.0 / n / n" command to the service, "/ n / N" means repeating the two cycle keys. We can get a visual process again:
************************* ******** ******** ************* ********* * connect to server * ===> * Request head * ===> * Server sends banner * ***************** *** *************** ********************** || // **** ********** ****************** * Filter Data * <=== * get the banner * ******** ******* ***************** Connect to Telnet and receive Banner. In the final data filtering, pay attention to the following process:
Snow: ~ # Telnet www.euronet.nl 80 Trying 194.134.0.158 ... connected to www.euronet.nl. escape character is '^]'. HEAD / HTTP / 1.0
HTTP / 1.1 302 Found Date: Fri, 21 Mar 2003 21:06:55 GMT Server: Apache / 1.3.26 (UNIX) location: http://home.euronet.nl/ Connection: Close Content-Type: Text / HTML Charset = ISO-8859-1
Connection Closed by Foreign Host. Snow: ~ #
You can see that many data information will be returned when a HEAD / HTTP / 1.0 command is issued. In fact, the information we are interested in is "Server:" behind. This is what we have to filter code. This code will perform the following steps: Connect the service of the target host, send the command, receive return information and filter data information:
char * ltnet_httpb (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / char * str_p; / * POINTER TO SERVER: Part * / INT SOCKFD; / * Socket File Descriptor * / int tentR_s0; / * String Iterate Integer * / ITR_S1; / * String Itereate Integer * /
BUF_S = (char *) Malloc (1000);
Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
rmtaddr.sin_family = AF_INET; rmtaddr.sin_port = htons (t_port); rmtaddr.sin_addr.s_addr = inet_addr (t_addr); if (! connect (sockfd, (struct sockaddr *) & rmtaddr, sizeof (struct sockaddr)) = 0) { Close (Sockfd); Return Null;
IF (SEND (SOCKFD, "HEAD / HTTP / 1.0 / N / N", 17, 0) <= 0) {Close (SOCKFD); Return Null;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close (SOCKFD); Return NULL;}
IF ((str_p = strstr (buf_s, "server:") == null) {close (sockfd); return null;}
For (ITR_S0 = 0; ITR_S0 BNR_S = (char *) Malloc (ITR_S0 - 8); For (ITR_S1 = 0; ITR_S1 Close (SOCKFD); Free (BUF_S); Return BNR_S;} Please pay close attention to the actual filtering section, first find "Server:" line, return a pointer to this line: IF ((str_p = strstr (buf_s, "server:") == null) {close (sockfd); return null;} Nowadolding "STR_P" points to the start address of the buffer of the "Server:" row. The next step we want to do it is that the actual Banner has a character line with "Server:", from saving to "BNR_s". We start this process to assign the memory to "BNR_s". BNR_S = (char *) Malloc (ITR_S0 - 8); please take a look at this line, we allocate the number of bytes of "Server:", minus 8. These 8 bytes are "Server:" is exactly what we want to delete. Next, we have done a complete string, copy it to "BNR_S". Now "BNR_S" contains a string without "Server:" characters. We transfer to the FTP section. We discuss two ways to identify the FTP service Banner. The first is very easy because it simply mixes SSH / SMTP and HTTP identification methods. Connect to the target host, get Banner, then filter it, this visualization process is like: ****************************************** ********* ******** ************ * connect to daemon * ===> * daemon shows banner * ===> * get the banner * ************** ****** ************************************************* || / / ************** * Filter Data * ************** If we use Telent to follow this process, it looks like the following : Snow: ~ # Telnet Euronet.nl 21 TRYING 194.134.0.10 ... Connected to EURONET.NL. Escape Character IS '^]'. 220 Gaia.EURONET.NL FTP Server (Version Wu-2.4.2-Academ (3 Fri Jun 23 20:47:26 Met DST 2000) Ready. ^] Telnet> Quit Connection Closed. Snow: ~ # As you can see, it will present Banner (this is not all cases) in "220", which may be version information. As the HTTP service is done. The following code is actually the mixed mixed by our previous: char * ltnet_ftpb (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / char * str_p; / * POINTER TO SERVER: Part * / INT SOCKFD; / * Socket File Descriptor * / int tentR_s0; / * String Iterate Integer * / ITR_S1; / * String Itereate Integer * / BUF_S = (char *) Malloc (250); Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); RMTADDR.SIN_FAMILY = AF_INET; RMTADDR.SIN_PORT = HTONS (T_Port); RMTADDR.SIN_ADDR.S_ADDR = INET_ADDR (T_ADDR); IF (Connect (STRUCKD, STRUCKADDR *) & RMTADDR, SIZEOF (STRUCT SOCKADDR))! = 0) {Close (SockFD); Return Null;} IF (RECV (SockFD, BUF_S, 250, 0) <= 0) { Close (Sockfd); Return Null; IF ((str_p = str_2)) == null) {close (sockfd); return null;} For (ITR_S0 = 0; ITR_S0 BNR_S = (char *) Malloc (ITR_S0 - 8); FOR (ITR_S1 = 0; ITR_S1 Close (SOCKFD); Free (BUF_S); Return BNR_S;} Although this FTP recognition method is very simple, it is not always effective. In addition, there is another method for identifying the FTP service. This technical requires us to go in anonymous users, and this method requires services to allow anonymous to log in. If we can successfully enter the anonymous identity, we can think that the FTP service issues "syst" commands, and the FTP service will send back the system type. The illustration of this method can be visualized as: ******************* ******************* * ***************** * connect to daemon * ===> * login to server * ==== * get the banner * ********** ********** ****************** ****************** || // ************** * Filter Data * *************** If we use telnet to follow, it looks like the following: Snow: ~ # Telnet ftp.cdrom.com 21 TRYING 208.217.74.248 ... conne. Cdrom.wip.digitalriver.com. Escape character is '^]'. 220 drftp.digitalriver.com NCFTPD Server (licensed Copy) Ready. USER anonymous 331 Guest login ok, send your complete e-mail address as password PASS ghost@truncode.org 230-You are user # 28 of 300 simultaneous users allowed 230- 230 Logged in anonymously SYST 215 UNIX Type:... L While So, this code does not present how much difference we have done before, the only difference is that we send multiple commands to the service ("user", "pass" and "system"), after this process, we filtered again Data information, the following is the code: char * ltnet_ftps (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / char * str_p; / * POINTER TO SERVER: Part * / INT SOCKFD; / * Socket File Descriptor * / int tentR_s0; / * String Iterate Integer * / ITR_S1; / * String Itereate Integer * / BUF_S = (char *) Malloc (1000); Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); RMTADDR.SIN_FAMILY = AF_INET; RMTADDR.SIN_PORT = HTONS (T_Port); RMTADDR.SIN_ADDR.S_ADDR = INET_ADDR (T_ADDR); IF (Connect (STRUCKD, STRUCKADDR *) & RMTADDR, SIZEOF (STRUCT SOCKADDR))! = 0) {Close (Sockfd); Return Null; IF (SOND (SOCKFD, "User Anonymous / N", 15, 0) <= 0) {Close (SOCKFD); Return Null;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close SOCKFD); RETURN NULL;} IF (SOND (SOCKFD, "Pass Libtrun@truncode.org/n", 26, 0) <= 0) {Close (SOCKFD); Return Null;} IF (RECV (Sockfd, BUF_S, 1000, 0) <= 0) {Close (SOCKFD); Return NULL;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close (SockFD); Return Null;} IF (SOCKFD, "SYST / N", 5, 0) <= 0) {Close (SOCKFD); Return NULL;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close (SockFD); Return Null;} IF ((str_p = strs, "UNIX TYPE:")) == null) {close (sockfd); Return Null;} For (ITR_S0 = 0; ITR_S0 BNR_S = (char *) Malloc (ITR_S0 - 8); For (ITR_S1 = 0; ITR_S1 Close (SOCKFD); Free (BUF_S); Return BNR_S;} 4.0 Editing more code Of course, there are many ways you can identify. But I hope this article can help you understand how to start. If you are planning to perform this code, you may have to sort out, but also add more errors! Copyright (c) 2003 Truncode.org 3. With the original: Service banner fingerprinting in c _ _ | | ______________ | | ___ | _ | _ | | | | || _ | | _ | | ___ | ___ | ___ | ___ | * Truncode security development * http://www.truncode.orgnecrose 0x01 Introduction This paper is written as a supplement to modular's tcpscan series This papercovers how to write C programs that will perform Banner Fingerprinting Thispaper assumes that you have already understood the tcpscan series from modular, and that you possess knowledge of the following protocols:.. HTTP and . FTP Thecomplete source code in this article consists of stand-alone functions with theintention to allow the reader to implement them easily into his own programs.All functions require the following minimal list of includes: #include 0x02 SSH / SMTP Fingerprinting Before we start coding, we will have a look at the subject of manual bannerfingerprinting Let uss start this one off with by far the easiest service tofingerprint:.. SSHD This is because we actually only have two things to accomplish: connect to the SSH daemon At The Target Host And Retrieve The Banner That Will Be Automatically Presented To US. The Process Might Be Visually Presented Like SO: ****************************************** ********* ******** ************ * connect to daemon * ===> * daemon shows banner * ===> * get the banner * ************** ****** ************* ************************************** START by connecting with telnet to a ssh daemon and retrieve the banner: Snow: ~ # Telnet Truncode.org 22 TRYING 207.44.194.142 ... connection to truncode.org. escape character is '^]'. ssh-1.99-openssh_3.1p1 ^] Telnet> Quit Connection Closed. Snow: ~ # As you can see after connecting to the target host, the SSH daemon willautomatically present the version banner: "SSH-1.99-OpenSSH_3.1p1" This process is relatively easy and can also be applied as well to the SMTP service banner.Now we. Connect to Port 25 on the target host: Snow: ~ # Telnet Euronet.nl 25 TRYING 194.134.0.10 ... Connected to Euronet.nl. Escape Character is '^]'. 220 pop1.euronet.nl esmtp postfix ^] telnet> Quit Connection Closed. Snow: ~ # Well there is not much to fingerprinting these two services. Since the processfor fingerprinting these services is identical, I will only discuss the code for the SSH daemon fingerprint function. You can specify the port for SMTP. Thefollowing is an example of code that will fingerprint The ssh daemon: char * grab_sshb (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / int sockfd; / * Socket File Descriptor * / BUF_S = (char *) Malloc (250); Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); RMTADDR.SIN_FAMILY = AF_INET; RMTADDR.SIN_PORT = HTONS (T_Port); RMTADDR.SIN_ADDR.S_ADDR = INET_ADDR (T_ADDR); IF (Connect (STRUCKD, STRUCKADDR *) & RMTADDR, SIZEOF (STRUCT SOCKADDR))! = 0) {Close (Sockfd); Return Null; IF (RECV (SOCKFD, BUF_S, 250, 0) <= 0) {Close (SOCKFD); Return Null;} BNR_S = (char *) Malloc (strn); strncpy (BNR_S, BUF_S, STRLEN (BUF_S) -1); Close (SOCKFD); Free (BUF_S); Return BNR_S;} This source code is rather straight forward We do exactly the same as presented in the former visual process:. Connect to the target host and receivethe banner it sends, then copy the banner in question and close the connection.0x03 HTTP / FTP FINGERPRINTING This technique is slightly more difficult than SSH and SMTP because we actuallyneed to perform some interaction with the server. An obvious difference is thatwe need to incite some minor string magic for this technique to work. We beginwith HTTP server fingerprinting. The server does not automatically Present Anybanner on connect. a request to the server is needed by sending the: "head / http / 1.0 / n / n" Command, where "/ n / n" represents ************************* ******** ******** ************* ********* * connect to server * ===> * Request head * ===> * Server sends banner * ***************** *** *************** ********************** || // **** ********** ****************** * Filter Data * <=== * get the banner * ******** ****** **************************** Connect with Telnet and Retreive The Banner. The Data Filtering Will Only Bedone with The Final Code. Pay Attention To The Following Process: Snow: ~ # Telnet www.euronet.nl 80 Trying 194.134.0.158 ... connected to www.euronet.nl. escape character is '^]'. HEAD / HTTP / 1.0 HTTP / 1.1 302 Found Date: Fri, 21 Mar 2003 21:06:55 GMT Server: Apache / 1.3.26 (UNIX) location: http://home.euronet.nl/ Connection: Close Content-Type: Text / HTML Charset = ISO-8859-1 Connection Closed by Foreign Host. Snow: ~ # As you can see the server return / 1.0 command. Actually the only data we are interested in is the banner behind the "Server:". This is What Our Filter Code Will Achieve: Connect To The Server At The Target Host, Send The Command, Receivethe Server Head and Filter The Data: char * ltnet_httpb (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / char * str_p; / * POINTER TO SERVER: Part * / INT SOCKFD; / * Socket File Descriptor * / int tentR_s0; / * String Iterate Integer * / ITR_S1; / * String Itereate Integer * / BUF_S = (char *) Malloc (1000); Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); RMTADDR.SIN_FAMILY = AF_INET; RMTADDR.SIN_PORT = HTONS (T_Port); RMTADDR.SIN_ADDR.S_ADDR = INET_ADDR (T_ADDR); IF (Connect (STRUCKD, STRUCKADDR *) & RMTADDR, SIZEOF (STRUCT SOCKADDR))! = 0) {Close (Sockfd); Return Null; IF (SEND (SOCKFD, "HEAD / HTTP / 1.0 / N / N", 17, 0) <= 0) {Close (SOCKFD); Return Null;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close (SOCKFD); Return NULL;} IF ((str_p = strstr (buf_s, "server:") == null) {close (sockfd); return null;} For (ITR_S0 = 0; ITR_S0 BNR_S = (char *) Malloc (ITR_S0 - 8); FOR (ITR_S1 = 0; ITR_S1 Take a Close Look at The section Performs The Actual Filtering. First Thecode Looks At The "Server:" LINE and RETURns a Pointer to IT: IF ((str_p = strstr (buf_s, "server:") == null) {close (sockfd); return null;} NOW "STR_P" Points to Where: "Line Starts in the buffer. The nexts" Server: "LINE INFRONT OF IT AND PUT IT INTO" BNR_S ". We Start this Process my allocating memoryto "bnr_s" BNR_S = (char *) Malloc (ITR_S0 - 8); Please Take a Good Look at this line. We alltes on the "Server:" Line, Minus 8. The 8 Bytes Repesent: "Server:" Which We Want to Strip Off. The next thing we do is itereate through The string and copy it to "bnr_s". Now "BNR_S" Contains The Stripped "Server:" String. We will move onto the FTP section now. We discuss two ways of fingerprintingthe FTP server. The first one is easy, because it's just a mix of the SSH / SMTPand HTTP fingerprinting. Connect to to the target host, get the banner and thenfilter it THIS Can Be Visually Presented Like So: ****************************************** ********* ******** ************ * connect to daemon * ===> * daemon shows banner * ===> * get the banner * ************** ****** ************************************************* || / / ************** * filter data * * ************** If We emulate this process with telnet, IT Will Look Like the Following: Snow: ~ # Telnet eund.nl 21 TRYING 194.134.0.10 ... connection to eund.nl. escape character is '^]'. 220 Gaia.EURONET.NL FTP Server (Version Wu-2.4.2-Academ (3) Fri Jun 23 20:47:26 Met DST 2000) Ready. ^] Telnet> Quit Connection Closed. Snow: ~ # As you can see it will directly present the banner (this is not what happens in all cases) after the "220" and then it is possible to strip it down to the version only, just like what was done with the HTTP server. The Code Is Actually Just A Mix of What We Have Done BEFORE: char * ltnet_ftpb (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / char * str_p; / * POINTER TO SERVER: Part * / INT SOCKFD; / * Socket File Descriptor * / int tentR_s0; / * String Iterate Integer * / ITR_S1; / * String Itereate Integer * / BUF_S = (char *) Malloc (250); Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); rmtaddr.sin_family = AF_INET; rmtaddr.sin_port = htons (t_port); rmtaddr.sin_addr.s_addr = inet_addr (t_addr); if (! connect (sockfd, (struct sockaddr *) & rmtaddr, sizeof (struct sockaddr)) = 0) { Close (Sockfd); Return Null; IF (RECV (SOCKFD, BUF_S, 250, 0) <= 0) {Close (SOCKFD); Return Null;} IF ((str_p = str_2)) == null) {close (sockfd); return null;} For (ITR_S0 = 0; ITR_S0 BNR_S = (char *) Malloc (ITR_S0 - 8); FOR (ITR_S1 = 0; ITR_S1 Close (SOCKFD); Free (BUF_S); Return BNR_S;} Although this way of FTP fingerprinting is fairly straight forward, it may notalways be effective. But there is another way of fingerprinting the FTP server, a technique that requires us to login with the anonymous account. This method requires the server to have the anonymous login . enabled If we can succesfullylog in as an anonymous user we can give the "SYST" command and the FTP server will send back the system type The scheme that represents this method is presented visually like so.: *************************************** ********* ********** ******** * connect to daemon * ===> * login to server * ===> * get the banner * ******************* ************************************** || // ******** ******** * filter data * ********************** If We emulate this with telnet, IT WILL LOOK LIKE The FOLLOWING: Snow: ~ # Telnet ftp.cdrom.com 21 TRYING 208.217.74.248 ... conne. Cdrom.wip.digitalriver.com. Escape character is '^]'. 220 drftp.digitalriver.com NCFTPD Server (licensed Copy) Ready. USER anonymous 331 Guest login ok, send your complete e-mail address as password PASS ghost@truncode.org 230-You are user # 28 of 300 simultaneous users allowed 230- 230 Logged in anonymously SYST 215 UNIX Type:... L8 Still this code does not show a lot of difference compared to what we have donebefore. The only difference is that we send multiple commands to the server ( "USER", "PASS" and "SYST"). After that process we just filter the Data Again. this is the code to achieve what: char * ltnet_ftps (char * t_addr, int t_port) {struct sockaddr_in rmtaddr; / * remote address structure * / char * buf_s; / * buffer string pointer * / char * bnr_s; / * banner string pointer * / char * str_p; / * POINTER TO SERVER: Part * / INT SOCKFD; / * Socket File Descriptor * / ITR_S0; / * String IteRate Integer * / ITR_S1; / * String Itereate Integer * / BUF_S = (CHAR *) Malloc (1000); Sockfd = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); RMTADDR.SIN_FAMILY = AF_INET; RMTADDR.SIN_PORT = HTONS (T_Port); RMTADDR.SIN_ADDR.S_ADDR = INET_ADDR (T_ADDR); IF (Connect (STRUCKD, STRUCKADDR *) & RMTADDR, SIZEOF (STRUCT SOCKADDR))! = 0) {Close (Sockfd); Return Null; IF (SOND (SOCKFD, "User Anonymous / N", 15, 0) <= 0) {Close (SOCKFD); Return Null;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close SOCKFD); RETURN NULL;} IF (SOND (SOCKFD, "Pass Libtrun@truncode.org/n", 26, 0) <= 0) {Close (SOCKFD); Return Null;} IF (RECV (Sockfd, BUF_S, 1000, 0) <= 0) {Close (SOCKFD); Return NULL;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close (SockFD); Return Null;} IF (SOCKFD, "SYST / N", 5, 0) <= 0) {Close (SOCKFD); Return NULL;} IF (RECV (SOCKFD, BUF_S, 1000, 0) <= 0) {Close (SockFD); Return Null;} IF ((str_p = strs, "UNIX TYPE:")) == null) {close (sockfd); Return Null;} For (ITR_S0 = 0; ITR_S0 BNR_S = (char *) Malloc (ITR_S0 - 8); For (ITR_S1 = 0; ITR_S1 0x04 Weave More Code Of course there is a lot more you can fingerprint, but I hope this paper hashelped to show you how you might begin. If you are going to implement the codein this paper, you might clean it up and add some error checking. Copyright (c) 2003 Truncode.org