Upload
others
View
10
Download
0
Embed Size (px)
Citation preview
Ready Made Bots
Phenny - Python – http://inamidst.com/phenny/
Cinch – Ruby – https://github.com/cinchrb/cinch
Egg Drop – C,TCl – http://www.eggheads.org/
http://en.wikipedia.org/wiki/Comparison_of_Internet_Relay_Chat_bots
Why Write an IRC Bot?
Arduino Bot – pyserial – Control Real Devices
Speaking Bot – espeak – Say Things
Command and Control Bot - bash – Run Commands
Error Notification Bot – sockets / web API – Send messages to groups of people
NemusBOT! (Sheep)
Python Code https://github.com/obscuritysystems/NemusBot
● IRC Components – Socket connection
• Join channel. • Check for identity and register.
– While Loop • Message parsing.
- Executing commands.
UDP Socket Client
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
MESSAGE = "Hello, World!"
print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT
print "message:", MESSAGE
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
UPD Socket Server
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024)
print "received message:", data
TCP Client
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!”
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
print "received data:", data
TCP Server #!/usr/bin/env python
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 20 # Normally 1024, but we want fast response
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connection address:', addr
while 1:
data = conn.recv(BUFFER_SIZE)
print "received data:", data
conn.send(data) # echo
conn.close()
Blocking Sockets
• http://docs.python.org/2/howto/sockets.html
• In Python, you use socket.setblocking(0) to make it non-blocking.
• When the socket is non blocking it will throw an error when there is no data or the socket is not available to write data.
• The major mechanical difference is that send, recv, connect and accept can return without having done anything.
• You have (of course) a number of choices. You can check return code and error codes and generally drive yourself crazy.
Python Socket Select
ready_to_read, ready_to_write, in_error = \ select.select( potential_readers, potential_writers, potential_errs, timeout)
• You pass select three lists: the first contains all sockets that you might want to try reading; the second all the sockets you might want to try writing to, and the last (normally left empty) those that you want to check for errors. You should note that a socket can go into more than one list. The select call is blocking, but you can give it a timeout
• In return, you will get three lists. They contain the sockets that are actually readable, writable and in error. Each of these lists is a subset (possibly empty) of the corresponding list you passed in.
Connecting to an IRC SERVER
### CODE
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Here we connect to the server using the port 6667
ircsock.connect((‘chat.freenode.net’, 6667))
ircsock.send('USER '+nicks+' host '+host_name+' : Nemus Brand Bot\r\n')
### OUPUT
:pratchett.freenode.net NOTICE * :*** Looking up your hostname...
:pratchett.freenode.net NOTICE * :*** Checking Ident
:pratchett.freenode.net NOTICE * :*** Found your hostname
:pratchett.freenode.net NOTICE * :*** No Ident response
:pratchett.freenode.net 001 WhyYouMakeaMeBot :Welcome to the freenode Internet Relay Chat Network WhyYouMakeaMeBot
:pratchett.freenode.net 002 WhyYouMakeaMeBot :Your host is pratchett.freenode.net[192.168.25.107/6667], running version ircd-seven-1.1.3
IRC Protocol
IRC RFC • http://tools.ietf.org/html/rfc2812
IRC Over Telnet • http://oreilly.com/pub/h/1963
The message format Parameters: :<prefix> <command> <params> :<trailing> test@localhost PRIVMSG #mychannel :Hello everyone!
Prefix Parameter
The prefix of the messages represents the origin of the message, If there is no prefix, then the source of the message is the server for the current connection, as in the PING example.
• PING :wright.freenode.net
The presence of a prefix is indicated by the message beginning with a colon character. The prefix cannot contain a white space so you can parse the first part and stop at the prefix.
So in this example :write.freenode.net is the prefix
• :wright.freenode.net NOTICE * :*** Looking up your hostname…
The Command Parameter
• The command part is the meat of the IRC message instructing your bot what action needs to be taken.
• Example Commands • PRIVMSG, QUIT, JOIN, MODE, and PING.
• In the case of the PRIVMSG example, an bot might log a users message to the database, display it on the terminal or execute some command.
• With QUIT and JOIN, the Bot would keep change state to keep track a user has quit the server or joined the channel
Numeric Commands
• Some messages contain commands as text other messages have numeric replies. An IRC bot will receive numeric replies in the event it sends a requests to the irc server .
• Example
• we send the command • NICK BadABot
• We Receive • :irc.localhost.localdomain 433 BadABot:Nickname is
already in use • In the message the 433 portion is the command
• Looking in the RFC for the IRC protocol we see the reply of 433 is used if a nickname is already in use.
The Params Parameter
• The params portion is a set of space separated parameters.
• Not all messages have parameters, but many do.
• test@localhost PRIVMSG #channel :Hello
• The channel name (#channel) of the PRIVMSG, JOIN, and MODE messages is a parameter
The Trail
• The Trail is the last parameter and because params are separated by space, it isn't possible to include the trail parameter with a space in the normal set of parameters. • The very last parameter is indicated with a leading colon, this means
that everything after the colon should be interpreted together. This allows a message to carry one fully textual piece. • Later we will further parse this string for our specific IRC BOT commands
• The defining characteristic of the trailing part is that it also begins with a colon but is preceded by a space.
• The trailing portions continues until the end of the message
• Simply grab the substring of the message that begins at the first occurrence of " :" (a space and colon).
Regular Expression Parsing
import re
string1 = ':wright.freenode.net NOTICE * :*** Looking up your hostname...’
regex = '^(:(\S+) )?(\S+)( (?!:)(.+?))?( :(.+))?$’
matchObj = re.match(regex, string1, re.M|re.I)
if matchObj:
print "matchObj.group() : ", matchObj.group()
print "matchObj.group(1): ", matchObj.group(1)
print "matchObj.group(2): ", matchObj.group(2)
print "matchObj.group(3): ", matchObj.group(3)
print "matchObj.group(4): ", matchObj.group(4)
print "matchObj.group(5): ", matchObj.group(5)
print "matchObj.group(6): ", matchObj.group(6)
else:
print "No match!!"
Code Parsing of IRC messages def parsemsg(s):
prefix = ''
trailing = []
if not s:
raise IRCBadMessage("Empty line.")
if s[0] == ':':
prefix, s = s[1:].split(' ', 1)
if s.find(' :') != -1:
s, trailing = s.split(' :', 1)
args = s.split()
args.append(trailing)
else:
args = s.split()
command = args.pop(0)
return prefix, command, args
Regex Sheep
if self.sheep and text.find(':!sheep_paging') == -1:
regex_array = re.findall(self.sheep_regex,text)
self.sendm(parsed_msg['handle'].split('!~')[0] + ' said \'sheep\'. Paging L34N. Someone said \'sheep\'');
self.send_email(parsed_msg, self.sheep_number,"[email protected]","SHEEP")
sheep_regex = '.*[sS$5]+[hH(|-|)]+[eE3]+[pP]+.*’ #metacortex
Text Messaging
import smtplib
SERVER = "10.x.x.1"
FROM = "[email protected]"
TO = ["[email protected]"] # must be a list
SUBJECT = "Hello!"
TEXT = "This message was sent with Python's smtplib.”
# Prepare actual message
message = """\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
# Send the mail
server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
Basic Bot
# Import some necessary libraries.
import socket
import time
# Some basic variables used to configure the bot
server = "chat.freenode.net" # Server
channel = "#test198" # Channel
botnick = "NemusBot2" # Your bots nick
nicks = "NemusBot2"
host_name = "Test”
Basic Bot 2
# This is our first function! It will respond to server Pings. def ping():
ircsock.send("PONG :pingis\n”)
# This is the send message function, it simply sends messages to the channel.
def sendmsg(chan , msg):
ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n”)
# This function is used to join channels.
def joinchan(chan):
ircsock.send("JOIN "+ chan +"\n”)
# This function responds to a user that inputs "Hello Mybot" def hello():
ircsock.send("PRIVMSG "+ channel +" :Hello!\n”)
Basic Bot 3
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Here we connect to the server using the port 6667
ircsock.connect((server, 6667))
ircsock.send('USER '+nicks+' host '+host_name+' : Nemus Brand Bot\r\n')
# here we actually assign the nick to the bot
ircsock.send("NICK "+ botnick +"\n")
# Join the channel using the functions we previously defined
joinchan(channel)
Basic Bot 4
while 1: # receive data from the server
ircmsg = ircsock.recv(2048) # removing any unnecessary linebreaks.
ircmsg = ircmsg.strip('\n\r')
# Here we print what's coming from the server
print(ircmsg) # If we can find "Hello Mybot" it will call the function hello()
if ircmsg.find(":Hello "+ botnick) != -1:
hello() # if the server pings us then we've got to respond!
if ircmsg.find("PING :") != -1:
ping()
Forking
#!/usr/bin/env python
"""A basic forking action"””
import os
def my_fork():
child_pid = os.fork()
if child_pid == 0:
print "Child Process: PID# %s" % os.getpid()
else:
print "Parent Process: PID# %s" % os.getpid()
if __name__ == "__main__":
my_fork()
Daemon Class
#!/usr/bin/env python
import sys, time
from daemon import Daemon
class MyDaemon(Daemon):
def run(self):
while True:
time.sleep(1)
#bot code here
if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-example.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]: daemon.start()
elif 'stop' == sys.argv[1]: daemon.stop()
elif 'restart' == sys.argv[1]: daemon.restart()
else:
print "Unknown command” sys.exit(2)
sys.exit(0)
else: print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)
http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python
Sqlite3 Simple IPC (Inter Process Communcation)
import sqlite3 as lite
self.con = lite.connect('/tmp/speakbot.db')
cur = self.con.cursor()
cur.execute("create TABLE if not exists talk ( id INTEGER PRIMARY KEY AUTOINCREMENT, handle TEXT, channel TEXT , message TEXT)")
self.con.commit()
cur = self.con.cursor()
cur.execute('INSERT INTO talk(handle,channel,message) values (?,?,?)',(parsed_msg['handle'],parsed_msg['channel'],parsed_msg['text']))
self.con.commit()
Espeak for Speaking Bot
while self.running:
time.sleep(1)
cur = self.con.cursor()
cur.execute("select id,handle,channel,message from talk limit 1")
rows = cur.fetchall()
for row in rows:
#print row
speak = re.sub(r'[^\w]', ' ', row[3])
print row
cmd = 'espeak -s 130 "%s"'% speak
print cmd
cur.execute("delete from talk where id = ?",(row[0],))
self.con.commit()
Python Curl Web Calls
import pycurl
import json
import StringIO
c = pycurl.Curl()
c.setopt(c.URL, 'http://data.mtgox.com/api/2/BTCUSD/money/ticker')
c.setopt(c.CONNECTTIMEOUT, 5)
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(c.TIMEOUT, 8)
b = StringIO.StringIO()
c.setopt(c.COOKIEFILE, '')
c.setopt(c.FAILONERROR, True)
c.setopt(c.HTTPHEADER, ['Accept: application/json', 'Content-Type: application/x-www-form-urlencoded'])
c.setopt(pycurl.WRITEFUNCTION, b.write)
try:
c.perform()
bitcoin_data = json.loads(b.getvalue())
print bitcoin_data
except pycurl.error, error:
errno, errstr = error
print 'An error occurred: ', errstr
Executing a command getting output
########### pg1
import subprocess
output=subprocess.Popen(["ls", "-lah"], stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
print output
################### pg2
import os
retvalue = os.system(“ls")
print retvalue
Goes to standard out
Command Function
def command(msg):
regex = '^(:(\S+) )?(\S+)( (?!:)(.+?))?( :(.+))?$'
matchObj = re.match(regex, msg, re.M|re.I)
trail = matchObj.group(6)
commands = trail.split()
commands.remove(commands[0]) # remove first part of the trail
print commands
output=subprocess.Popen(commands, stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
pre = "PRIVMSG "+ channel +" :"+str(output)+"\n"
ircsock.send(pre)
Authorization import hmac, time
from hashlib import sha1
from base64 import b64encode, b64decode
def generate_sig(msg,salt):
signature = hmac.new(salt,msg,sha1).hexdigest()
command = msg + '|signature:'+signature
return command
def validate_sig(msg,salt):
rslt = command_sig.split('|')
sig_time = rslt[1].split(':')[1]
sig_cmd = rslt[2]
sig = rslt[3].split(':')[1]
now = time.time()
time_diff = abs(float(sig_time) - now)
if time_diff < 5.00 :
command = rslt[0]+'|'+rslt[1] + '|'+rslt[2]
print command
gen_signature = hmac.new(salt,command,sha1).hexdigest()
if gen_signature == sig:
return True
else:
return False
Encryption
import gnupg
gpg = gnupg.GPG(gnupghome='/home/testgpguser/gpghome')
unencrypted_string = 'Who are you? How did you get in my house?'
encrypted_data = gpg.encrypt(unencrypted_string, '[email protected]')
encrypted_string = str(encrypted_data)
print 'ok: ', encrypted_data.ok
print 'status: ', encrypted_data.status
print 'stderr: ', encrypted_data.stderr
print 'unencrypted_string: ', unencrypted_string
print 'encrypted_string: ', encrypted_string
http://www.saltycrane.com/blog/2011/10/python-gnupg-gpg-example/
Next Phase Nemus WoRm!
SSH Brute Forcing • Twisted Python Conch –
• http://twistedmatrix.com/documents/current/conch/examples/
VNC Brute Forcing and Control • https://github.com/sibson/vncdotool
• RDP using rdesktop • http://www.soldierx.com/tutorials/Brute-forcing-RDP-Linux-Rdesktop
http://www.darknet.org.uk/2006/12/writing-worms-for-fun-or-profit/
San's Paper on Writing Code for BotNets
● http://www.sans.org/reading_room/
whitepapers/covert/byob-build-botnet_33729