Skip to content

Commit

Permalink
Merge pull request #7 from botherder/master
Browse files Browse the repository at this point in the history
Added Cuckoo Sandbox HPFeeds reporting module
  • Loading branch information
rep committed Jul 4, 2012
2 parents df9311a + 491b063 commit 0fee3c9
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 0 deletions.
20 changes: 20 additions & 0 deletions cuckoo/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Cuckoo Sandbox HPFeeds Reporting Module
=======================================

This is a module you can use to push Cuckoo's JSON report to an HPFeeds
broker.

In order to install it, follow these steps:
- Put hpfeeds.py in "lib/"
- Put hpfclient.py in "modules/reporting/"
- Append the following section to "conf/reporting.conf":

[hpfclient]
enabled = on
host = <host name>
port = 10000
ident = <ident>
secret = <secret key>
channel = <channel name>

The module will be automatically executed when each analysis is completed.
36 changes: 36 additions & 0 deletions cuckoo/hpfclient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json

from lib.cuckoo.common.abstracts import Report
from lib.cuckoo.common.exceptions import CuckooDependencyError, CuckooReportError

try:
import lib.hpfeeds as hpfeeds
except:
raise CuckooDependencyError("Unable to import HPFeeds library")

# This file should be placed in "modules/reporting/" in Cuckoo >= 0.4.
# You should have the hpfeeds.py library installed in "lib/" and you should
# place the following configuration section in "conf/reporting.conf":
#
# [hpfclient]
# enabled = on
# host = <host name>
# port = 10000
# ident = <ident>
# secret = <secret key>
# channel = <channel name>

class HPFClient(Report):
"""Publishes the results on an HPFeeds broker channel."""

def run(self, results):
"""Sends JSON report to HPFeeds channel.
@param results: Cuckoo results dict.
@raise CuckooReportError: if fails to write report.
"""
try:
hpc = hpfeeds.HPC(self.options["host"], self.options["port"], self.options["ident"], self.options["secret"], timeout=60)
hpc.publish(self.options["channel"], json.dumps(results, sort_keys=False, indent=4))
hpc.close()
except hpfeeds.FeedException as e:
raise CuckooReportError("Failed to publish on HPFeeds channel: %s" % e.message)
156 changes: 156 additions & 0 deletions cuckoo/hpfeeds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@

import struct
import socket
import hashlib
import logging
from time import sleep

logger = logging.getLogger('pyhpfeeds')

OP_ERROR = 0
OP_INFO = 1
OP_AUTH = 2
OP_PUBLISH = 3
OP_SUBSCRIBE = 4
BUFSIZ = 16384

__all__ = ["new", "FeedException"]

def msghdr(op, data):
return struct.pack('!iB', 5+len(data), op) + data
def msgpublish(ident, chan, data):
# if isinstance(data, str):
# data = data.encode('latin1')
return msghdr(OP_PUBLISH, struct.pack('!B', len(ident)) + ident + struct.pack('!B', len(chan)) + chan + data)
def msgsubscribe(ident, chan):
return msghdr(OP_SUBSCRIBE, struct.pack('!B', len(ident)) + ident + chan)
def msgauth(rand, ident, secret):
hash = hashlib.sha1(rand+secret).digest()
return msghdr(OP_AUTH, struct.pack('!B', len(ident)) + ident + hash)

class FeedUnpack(object):
def __init__(self):
self.buf = bytearray()
def __iter__(self):
return self
def next(self):
return self.unpack()
def feed(self, data):
self.buf.extend(data)
def unpack(self):
if len(self.buf) < 5:
raise StopIteration('No message.')

ml, opcode = struct.unpack('!iB', buffer(self.buf,0,5))
if len(self.buf) < ml:
raise StopIteration('No message.')

data = bytearray(buffer(self.buf, 5, ml-5))
del self.buf[:ml]
return opcode, data

class FeedException(Exception):
pass

class HPC(object):
def __init__(self, host, port, ident, secret, timeout=3, reconnect=False, sleepwait=20):
self.host, self.port = host, port
self.ident, self.secret = ident, secret
self.timeout = timeout
self.reconnect = reconnect
self.sleepwait = sleepwait
self.brokername = 'unknown'
self.connected = False
self.stopped = False
self.unpacker = FeedUnpack()

self.connect()

def connect(self):
logger.info('connecting to {0}:{1}'.format(self.host, self.port))
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.settimeout(self.timeout)
try: self.s.connect((self.host, self.port))
except: raise FeedException('Could not connect to broker.')
self.connected = True

try: d = self.s.recv(BUFSIZ)
except socket.timeout: raise FeedException('Connection receive timeout.')

self.unpacker.feed(d)
for opcode, data in self.unpacker:
if opcode == OP_INFO:
rest = buffer(data, 0)
name, rest = rest[1:1+ord(rest[0])], buffer(rest, 1+ord(rest[0]))
rand = str(rest)

logger.debug('info message name: {0}, rand: {1}'.format(name, repr(rand)))
self.brokername = name

self.s.send(msgauth(rand, self.ident, self.secret))
break
else:
raise FeedException('Expected info message at this point.')

self.s.settimeout(None)

def _run(self, message_callback, error_callback):
while not self.stopped:
while self.connected:
d = self.s.recv(BUFSIZ)
if not d:
self.connected = False
break

self.unpacker.feed(d)
for opcode, data in self.unpacker:
if opcode == OP_PUBLISH:
rest = buffer(data, 0)
ident, rest = rest[1:1+ord(rest[0])], buffer(rest, 1+ord(rest[0]))
chan, content = rest[1:1+ord(rest[0])], buffer(rest, 1+ord(rest[0]))

message_callback(str(ident), str(chan), content)
elif opcode == OP_ERROR:
error_callback(data)

if self.stopped: break

if self.stopped: break
self.connect()

def run(self, message_callback, error_callback):
if not self.reconnect:
self._run(message_callback, error_callback)
else:
while True:
self._run(message_callback, error_callback)
# reconnect now we've failed
sleep(self.sleepwait)
while True:
try:
self.connect()
break
except FeedException:
sleep(self.sleepwait)

def subscribe(self, chaninfo):
if type(chaninfo) == str:
chaninfo = [chaninfo,]
for c in chaninfo:
self.s.send(msgsubscribe(self.ident, c))
def publish(self, chaninfo, data):
if type(chaninfo) == str:
chaninfo = [chaninfo,]
for c in chaninfo:
self.s.send(msgpublish(self.ident, c, data))

def stop(self):
self.stopped = True

def close(self):
try: self.s.close()
except: logger.warn('Socket exception when closing.')

def new(host=None, port=10000, ident=None, secret=None, reconnect=True, sleepwait=20):
return HPC(host, port, ident, secret, reconnect)

0 comments on commit 0fee3c9

Please sign in to comment.