Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPv6 support for kippo #168

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text eol=lf
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ __pycache__/
env/
env1/
env2/

sftp-config.json
134 changes: 134 additions & 0 deletions debian.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: kippo
# Required-Start: $remote_fs $syslog $network mysql
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: SSH honeypot
# Description: SSH honeypot
### END INIT INFO

# Author: Kevin Valk <kevin@kevinvalk.nl>
#

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/local/bin:$PATH
DESC="Kippo SSH honeypot"
NAME=kippo
DAEMON_DIR=/var/software/$NAME
DAEMON=$DAEMON_DIR/$NAME.tac
DAEMON_ARGS=""
TWISTD=/usr/local/bin/twistd
PIDFILE=$DAEMON_DIR/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
LOGFILE=log/$NAME.log

# Exit if the package is not installed
[ -x $TWISTD ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

VERBOSE=yes

#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --chdir $DAEMON_DIR --chuid $NAME:$NAME --exec $TWISTD --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --chdir $DAEMON_DIR --chuid $NAME:$NAME --exec $TWISTD -- \
--pidfile=$PIDFILE \
--logfile=$LOGFILE \
-y $DAEMON \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --chdir $DAEMON_DIR --chuid $NAME:$NAME --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --chdir $DAEMON_DIR --chuid $NAME:$NAME --oknodo --retry=0/30/KILL/5 --exec $TWISTD
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$TWISTD" "$NAME" && exit 0 || exit $?
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac

:
6 changes: 4 additions & 2 deletions doc/sql/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ CREATE TABLE `input` (

CREATE TABLE `sensors` (
`id` int(11) NOT NULL auto_increment,
`ip` varchar(15) NOT NULL,
`version` TINYINT NOT NULL,
`ip` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ;

Expand All @@ -36,7 +37,8 @@ CREATE TABLE `sessions` (
`starttime` datetime NOT NULL,
`endtime` datetime default NULL,
`sensor` int(4) NOT NULL,
`ip` varchar(15) NOT NULL default '',
`version` TINYINT NOT NULL,
`ip` varchar(45) NOT NULL default '',
`termsize` varchar(7) default NULL,
`client` int(4) default NULL,
PRIMARY KEY (`id`),
Expand Down
4 changes: 4 additions & 0 deletions doc/sql/update8.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE `sessions` CHANGE `ip` `ip` VARCHAR(45) NOT NULL DEFAULT '';
ALTER TABLE `sensors` CHANGE `ip` `ip` VARCHAR(45) NOT NULL DEFAULT '';
ALTER TABLE `sessions` ADD `version` TINYINT NOT NULL AFTER `sensor`;
ALTER TABLE `sensors` ADD `version` TINYINT NOT NULL AFTER `id`;
25 changes: 19 additions & 6 deletions kippo/core/dblog.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ def __init__(self, cfg):
self.cfg = cfg
self.sessions = {}
self.ttylogs = {}
self.re_connected = re.compile(
'^New connection: ([0-9.]+):([0-9]+) \(([0-9.]+):([0-9]+)\) ' + \
self.re_connected_ipv4 = re.compile(
'^New connection: (?:::ffff:)?([0-9.]+):([0-9]+) \((?:::ffff:)?([0-9.]+):([0-9]+)\) ' + \
'\[session: ([0-9]+)\]$')
self.re_connected_ipv6 = re.compile(
'^New connection: ([0-9a-f:]+):([0-9]+) \(([0-9a-f:]+):([0-9]+)\) ' + \
'\[session: ([0-9]+)\]$')
self.re_sessionlog = re.compile(
'.*HoneyPotTransport,([0-9]+),[0-9.]+$')
'.*HoneyPotTransport,([0-9]+),(?:(?:::ffff:)?[0-9.]+|[0-9a-f:]+)$')

# :dispatch: means the message has been delivered directly via
# logDispatch, instead of relying on the twisted logging, which breaks
Expand Down Expand Up @@ -65,13 +68,23 @@ def nowUnix(self):
def emit(self, ev):
if not len(ev['message']):
return
match = self.re_connected.match(ev['message'][0])

# Test for IPv4
match = self.re_connected_ipv4.match(ev['message'][0])
ipv = 4

# Test for IPv6
if not match:
match = self.re_connected_ipv6.match(ev['message'][0])
ipv = 6

# If IPv4 or IPv6 then we golden!
if match:
sessionid = int(match.groups()[4])
self.sessions[sessionid] = \
self.createSession(
match.groups()[0], int(match.groups()[1]),
match.groups()[2], int(match.groups()[3]))
match.groups()[2], int(match.groups()[3]), ipv)
return
match = self.re_sessionlog.match(ev['system'])
if not match:
Expand Down Expand Up @@ -102,7 +115,7 @@ def ttylog(self, session):
return ttylog

# We have to return an unique ID
def createSession(self, peerIP, peerPort, hostIP, hostPort):
def createSession(self, peerIP, peerPort, hostIP, hostPort, versionIP):
return 0

# args has: logfile
Expand Down
14 changes: 7 additions & 7 deletions kippo/dblog/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,29 @@ def simpleQuery(self, sql, args):
d = self.db.runQuery(sql, args)
d.addErrback(self.sqlerror)

def createSession(self, peerIP, peerPort, hostIP, hostPort):
def createSession(self, peerIP, peerPort, hostIP, hostPort, versionIP):
sid = uuid.uuid1().hex
self.createSessionWhenever(sid, peerIP, hostIP)
self.createSessionWhenever(sid, peerIP, hostIP, versionIP)
return sid

# This is separate since we can't return with a value
@defer.inlineCallbacks
def createSessionWhenever(self, sid, peerIP, hostIP):
def createSessionWhenever(self, sid, peerIP, hostIP, versionIP):
sensorname = self.getSensor() or hostIP
r = yield self.db.runQuery(
'SELECT `id` FROM `sensors` WHERE `ip` = %s', (sensorname,))
if r:
id = r[0][0]
else:
yield self.db.runQuery(
'INSERT INTO `sensors` (`ip`) VALUES (%s)', (sensorname,))
'INSERT INTO `sensors` (`version`, `ip`) VALUES (%s, %s)', (versionIP, sensorname,))
r = yield self.db.runQuery('SELECT LAST_INSERT_ID()')
id = int(r[0][0])
# now that we have a sensorID, continue creating the session
self.simpleQuery(
'INSERT INTO `sessions` (`id`, `starttime`, `sensor`, `ip`)' + \
' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)',
(sid, self.nowUnix(), id, peerIP))
'INSERT INTO `sessions` (`id`, `starttime`, `sensor`, `version`, `ip`)' + \
' VALUES (%s, FROM_UNIXTIME(%s), %s, %s, %s)',
(sid, self.nowUnix(), id, versionIP, peerIP))

def handleConnectionLost(self, session, args):
ttylog = self.ttylog(session)
Expand Down
2 changes: 1 addition & 1 deletion kippo/dblog/textlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def write(self, session, msg):
(session, time.strftime('%Y-%m-%d %H:%M:%S'), msg))
self.outfile.flush()

def createSession(self, peerIP, peerPort, hostIP, hostPort):
def createSession(self, peerIP, peerPort, hostIP, hostPort, versionIP):
sid = uuid.uuid1().hex
sensorname = self.getSensor() or hostIP
self.write(sid, 'New connection: %s:%s' % (peerIP, peerPort))
Expand Down
3 changes: 2 additions & 1 deletion kippo/dblog/xmpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ def report(self, msgtype, to, xmsg):
self.muc.groupChat(to, None, children=[body])

# We have to return an unique ID
def createSession(self, peerIP, peerPort, hostIP, hostPort):
def createSession(self, peerIP, peerPort, hostIP, hostPort, versionIP):
session = uuid.uuid4().hex
ses = domish.Element((None, 'session'))
ses['session'] = session
ses['remote_ipv'] = versionIP
ses['remote_host'] = peerIP
ses['remote_port'] = str(peerPort)
if self.anonymous == True:
Expand Down