Exploit Writing (N0Pspoof): Portspoof Evasion
Introduction
In the previous blog (Read Here), Portspoof
explained well and how we can abuse it’s logic to bypass it. Now, it’s the time to write a full exploit to take advantaged of it and scan a range of ports.
Writing Our tool
Header files
These are all C header files that are being included in the code. Each of them contains declarations for functions, variables and types that are used in the code that follows.
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <errno.h>
-
#include <sys/socket.h>
: This header file contains the definitions of the socket-related data types, structures, and functions needed for socket programming. It includes the definitions for creating and manipulating sockets, as well as functions for interacting with the underlying transport protocol (typically TCP or UDP). -
#include <arpa/inet.h>
: This header file contains the definitions for internet operations such as IP addresses, port numbers, and protocol families. It provides functions to convert between human-readable and network-readable addresses, and also defines constants for common internet protocols such as TCP and UDP. -
#include <unistd.h>
: This header file provides various system calls and library functions that are used for performing basic file and process management operations in POSIX systems, like read, write, close, sleep, getpid, etc. -
#include <string.h>
: This header file contains a set of functions to manipulate arrays of characters, such as strcmp, strcpy, strlen, etc. -
#include <sys/time.h>
: This header file provides functions and data structures for measuring time, like gettimeofday, timeval, timespec, etc. -
#include <errno.h>
: This header file contains the global variable errno, which is set by various library functions and system calls to indicate the error that occurred during their execution. It also contains some commonly used error codes and macros.
Scanning Functions
- TCP
void TCP_scan(char* host, int start_port, int end_port, struct timeval timeout) {
for (int port = start_port; port <= end_port; port++) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(host);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (connect(sock, (struct sockaddr *) &server, sizeof(server)) == 0) {
char buffer[32];
int bytes_sent = send(sock, buffer, sizeof(buffer), 0);
if (bytes_sent > 0) {
int bytes_received = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {
printf("[+] Port %d is open\n", port);
} else if (bytes_received == -1 && errno == EAGAIN) {
printf("[+] Port %d is open\n", port);
}
}
close(sock);
} else {
//printf("[+] Port %d is closed\n", port);
}
close(sock);
}
}
The TCP
function takes four parameters:
-
host
: a char pointer to the hostname or IP address of the target machine. -
start_port
: an integer representing the start of the port range to be scanned. -
end_port
: an integer representing the end of the port range to be scanned. -
timeout
: a struct timeval representing the timeout for the receive operation.
The function starts a for loop that iterates through all the ports in the specified range. For each port, it creates a new socket using the socket()
function, with the AF_INET
parameter for IPv4 addresses, SOCK_STREAM
for TCP
protocol,Then sets the timeout value for the socket using the setsockopt()
function with the SOL_SOCKET
and SO_RCVTIMEO
options. Next, the function creates a struct sockaddr_in
called server, which is used to store the host’s IP address and port number. The function converts the host’s IP address to a 32-bit number using inet_addr()
and sets the sin_addr.s_addr
field of the server struct. The sin_family field is set to AF_INET
and the sin_port
field is set to the current port number in the for loop, converted to network byte order using htons()
. The function then creates a buffer and sends an empty packet to the server using the sendto()
function. If the sendto()
function returns a value greater than 0
, it means that the packet was sent successfully. Then uses the recv()
function to receive a response from the server. If the recv()
function returns a value greater than 0
, it means that there is an open port, and the function prints a message indicating that the port is open. If the recv()
function returns -1
and the errno value is EAGAIN
, it means that the response timed out and the port is open. Finally, the function closes the socket using the close()
function. The function repeats the process for all the ports in the specified range.
- UDP
void UDP_scan(char* host, int start_port, int end_port, struct timeval timeout) {
for (int port = start_port; port <= end_port; port++) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(host);
server.sin_family = AF_INET;
server.sin_port = htons(port);
char buffer[32];
int bytes_sent = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&server, sizeof(server));
if (bytes_sent > 0) {
int bytes_received = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {
printf("[+] Port %d is open\n", port);
} else if (bytes_received == -1 && errno == EAGAIN) {
printf("[+] Port %d is open\n", port);
}
} else {
//printf("[+] Port %d is closed\n", port);
}
close(sock);
}
}
The UDP
function takes four parameters:
-
host
: a char pointer to the hostname or IP address of the target machine. -
start_port
: an integer representing the start of the port range to be scanned. -
end_port
: an integer representing the end of the port range to be scanned. -
timeout
: a struct timeval representing the timeout for the receive operation.
The function starts a for loop that iterates through all the ports in the specified range. For each port, it creates a new socket using the socket()
function, with the AF_INET
parameter for IPv4 addresses, SOCK_DGRAM
for UDP
protocol, and a value of 0
for the protocol.Then sets the timeout value for the socket using the setsockopt()
function with the SOL_SOCKET
and SO_RCVTIMEO
options. Next, the function creates a struct sockaddr_in
called server, which is used to store the host’s IP address and port number. The function converts the host’s IP address to a 32-bit number using inet_addr()
and sets the sin_addr.s_addr
field of the server struct. The sin_family field is set to AF_INET
and the sin_port
field is set to the current port number in the for loop, converted to network byte order using htons()
. The function then creates a buffer and sends an empty packet to the server using the sendto()
function. If the sendto()
function returns a value greater than 0
, it means that the packet was sent successfully. Then uses the recv()
function to receive a response from the server. If the recv()
function returns a value greater than 0
, it means that there is an open port, and the function prints a message indicating that the port is open. If the recv()
function returns -1
and the errno value is EAGAIN
, it means that the response timed out and the port is open. Finally, the function closes the socket using the close()
function. The function repeats the process for all the ports in the specified range.
Main function
int main() {
char host[256];
int start_port, end_port;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int scan_type;
printf("[+] N0Pspoof is a tool to bypass and evade Portspoof solution \n");
printf("[+] By: Zeyad Azima\n");
printf("[+] Github: https://github.com/Zeyad-Azima/N0Pspoof\n");
printf("\n");
printf("[+] Target Behind Portspoof: ");
scanf("%255s", host);
printf("[+] Enter the start port: ");
scanf("%d", &start_port);
printf("[+] Enter the end port: ");
scanf("%d", &end_port);
printf("[+] Choose the scan type: \n 1) TCP \n 2) UDP \n");
scanf("%d", &scan_type);
printf("\n");
if (scan_type == 1) {
printf("[+] Scan Info:\n[*] Target: %s [*] Ports Range: %d-%d [*] Scan Type: TCP\n", host, start_port, end_port);
TCP_scan(host, start_port, end_port, timeout);
} else if (scan_type == 2) {
printf("[+] Scan Info:\n[*] Target: %s [*] Ports Range: %d-%d [*] Scan Type: UDP\n", host, start_port, end_port);
UDP_scan(host, start_port, end_port, timeout);
} else {
printf("Invalid scan type\n");
}
return 0;
}
-
host
: is an array of characters with a maximum size of 256, which will be used to store the target host entered by the user. -
start_port
: andend_port
: are integers that will be used to store the start and end ports entered by the user. -
timeout
: is a struct of typetimeval
, which is used to store the timeout value for the scan. The struct has two members:tv_sec
andtv_usec
. In this case,tv_sec
is set to 5 indicating that the timeout for the scan is 5 seconds.tv_usec
is set to 0, indicating that the timeout is in seconds and not microseconds. -
scan_type
: is an integer that will be used to store the scan type chosen by the user.
When the code starts it prompts for the user to enter the target host, start and end ports, and scan type. The user input is stored in the variables:
-
host
-
start_port
-
end_port
-
scan_type
Then checks the value of scan_type
using an if-else
statement. If the value of scan_type
is 1, it means the user has chosen a TCP scan, and the program will call the TCP_scan
function, passing in the host, start and end ports, and the timeout value. If the value of scan_type
is 2, it means the user has chosen a UDP scan, and the program will call the UDP_scan
function, passing in the host, start and end ports, and the timeout value. If the value of scan_type
is not 1 or 2, it means the user has entered an invalid scan type, and the program will display an error message.
Full Code:
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <errno.h>
void TCP_scan(char* host, int start_port, int end_port, struct timeval timeout) {
for (int port = start_port; port <= end_port; port++) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(host);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (connect(sock, (struct sockaddr *) &server, sizeof(server)) == 0) {
char buffer[32];
int bytes_sent = send(sock, buffer, sizeof(buffer), 0);
if (bytes_sent > 0) {
int bytes_received = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {
printf("[+] Port %d is open\n", port);
} else if (bytes_received == -1 && errno == EAGAIN) {
printf("[+] Port %d is open\n", port);
}
}
close(sock);
} else {
//printf("[+] Port %d is closed\n", port);
}
close(sock);
}
}
void UDP_scan(char* host, int start_port, int end_port, struct timeval timeout) {
for (int port = start_port; port <= end_port; port++) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(host);
server.sin_family = AF_INET;
server.sin_port = htons(port);
char buffer[32];
int bytes_sent = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&server, sizeof(server));
if (bytes_sent > 0) {
int bytes_received = recv(sock, buffer, sizeof(buffer), 0);
if (bytes_received > 0) {
printf("[+] Port %d is open\n", port);
} else if (bytes_received == -1 && errno == EAGAIN) {
printf("[+] Port %d is open\n", port);
}
} else {
//printf("[+] Port %d is closed\n", port);
}
close(sock);
}
}
int main() {
char host[256];
int start_port, end_port;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int scan_type;
printf("[+] N0Pspoof is a tool to bypass and evade Portspoof solution \n");
printf("[+] By: Zeyad Azima\n");
printf("[+] Github: https://github.com/Zeyad-Azima/N0Pspoof\n");
printf("\n");
printf("[+] Target Behind Portspoof: ");
scanf("%255s", host);
printf("[+] Enter the start port: ");
scanf("%d", &start_port);
printf("[+] Enter the end port: ");
scanf("%d", &end_port);
printf("[+] Choose the scan type: \n 1) TCP \n 2) UDP \n");
scanf("%d", &scan_type);
printf("\n");
if (scan_type == 1) {
printf("[+] Scan Info:\n[*] Target: %s [*] Ports Range: %d-%d [*] Scan Type: TCP\n", host, start_port, end_port);
TCP_scan(host, start_port, end_port, timeout);
} else if (scan_type == 2) {
printf("[+] Scan Info:\n[*] Target: %s [*] Ports Range: %d-%d [*] Scan Type: UDP\n", host, start_port, end_port);
UDP_scan(host, start_port, end_port, timeout);
} else {
printf("Invalid scan type\n");
}
return 0;
}
You can also find the code on github.
Conclusion
Now, it’s time to compile our code using gcc
and try it out.
- Compile:
gcc N0Pspoof.c -o N0Pspoof
We will perform scanning using nmap first & then Our tool.
-
Nmap
-
N0Pspoof