Last active
October 6, 2015 17:57
-
-
Save jesselang/1667c4a0a1bde618773e to your computer and use it in GitHub Desktop.
Script to assist in cleaning up one type of injection from PHP malware
This file contains hidden or 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 | |
# Script to assist in cleaning up one type of injection from PHP malware. | |
# Author: Jesse Lang | http://jesselang.com/ | |
# Use it with "find" like this: | |
# $ for FILE in $(find -iname *.php); do python malware_cleanup.py $FILE; done | |
# This script takes one argument, a file path. | |
# The file is opened and scanned for a match. | |
# The user is given the option of cleaning or deleting the file, or doing nothing. | |
# If repairing the file would result in an empty file, the file is deleted instead. | |
# Example output: | |
# ./infected/sketchys/sket.php matched "eval (base64_decode (..." | |
# File size: 163 bytes | |
# Match size: 163 bytes | |
# Last modified: Tue Jul 29 08:26:57 2014 | |
# Re(V)iew, re(P)air, (D)elete, or (S)kip? [V/P/D/S]: | |
import os | |
import re | |
import shutil | |
import sys | |
import time | |
from stat import ST_SIZE, ST_MTIME | |
# Constants. | |
MAX_FILE_READ = 1024 * 1024 # 1 megabyte. | |
try: | |
filename = sys.argv[1] | |
except IndexError: | |
print 'Error: This script takes one argument, a file path.' | |
sys.exit(1) | |
php_eval_decode_pattern_string = r'''<\?\s*?php\s*?(eval\s*?\(.*decode\s*?\().*?\?>''' | |
php_eval_decode_pattern = re.compile(php_eval_decode_pattern_string) | |
file = open(filename, 'r') | |
match = php_eval_decode_pattern.match(file.read(MAX_FILE_READ)) | |
if match: | |
info = os.fstat(file.fileno()) | |
print '%s matched "%s..."' % (filename, match.group(1)) | |
print 'File size: %10d bytes' % info[ST_SIZE] | |
print 'Match size: %10d bytes' % len(match.group(0)) | |
print 'Last modified: %s' % time.asctime(time.localtime(info[ST_MTIME])) | |
deciding = True | |
while deciding: | |
input = raw_input('Re(V)iew, re(P)air, (D)elete, or (S)kip? [V/P/D/S]: ') | |
if input.lower() == 'v': | |
os.system('less -p\'%s\' "%s"' % (php_eval_decode_pattern_string, sys.argv[1])) | |
elif input.lower() == 'p': | |
if info[ST_SIZE] == len(match.group(0)): | |
print 'Since the repaired file would be empty, deleting instead.' | |
file.close() | |
os.remove(filename) | |
deciding = False | |
else: | |
shutil.copyfile(filename, '%s-orig' % filename) | |
file.seek(0) | |
repaired_data = php_eval_decode_pattern.sub('', file.read(MAX_FILE_READ)) | |
file.close() | |
file = open(filename, 'w') | |
file.write(repaired_data) | |
deciding = False | |
elif input.lower() == 'd': | |
confirm = raw_input('Are you sure you want to delete this file? [Y/N]: ') | |
if confirm.lower() == 'y': | |
file.close() | |
os.remove(filename) | |
deciding = False | |
elif input.lower() == 's': | |
deciding = False | |
file.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment