Skip to content

Instantly share code, notes, and snippets.

@pfctdayelise
Created February 7, 2012 13:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfctdayelise/1759815 to your computer and use it in GitHub Desktop.
Save pfctdayelise/1759815 to your computer and use it in GitHub Desktop.
something to help me detect badware. hopefully useful to run as cron.
#!/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