Created
February 7, 2012 13:57
-
-
Save pfctdayelise/1759815 to your computer and use it in GitHub Desktop.
something to help me detect badware. hopefully useful to run as cron.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import argparse | |
import urllib | |
from BeautifulSoup import BeautifulSoup # 3.2.0 | |
def getPagesForOnePath(path): | |
f = urllib.urlopen(path) | |
soup = BeautifulSoup(f) | |
links = [li.a.text for li in soup.findAll('li')] | |
pages = set([l for l in links if l.endswith('.php')]) | |
subdirs = [l[:-1] for l in links if l.endswith('/')] | |
subdirs = [os.path.join(path, s) for s in subdirs] | |
return pages, subdirs | |
def getPages(path, allPages): | |
# print "checking", path | |
pages, subdirs = getPagesForOnePath(path) | |
allPages.update(pages) | |
for subdir in subdirs: | |
getPages(subdir, allPages) | |
def getWordpressFilesList(): | |
# should do latest release instead?? | |
path = 'http://core.svn.wordpress.org/trunk/' | |
pages = set([]) | |
getPages(path, pages) | |
print pages | |
def getTextpatternFilesList(): | |
# note version is hardcoded | |
path = 'http://textpattern.googlecode.com/svn/releases/4.4.1/source/' | |
pages = set([]) | |
getPages(path, pages) | |
print pages | |
textpatternFiles = set([u'_to_4.0.6.php', u'txp_form.php', u'_to_4.2.0.php', u'_update.php', u'config-dist.php', u'PasswordHash.php', u'txpsql.php', u'_to_4.0.8.php', u'txplib_theme.php', u'_to_4.0.4.php', u'IXRClass.php', u'taglib.php', u'atom.php', u'txp_link.php', u'txp_plugin.php', u'admin_config.php', u'txp_log.php', u'class.thumb.php', u'txp_import.php', u'_to_4.0.7.php', u'TXP_RPCServer.php', u'index.php', u'import_blogger.php', u'classTextile.php', u'en-gb.php', u'_to_1.0.0.php', u'txp_section.php', u'txp_article.php', u'txp_image.php', u'remora.php', u'_to_4.4.0.php', u'publish.php', u'import_mt.php', u'txp_diag.php', u'txp_prefs.php', u'txplib_admin.php', u'txplib_db.php', u'txplib_update.php', u'txplib_html.php', u'rss.php', u'import_wp.php', u'constants.php', u'txp_discuss.php', u'_to_4.4.1.php', u'txplib_wrapper.php', u'import_b2.php', u'comment.php', u'txplib_head.php', u'txp_page.php', u'_to_4.0.5.php', u'log.php', u'search.php', u'txp_list.php', u'txp_file.php', u'setup-langs.php', u'txplib_misc.php', u'txplib_forms.php', u'_to_4.3.0.php', u'taghandlers.php', u'txp_tag.php', u'txp_auth.php', u'_to_4.0.2.php', u'_to_4.0.3.php', u'classic.php', u'txp_category.php', u'import_mtdb.php', u'css.php', u'txp_css.php', u'txp_admin.php']) | |
# note you create this manually, it wouldn't be in the src | |
textpatternFiles.add('config.php') | |
# http://www.forum.textpattern.com/viewtopic.php?id=30071 | |
textpatternFiles.add('evaluator_trace.php') | |
# removed in http://code.google.com/p/textpattern/source/detail?r=3520 | |
textpatternFiles.add('txp_preview.php') | |
wordpressFiles = set([u'content-aside.php', u'class-phpmailer.php', u'options-reading.php', u'meta.php', u'wp-load.php', u'class-wp-plugin-install-list-table.php', u'custom-header.php', u'bookmark.php', u'option.php', u'load-scripts.php', u'class-wp-filesystem-ftpext.php', u'options.php', u'content-status.php', u'wp-settings.php', u'default-widgets.php', u'class-wp-xmlrpc-server.php', u'GoogleSpell.php', u'entry.php', u'feed-rdf.php', u'bookmark-template.php', u'class-smtp.php', u'class-wp-admin-bar.php', u'theme.php', u'wp-blog-header.php', u'user-new.php', u'options-head.php', u'sidebar-page.php', u'onecolumn-page.php', u'class-wp-ajax-response.php', u'class.wp-styles.php', u'Diff.php', u'ms-themes.php', u'site-info.php', u'Renderer.php', u'content-featured.php', u'export.php', u'media.php', u'kses.php', u'ms-sites.php', u'ms-options.php', u'wp-cron.php', u'revisions-js.php', u'wp-diff.php', u'class-wp-posts-list-table.php', u'ms-default-constants.php', u'theme-editor.php', u'options-general.php', u'feed-atom.php', u'site-users.php', u'wp-langs.php', u'single.php', u'continents-cities.php', u'site-settings.php', u'rss-functions.php', u'manifest.php', u'class-wp-ms-users-list-table.php', u'EnchantSpell.php', u'admin.php', u'capabilities.php', u'cron.php', u'feed-rss2-comments.php', u'attachment.php', u'ms-delete-site.php', u'cache.php', u'class-wp-theme-install-list-table.php', u'link-parse-opml.php', u'site-themes.php', u'query.php', u'link-template.php', u'page.php', u'registration-functions.php', u'default-constants.php', u'ms-files.php', u'SpellChecker.php', u'link.php', u'user-edit.php', u'edit.php', u'content-link.php', u'media-new.php', u'admin-footer.php', u'class-wp-filesystem-ssh2.php', u'mo.php', u'header.php', u'options-privacy.php', u'registration.php', u'press-this.php', u'class-wp-terms-list-table.php', u'loop.php', u'pluggable.php', u'wp-app.php', u'edit-tags.php', u'category-template.php', u'class-wp-themes-list-table.php', u'install-helper.php', u'edit-form-comment.php', u'script-loader.php', u'admin-header.php', u'class-pclzip.php', u'class-wp-filesystem-direct.php', u'vars.php', u'loop-page.php', u'ms-upgrade-network.php', u'users.php', u'sites.php', u'ms-functions.php', u'comments.php', u'class-wp-comments-list-table.php', u'site-new.php', u'comments-popup.php', u'admin-functions.php', u'edit-tag-form.php', u'compat.php', u'functions.wp-scripts.php', u'feed-rss.php', u'plugin.php', u'class-wp-error.php', u'class-wp-filesystem-ftpsockets.php', u'freedoms.php', u'general.php', u'ms-edit.php', u'atomlib.php', u'network.php', u'PSpell.php', u'wp-signup.php', u'class-simplepie.php', u'inline.php', u'404.php', u'loop-single.php', u'meta-boxes.php', u'edit-comments.php', u'class-wp-list-table.php', u'wp-register.php', u'theme-options.php', u'tools.php', u'upload.php', u'class-phpass.php', u'class-wp-plugins-list-table.php', u'class-wp-media-list-table.php', u'admin-ajax.php', u'gears-manifest.php', u'wp-comments-post.php', u'media-upload.php', u'custom-background.php', u'comment.php', u'repair.php', u'options-discussion.php', u'author.php', u'formatting.php', u'class.wp-dependencies.php', u'class-feed.php', u'wp-tinymce.php', u'ms-deprecated.php', u'ms-settings.php', u'wp-db.php', u'install.php', u'theme-install.php', u'string.php', u'edit-link-form.php', u'about.php', u'wp-config-sample.php', u'showcase.php', u'upgrade-functions.php', u'class-wp-filesystem-base.php', u'class-wp-links-list-table.php', u'class-wp-walker.php', u'rpc.php', u'rss.php', u'menu.php', u'upgrade.php', u'themes.php', u'xmlrpc.php', u'post-thumbnail-template.php', u'deprecated.php', u'wp-mce-help.php', u'locale.php', u'streams.php', u'translations.php', u'list-table.php', u'load.php', u'edit-form-advanced.php', u'my-sites.php', u'file.php', u'plugins.php', u'wp-mail.php', u'nav-menus.php', u'tag.php', u'link-add.php', u'class-ftp.php', u'update.php', u'update-core.php', u'ms-default-filters.php', u'options-writing.php', u'shell.php', u'content-quote.php', u'class-wp-users-list-table.php', u'image-edit.php', u'pluggable-deprecated.php', u'class-wp.php', u'template.php', u'options-permalink.php', u'wp-login.php', u'wp-trackback.php', u'profile.php', u'class-wp-http-ixr-client.php', u'http.php', u'template-loader.php', u'import.php', u'search.php', u'feed-atom-comments.php', u'credits.php', u'link-manager.php', u'admin-post.php', u'l10n.php', u'plugin-editor.php', u'user.php', u'image.php', u'post-new.php', u'class-ftp-sockets.php', u'version.php', u'author-template.php', u'rewrite.php', u'class-IXR.php', u'post.php', u'xdiff.php', u'load-styles.php', u'wp-pass.php', u'sidebar-footer.php', u'feed.php', u'plugin-install.php', u'class-ftp-pure.php', u'admin-bar.php', u'post-template.php', u'PSpellShell.php', u'content-gallery.php', u'functions.wp-styles.php', u'sidebar.php', u'class.wp-scripts.php', u'default-filters.php', u'po.php', u'class-wp-editor.php', u'functions.php', u'ms-admin.php', u'misc.php', u'config.php', u'content-intro.php', u'index.php', u'revision.php', u'shortcodes.php', u'async-upload.php', u'archive.php', u'moderation.php', u'ms.php', u'ms-users.php', u'nav-menu-template.php', u'ms-load.php', u'footer.php', u'nav-menu.php', u'content-image.php', u'wp-links-opml.php', u'JSON.php', u'schema.php', u'category.php', u'canonical.php', u'class-snoopy.php', u'options-media.php', u'index-extra.php', u'class-wp-ms-sites-list-table.php', u'comment-template.php', u'hello.php', u'wp-activate.php', u'ms-blogs.php', u'class-oembed.php', u'class-pop3.php', u'taxonomy.php', u'screen.php', u'native.php', u'feed-rss2.php', u'setup.php', u'widgets.php', u'content-single.php', u'dashboard.php', u'content-page.php', u'setup-config.php', u'class-wp-upgrader.php', u'searchform.php', u'class-json.php', u'Logger.php', u'general-template.php', u'loop-attachment.php', u'class-wp-importer.php', u'menu-header.php', u'class-wp-ms-themes-list-table.php', u'class-http.php', u'content.php', u'ajax-actions.php', u'settings.php']) | |
def checkHtAccess(path): | |
htPath = os.path.join(path, '.htaccess') | |
problems = [] | |
msg = 'Probable google redirect in htaccess file, line {}, file {}' | |
try: | |
with open(htPath) as f: | |
for i, line in enumerate(f): | |
if 'google' in line: | |
problem = msg.format(i, htPath) | |
problems.append(problem) | |
except IOError: | |
# don't necessarily have a htaccess file | |
pass | |
return problems | |
def checkPath(path): | |
problems = checkHtAccess(path) | |
return problems | |
def checkTextpattern(path): | |
problems = checkHtAccess(path) | |
msg = 'Non-Textpattern PHP files found in {}: {}' | |
problems += checkKnownPhp(path, textpatternFiles, msg) | |
return problems | |
def checkKnownPhp(path, allowedFiles, problemMsg): | |
problems = [] | |
for (dirpath, _dirnames, filenames) in os.walk(path): | |
phpFiles = [f for f in filenames if f.endswith('php')] | |
badFiles = set(phpFiles).difference(allowedFiles) | |
if badFiles: | |
problem = problemMsg.format(dirpath, ','.join(badFiles)) | |
problems.append(problem) | |
return problems | |
def checkWordpress(path): | |
problems = checkHtAccess(path) | |
msg = 'Non-Wordpress PHP files found in {}: {}' | |
problems += checkKnownPhp(path, wordpressFiles, msg) | |
return problems | |
def fullPath(path): | |
path = os.path.expanduser(os.path.join('~', path)) | |
if not os.path.exists(path): | |
msg = 'Path does not exist: {}'.format(path) | |
raise argparse.ArgumentTypeError(msg) | |
return path | |
def main(): | |
parser = argparse.ArgumentParser(description='Check filesystem for evidence of malware being installed') | |
parser.add_argument('-t','--textpattern', help='(sub)domain of a Textpattern install', type=fullPath, default=[], action='append') | |
parser.add_argument('-w','--wordpress', help='(sub)domain of a Wordpress install', type=fullPath, default=[], action='append') | |
parser.add_argument('-d','--domain', help='a (sub)domain', type=fullPath, default=[], action='append') | |
parser.add_argument('-g','--generate', help='generate the paths by checking Wordpress/Textpattern src', action='store_true') | |
args = parser.parse_args() | |
if args.generate: | |
getWordpressFilesList() | |
getTextpatternFilesList() | |
problems = [] | |
for path in args.textpattern: | |
problems += checkTextpattern(path) | |
for path in args.wordpress: | |
problems += checkWordpress(path) | |
for path in args.domain: | |
problems += checkDomain(path) | |
for problem in problems: | |
print problem | |
if __name__ == "__main__": | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment