Virus honeypot with quarantine (initial implementation)

Michael Gerdts Michael.Gerdts at usa.alcatel.com
Wed May 2 11:56:10 GMT 2001


I have implemented much of what I talk about below, in a proof of concept
type of way.   Most of the code is stolen from skel.c and audit.c.

To compile and install:

     cp quarantine.c samba/examples/VFS
     cd samba/examples/VFS
     patch -p0 < Makefile.patch 		(On solaris 8, anyway)
     make quarantine.so
     cp quarantine.so /opt/samba/lib/quarantine.so
     mkdir /quarantine
     chmod 1777 /quarantine

This was on Solaris 8.  The Makefile patch is needed to create the shared
library.

Note that samba must be configured --with-vfs

smb.conf:

     [trap]
     	comment		= virus trap
	browseable	= yes
	writable	= yes
	guest		= yes
	path		= /trap
	vfs object      = /opt/samba/lib/quarantine.so

I think that I have documented things that are really broken with FIXME
tags.  I welcome any comments you may have.

Mike

On Tue, May 01, 2001 at 09:18:07AM -0400, Michael Gerdts wrote:
> While analyzing samba logs on a test server, I have found several machines
> that are crawling through guest accessible shares.  Each one of them was a
> rogue machine that was in violation of our virus scanning software policy.
> 
> I now realize how easy it is to identify potentially virus-infected
> machines.  I would like to be able to change that from "potentially" to
> "definitely".  My first thoughts were to provide a mechanism within samba
> that has shares that appear to be writable, but any changed files are
> actually written off to a quarantined area.  The original file should never
> be changed.
> 
> Presumably this could be done with the VFS layer.  I think that the
> open call would be the only think that needed to be modified.  Its behavior
> would be:
> 
>     If mode is:
> 
>         read-only - default_vfs_ops.open()
> 
> 	write-only - create the quarantine file
> 			/quarantine/%S/%m/%u/origfilename.unique_id
> 		     open the quarantine file
> 	
> 	read-write - copy file to quarantine file
> 		     open the quarantine file
> 
> I would then run a virus scanning program on the UNIX server to identify
> infected files in quarantine area. 
> 
> Is there anything that I am missing that I should be aware of?
> 
> Mike

-- 
Mike Gerdts                                              (919) 850-5284
Unix Systems Administrator               Michael.Gerdts at usa.alcatel.com
-------------- next part --------------
/* 
 * Skeleton VFS module.  Implements passthrough operation of all VFS
 * calls to disk functions.
 *
 * Copyright (C) Tim Potter, 1999-2000
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *  
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *  
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* FIXME - use the safe string functions instead of snprintf, strncpy */
#define _SAFE_STRING_H

#include "config.h"

#include <stdio.h>
#include <sys/stat.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <errno.h>
#include <string.h>

#include <includes.h>
#include <vfs.h>

#ifndef SYSLOG_FACILITY
#define SYSLOG_FACILITY   LOG_USER
#endif

#ifndef SYSLOG_PRIORITY
#define SYSLOG_PRIORITY   LOG_NOTICE
#endif

static char *mystrchr(char *path, int c) {
	char *p;
	for ( p = path ; p != NULL && *p != '\0' ; p++ ) {
		if ( *p == c ) {
			return(p);
		}
	}
	return(NULL);
}

/* Function prototypes */

    /* File operations */

    int quarantine_open(struct connection_struct *conn, char *fname, int flags, mode_t mode);

/* VFS operations structure */

    /*FIXME the ops listed below with FIXME tags should probably just
      return EPERM */

struct vfs_ops quarantine_ops = {

	/* Disk operations */

	NULL,	/* quarantine_connect, */
	NULL,	/* quarantine_disconnect, */
	NULL,	/* quarantine_disk_free, */
	
	/* Directory operations */

	NULL,	/* quarantine_opendir, */
	NULL,	/* quarantine_readdir, */
	NULL,	/* FIXME quarantine_mkdir, */
	NULL,	/* FIXME quarantine_rmdir, */
	NULL,	/* quarantine_closedir, */

