Welcome, guest | Sign In | My Account | Store | Cart

gen_twpol.py is a script that can be used to generate a tripwire policy source (twpol.txt) for your system.

This script may be distributed under the terms of the Gnu Public License GPLv2 or later.

For more information on the open source version of tripwire see http://sourceforge.net/projects/tripwire/

The tripwire source package usually ships with a an example twpol.txt file based on a RedHat Enterprise (RHEL) distribution, typically an RHEL4 or RHEL5 version. It doesn't do much good to have this get parked by your Gentoo ebuild (nor other distro packager) as all sorts of stuff in /boot, /lib/modules and other places will be out of sync, differently named or just plain missing. In addition, your system may have extra stuff that isn't present in the file but critical to the distro.

Python, 172 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/python
"""
gen_twpol.py    Copyright 2009 Bill Sharer

gen_twpol.py is a script that can be used to generate a tripwire policy source (twpol.txt) for your system.

This script may be distributed under the terms of the Gnu Public License GPLv2 or later.

For more information on the open source version of tripwire see http://sourceforge.net/projects/tripwire/

The tripwire source package usually ships with a an example twpol.txt file based on a RedHat Enterprise (RHEL)
distribution, typically an RHEL4 or RHEL5 version.  It doesn't do much good to have this get parked by your Gentoo
ebuild (nor other distro packager) as all sorts of stuff in /boot, /lib/modules and other places will be
out of sync, differently named or just plain missing.  In addition, your system may have extra stuff that isn't
present in the file but critical to the distro.

To use this script, park it in the tripwire config directory (probably /etc/tripwire).  Copy your existing twpol.txt
to twpol_header.txt and hack it up to remove the middle section of rules for the directories which will be scanned in
the crit_dir list.  You will want to keep the sections at the bottom for root's home dir and things like /home.  The
output from this script would then be appended to the header contents.

You will still want to tweak the root homedir rule section to take into account your prefs for window manager and the
settings for other dot files.  You should also do a quick sanity check of the output to fine tune the results before
generating a policy file with twadmin.  Since the list can be quite large, it may take 10 minutes or more for twadmin
to parse and create the encrypted policy.  A common problem is having a directory called out in a rule in the header
which is part of the crit_dirs and their subdirectories.  Tripwire doesn't like overlapping rules.
"""
import os
import re

#
#  These are all on a gentoo 64 bit distro but may be softlinked (/usr/lib to /usr/lib64).
#  On 64 bit RedHat or other 64 bit distros may see just /usr/lib instead of /usr/lib64
#  On 32 bit distros, will just have /usr/lib and no /usr/lib32 or /usr/lib64
#  You might consider tweaking to add /usr/local and other directories
#
crit_dirs = ("/boot", "/sbin", "bin", "/usr/sbin", "/usr/bin", "/lib", "/usr/lib", "/usr/lib32", "/usr/lib64", "/usr/libexec", "/etc")
#crit_dirs = ("/etc",)
#
#  Skip the following files and directories.  By default, tripwire watches its own files in a separate rule so we don't
#  want to duplicate.  If you decide to watch /var or /var/lib, you will probably want to include /var/lib/tripwire
#
#  The cron files will probably be covered in one of your header sections as "$(growing)"
#
#skip_dirs = ("/etc/tripwire", "/var/lib/tripwire")
skip_dirs = ("/etc/tripwire",)
skip_files = ("siggen", "tripwire", "twadmin", "twprint", "cron.daily", "cron.weekly", "cron.monthly")

#
#  Files ending with these extensions are include files, images, fonts and other junk that can usually be ignored
#
skip_types = (".keep", ".lock", ".zip", ".png", ".gif", ".jpg", ".h", ".hpp", ".c", ".cpp", ".txt", ".html", ".css", ".exsd", "Makefile", ".mak", ".cf", ".rules", ".tmpl", ".pmf", ".afm", ".idl", ".xsl")

#
#  Specials in a filename which will trip up the policy parser.  "$" gets used for anonymous java classes and appears with some frequency.
#  Thunderbird and Firefox like to use directories that are guid's stuck between braces.  May need to add more as we go along
#
skip_patterns = re.compile("[${}(),=]")

