• No results found

IRC Bots. Lance Buttars AKA Nemus. Code From This Talk

N/A
N/A
Protected

Academic year: 2021

Share "IRC Bots. Lance Buttars AKA Nemus. Code From This Talk"

Copied!
40
0
0

Loading.... (view fulltext now)

Full text

(1)

IRC Bots

Lance Buttars AKA Nemus

Code From This Talk

(2)

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
(3)

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

(4)

NemusBOT! (Sheep)

Python Code

https://github.com/obscuritysystems/NemusBot

● 

IRC Components

Socket connection

•  Join channel.

•  Check for identity and register.

While Loop

•  Message parsing.

(5)

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))

(6)

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

(7)

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()

(8)

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()

(9)

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.

(10)

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

(11)

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

(12)

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>

(13)

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

(14)

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

(15)

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

(16)

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,

(17)

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

(18)

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:

(19)

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)

(20)

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

(21)

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()

(22)

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"

(23)

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():

(24)

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)

(25)

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:

(26)
(27)

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__":

(28)

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)

(29)

Speaking Bot

https://github.com/obscuritysystems/

SpeakingNemusBot

(30)
(31)

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()

(32)

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()

(33)

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

(34)

Executing a command getting output

########### pg1 import subprocess output=subprocess.Popen(["ls", "-lah"], stdout=subprocess.PIPE,stderr=subprocess.PIPE).communica te() print output ################### pg2 import os retvalue = os.system(“ls") print retvalue
(35)

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"

(36)

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

(37)

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

(38)

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

(39)

San's Paper on Writing Code for

BotNets

● 

http://www.sans.org/reading_room/

(40)

References

Related documents

The explanatory emphasis in each case is not the apparent subject of the question (Mary, the treat), but the whole of which the individual is a part (the movement of the ball,

The EXs we analyze are those associated with vulcanian and strombolian eruption styles and gas bursts at Sakurajima, Suwanosejima, and Tokachi-dake in Japan, Semeru and Lokon

Тип ресурсу Призначення Алфавітний підхід Статистичний підхід Семантичний підхід Файлова система Персональний ресурс Автоматично Не застосовується

All stationary perfect equilibria of the intertemporal game approach (as slight stochastic perturbations as in Nash (1953) tend to zero) the same division of surplus as the static

Key words: Ahtna Athabascans, Community Subsistence Harvest, subsistence hunting, GMU 13 moose, Alaska Board o f Game, Copper River Basin, natural resource management,

Kemudian di tahap selanjutnya keempat subjek memilih hubungan biseksual simultan atau menjalin hubungan dengan kedua pasangan sebagai satu pilihan yang

According to the Clinical Laboratories Improvement Amendment (CLIA) guidelines, the acceptable difference range of two measurements is up to 4 mol/L for sodium and