	/* File operations */

	quarantine_open,
	NULL,	/* quarantine_close, */
	NULL,	/* quarantine_read, */
	NULL,	/* quarantine_write, */
	NULL,	/* quarantine_lseek, */
	NULL,	/* quarantine_rename, */
	NULL,	/* quarantine_fsync, */
	NULL,	/* quarantine_stat, */
	NULL,	/* quarantine_fstat, */
	NULL,	/* quarantine_lstat, */
	NULL,	/* FIXME quarantine_unlink, */
	NULL,	/* quarantine_chmod, */
        NULL,	/* quarantine_chown, */
        NULL,	/* quarantine_chdir, */
        NULL,	/* quarantine_getwd, */
	NULL,	/* quarantine_utime, */
	NULL,	/* FIXME quarantine_ftruncate, */
	NULL,	/* quarantine_lock, */

	/* NT File ACL operations */

        NULL,	/* quarantine_fget_nt_acl, */
        NULL,	/* quarantine_get_nt_acl, */
        NULL,	/* quarantine_fset_nt_acl, */
        NULL,	/* quarantine_set_nt_acl */
};

/* VFS initialisation - return vfs_ops function pointer structure */

struct vfs_ops *vfs_init(int *vfs_version)
{
    	openlog("smbd_audit", LOG_PID, SYSLOG_FACILITY);
	*vfs_version = SMB_VFS_INTERFACE_VERSION;
	return(&quarantine_ops);
}

/* Implementation of VFS functions.  Insert your useful stuff here */

extern struct vfs_ops default_vfs_ops;   /* For passthrough operation */

int quarantine_open(struct connection_struct *conn, char *fname, int flags, mode_t mode)
{
	char qfname[PATH_MAX+1];
	char qfdir[PATH_MAX+1];
	struct stat statbuf;
	char *p, *file;

	syslog(SYSLOG_PRIORITY, "quarantine_open(%s, 0%o, 0%o)\n",
			fname, flags, mode);

	/* FIXME for O_WRONLY and O_RDWR, if neither O_CREAT nor O_TRUNC
	   is given, the file (fname) should be copied to the quarantine
	   file (qfname) */
	if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC | O_APPEND)) {
		if (snprintf(qfname, PATH_MAX+1, "/quarantine/%s/%s/%s/%s",
					conn->client_address, conn->user,
					conn->origpath, fname) 
				> PATH_MAX) {
			return(ENAMETOOLONG);
		}
		syslog(SYSLOG_PRIORITY, "quarantine_open: quarantine file is \"%s\"",
			qfname);
		strncpy(qfdir, qfname, PATH_MAX+1);
		p = qfdir;
		while ((p=mystrchr(p, '/')) != NULL) {
			*p = '\0';
			if (stat(qfdir,&statbuf) != 0) {
				syslog(SYSLOG_PRIORITY, "quarantine_open: mkdir \"%s\"",
					qfdir);
				mkdir(qfdir, 01777);
			}
			*p = '/';
			p++;
		}

		file = qfname;
	}
	else {
		file = fname;
	}
		
	syslog(SYSLOG_PRIORITY, "quarantine_open: open(\"%s\", 0%o, 0%o)",
		file, flags, mode);
	return open(file, flags, mode);
}

/* vim: ts=8 sw=8 
 */
-------------- next part --------------
Index: Makefile
===================================================================
RCS file: /cvsroot/samba/examples/VFS/Makefile,v
retrieving revision 1.3.4.2
diff -r1.3.4.2 Makefile
9a10
> #LIBTOOL	=
25c26,27
< 	$(LIBTOOL) $(CC) -shared -o $@ $< $(LDFLAGS)
---
> 	#$(LIBTOOL) $(CC) -shared -o $@ $< $(LDFLAGS)
> 	ld -G -o $@ $< $(LDFLAGS)


More information about the samba-technical mailing list