#
#  This gets tacked onto the end of each policy rule indicating what to watch for.  You may need to tweak this depending on your header.
#  
crit = "-> $(SEC_CRIT) ;"
#crit = "-> $(ReadOnly) ;"

#
#  which column do we space/tab over to before doing the crit string on the line
#
target_col = 100
blanks = "                                                                                                                                             "


#
#  Check a string to see if it's an item in a list
#
def found_in(string1, list1):
    for x in list1:
        if x == string1:
            return True
    return False


#
#  Check a string to see if it ends with an item on a list
#
def ends_with(string1, list1):
    for x in list1:
        if string1[-len(x):] == x:
            return True
    return False


#
#  output a single rule using whitespace to pad over to the action type
#
def do_rule(file1, string1):
    line = "  " + string1
    length = len(line)
    if length > target_col:
        line = line + blanks[:8] + crit + "\n"
    else:
        line = line + blanks[:(target_col-len(line)+1)] + crit + "\n"
    file1.write(line)
    
#
#  Check for twpol header in current directory
#
if os.path.isfile("./twpol_header.txt"):
    #
    #  Check for existing twpol.txt file and move out of the way
    #
    if os.path.isfile("./twpol.txt"):
        os.rename("./twpol.txt","./twpol.txt.old")
    #
    #  Copy the header to a new twpol.txt
    #
    headerfile = open("./twpol_header.txt","r")
    twpol = open("./twpol.txt","w")
    headerlist = headerfile.readlines()
    for header in headerlist:
        twpol.write(header)
    headerfile.close()
    
    #
    #  Iterate over each crit_dir
    #
    for crit_dir in crit_dirs:
        if os.path.islink(crit_dir):
            print "Ignoring softlinked directory ", crit_dir
        else:
            if os.path.isdir(crit_dir):
                #
                #  Dump the rule header lines
                #
                # rule_header = '\n\n(\n  rulename = "' + crit_dir + '",\n  severity = $(SIG_HI)\n)\n{\n'
                rule_header = '\n\n(\n  rulename = "' + crit_dir + '",\n)\n{\n'
                twpol.write(rule_header)
                do_rule(twpol,crit_dir+"/")
                #
                #  Walk the directory including subdirs and files
                #
                for path, subdirs, files in os.walk(crit_dir):
                    if found_in(path,skip_dirs):
                        print "*** Skipping subdirectory", path
                    else:
                        #
                        #  Do the directory or subdirectory itself
                        #
                        #do_rule(twpol,path+"/")
                        files.extend(subdirs)
                        files.sort()
                        for name in files:
                            filename = os.path.join(path, name)
                            if found_in(name,skip_files):
                                print "***Skipping file ", filename
                            else:
                                if ends_with(name,skip_types):
                                    print "***Skipping extension ", filename
                                else:
                                    if re.search(skip_patterns,filename) != None:
                                        print "***Skipping filename with bad chars ", filename
                                    else:
                                        #print filename
                                        do_rule(twpol,filename)
                twpol.write("}\n")
            else:
                print "*** %s is not a directory!" % crit_dir
    #
    #  
    twpol.close()
else:
    exit("No twpol_header.txt file present in this directory")

This provides a good detailed policy file to start tweaking for a tripwire database. You may also want to tweak some of the lists in the script to better conform to your particular distro.

I may add a dictionary later to match directory rules to different severities or rule criteria. This is just something I slapped together over a weekend to scratch an itch.

I also have an idea of matching a live cd, a tripwire installation and a scan set to lock down a configuration of a Windows system to a database on a network share or a thumb drive. This would probably be an effective deterrent to discover rootkit installations that snuck by virus scanners. Combine with a CM package (git maybe?) and you may have a toolkit to repair wear and tear on .exe's and .dll's when "Winders" decides to crap its diaper.

1 comment

Sergey Nosenko 10 years, 7 months ago  # | flag

Thank you sir, your script saved me tons of time.