Skip to content
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
10 changes: 9 additions & 1 deletion data/userdb.txt
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
root:0:123456
root:0:password1
root:0:qwerty
root:0:p4ssw0rd
root:0:administrator
root:0:america
root:0:changeme
www:501:www
www-data:501:www-data

18 changes: 14 additions & 4 deletions kippo.cfg.dist
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
# Port to listen for incoming SSH connections.
#
# (default: 2222)
ssh_port = 2222
ssh_port = 22

# Hostname for the honeypot. Displayed by the shell prompt of the virtual
# environment.
#
# (default: svr03)
hostname = svr03
hostname = devops05

# Directory where to save log files in.
#
Expand All @@ -37,6 +37,15 @@ download_path = dl
# (default: 0)
#download_limit_size = 10485760

# Allow the attacker to exit the honeypot on request or try to 'trick' the attacker with another shell.
# note: depending on the attackers client (e.g. putty), will just quit regardless.
#
# (default: false)
exit_jail = false

# sftp_enabled enables the sftp subsystem
sftp_enabled = true

# Directory where virtual file contents are kept in.
#
# This is only used by commands like 'cat' to display the contents of files.
Expand Down Expand Up @@ -129,8 +138,8 @@ private_key = private.key
# SSH-2.0-OpenSSH_5.9p1 Debian-5ubuntu1
# SSH-2.0-OpenSSH_5.9
#
# (default: "SSH-2.0-OpenSSH_5.1p1 Debian-5")
ssh_version_string = SSH-2.0-OpenSSH_5.1p1 Debian-5
# (default: "SSH-2.0-OpenSSH_5.1 Debian-5")
ssh_version_string = SSH-2.0-OpenSSH_5.1 Debian-5

# Banner file to be displayed before the first login attempt.
#
Expand Down Expand Up @@ -200,3 +209,4 @@ interact_port = 5123
#identifier = abc123
#secret = secret
#debug=false

8 changes: 7 additions & 1 deletion kippo/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,15 @@ def call(self):

class command_exit(HoneyPotCommand):
def call(self):
cfg = config()
self.exit_jail = True
if cfg.has_option('honeypot', 'exit_jail'):
if (cfg.get('honeypot', 'exit_jail') == "false"):
self.exit_jail = False
if 'PuTTY' in self.honeypot.clientVersion or \
'libssh' in self.honeypot.clientVersion or \
'sshlib' in self.honeypot.clientVersion:
'sshlib' in self.honeypot.clientVersion or \
self.exit_jail is False:
self.honeypot.terminal.loseConnection()
return
self.honeypot.terminal.reset()
Expand Down
2 changes: 1 addition & 1 deletion kippo/commands/wget.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def download(self, url, fakeoutfile, outputfile, *args, **kwargs):
host = parsed.hostname
port = parsed.port or (443 if scheme == 'https' else 80)
path = parsed.path or '/'
if scheme == 'https' or port != 80:
if scheme == 'https':
self.writeln('Sorry, SSL not supported in this release')
self.exit()
return None
Expand Down
192 changes: 191 additions & 1 deletion kippo/core/fs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) 2009 Upi Tamminen <desaster@gmail.com>
# See the COPYRIGHT file for more information

import os, time, fnmatch
import os, time, fnmatch, re, stat, errno
from kippo.core.config import config

A_NAME, \
Expand Down Expand Up @@ -176,5 +176,195 @@ def is_dir(self, path):
if l:
return True
return False
# additions for SFTP support, try to keep functions here similar to os.*

def open(self, filename, openFlags, mode):
#print "fs.open %s" % filename

#if (openFlags & os.O_APPEND == os.O_APPEND):
# print "fs.open append"

#if (openFlags & os.O_CREAT == os.O_CREAT):
# print "fs.open creat"

#if (openFlags & os.O_TRUNC == os.O_TRUNC):
# print "fs.open trunc"

#if (openFlags & os.O_EXCL == os.O_EXCL):
# print "fs.open excl"

if openFlags & os.O_RDWR == os.O_RDWR:
raise notImplementedError

elif openFlags & os.O_WRONLY == os.O_WRONLY:
# ensure we do not save with executable bit set
realmode = mode & ~(stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)

#print "fs.open wronly"
# TODO: safeoutfile could contains source IP address
safeoutfile = '%s/%s_%s' % \
(config().get('honeypot', 'download_path'),
time.strftime('%Y%m%d%H%M%S'),
re.sub('[^A-Za-z0-9]', '_', filename))
#print "fs.open file for writing, saving to %s" % safeoutfile

self.mkfile(filename, 0, 0, 0, stat.S_IFREG | mode)
fd = os.open(safeoutfile, openFlags, realmode)
self.update_realfile(self.getfile(filename), safeoutfile)

return fd

elif openFlags & os.O_RDONLY == os.O_RDONLY:
return None

return None

# FIXME mkdir() name conflicts with existing mkdir
def mkdir2(self, path):
dir = self.getfile(path)
if dir != False:
raise OSError(errno.EEXIST, os.strerror(errno.EEXIST), path)
return self.mkdir(path, 0, 0, 4096, 16877)

def rmdir(self, path):
raise notImplementedError

def utime(self, path, atime, mtime):
p = self.getfile(path)
if p == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
p[A_CTIME] = mtime

def chmod(self, path, perm):
p = self.getfile(path)
if p == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
p[A_MODE] = stat.S_IFMT(p[A_MODE]) | perm

def chown(self, path, uid, gid):
p = self.getfile(path)
if p == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
if (uid != -1):
p[A_UID] = uid
if (gid != -1):
p[A_GID] = gid

def remove(self, path):
p = self.getfile(path)
if p == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
self.get_path(os.path.dirname(path)).remove(p)
return

def readlink(self, path):
p = self.getfile(path)
if p == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
if not (p[A_MODE] & stat.S_IFLNK):
raise OSError
return p[A_TARGET]

def symlink(self, targetPath, linkPath):
raise notImplementedError

def rename(self, oldpath, newpath):
#print "rename %s to %s" % (oldpath, newpath)
old = self.getfile(oldpath)
if old == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
new = self.getfile(newpath)
if new != False:
raise OSError(errno.EEXIST, os.strerror(errno.EEXIST))

self.get_path(os.path.dirname(oldpath)).remove(old)
old[A_NAME] = os.path.basename(newpath)
self.get_path(os.path.dirname(newpath)).append(old)
return

def read(self, fd, size):
# this should not be called, we intercept at readChunk
raise notImplementedError

def write(self, fd, string):
return os.write(fd, string)

def close(self, fd):
if (fd == None):
return True
return os.close(fd)

def lseek(self, fd, offset, whence):
if (fd == None):
return True
return os.lseek(fd, offset, whence)

def listdir(self, path):
names = [x[A_NAME] for x in self.get_path(path)]
return names

def lstat(self, path):

# need to treat / as exception
if (path == "/"):
p = { A_TYPE:T_DIR, A_UID:0, A_GID:0, A_SIZE:4096, A_MODE:16877, A_CTIME:time.time() }
else:
p = self.getfile(path)

if p == False:
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))

return _statobj(
p[A_MODE],
0,
0,
1,
p[A_UID],
p[A_GID],
p[A_SIZE],
p[A_CTIME],
p[A_CTIME],
p[A_CTIME])

def stat(self, path):
if (path == "/"):
p = { A_TYPE:T_DIR, A_UID:0, A_GID:0, A_SIZE:4096, A_MODE:16877, A_CTIME:time.time() }
else:
p = self.getfile(path)

if (p == False):
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))

#if p[A_MODE] & stat.S_IFLNK == stat.S_IFLNK:
if p[A_TYPE] == T_LINK:
return self.stat(p[A_TARGET])

return self.lstat(path)

def realpath(self, path):
return path

def update_size(self, filename, size):
f = self.getfile(filename)
if (f == False):
return
if (f[A_TYPE] != T_FILE):
return
f[A_SIZE] = size


# transform a tuple into a stat object
class _statobj:
def __init__(self, st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime):
self.st_mode = st_mode
self.st_ino = st_ino
self.st_dev = st_dev
self.st_nlink = st_nlink
self.st_uid = st_uid
self.st_gid = st_gid
self.st_size = st_size
self.st_atime = st_atime
self.st_mtime = st_mtime
self.st_ctime = st_ctime

# vim: set sw=4 et:
Loading