Skip to content

Instantly share code, notes, and snippets.

@robmiller
Created May 23, 2014 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robmiller/d32dc4826639b69c92e7 to your computer and use it in GitHub Desktop.
Save robmiller/d32dc4826639b69c92e7 to your computer and use it in GitHub Desktop.
Script, designed to be run on a cron job, to scan for files (in this case PHP files) that have been modified and notify a Slack channel with the changes. Just for information, not for proper intrusion detection or anything
#!/usr/bin/env ruby
require 'net/http'
require "json"
require "pathname"
require "logger"
class Slack
attr_reader :account, :token, :channel
def initialize(account, token, channel)
@account = account
@token = token
@channel = channel
end
def uri
URI.parse("https://#{account}.slack.com/services/hooks/incoming-webhook?token=#{token}&channel=#{channel}")
end
def notify(text)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri.request_uri)
req.body = { text: text }.to_json
res = http.request(req)
res === Net::HTTPSuccess
end
end
class Watcher
LOG_FILE = ENV["SCANPHP_LOG_FILE"] || "/var/log/scan-php"
def initialize
@notified = []
@logger = Logger.new(LOG_FILE)
@logger.level = ENV["SCANPHP_DEBUG"] ? Logger::DEBUG : Logger::INFO
@slack = Slack.new(ENV["SLACK_ACCOUNT"], ENV["SLACK_TOKEN"], ENV["SLACK_CHANNEL"])
end
def call
@logger.info("Running scan in #{Dir.pwd}")
unless something_new?
@logger.info("No new files found in scan")
return
end
@slack.notify(message)
@logger.debug(message)
end
def something_new?
files.length > 0
end
def files
@files ||= begin
raw_files = `find . -iname '*.php' -mtime 0`
@logger.debug("Raw files:\n" + raw_files)
raw_files = raw_files.split("\n").map { |file| Pathname(file) }
raw_files.reject do |file|
Time.now - File.mtime(file) > 3600 ||
/gravity_forms\/captcha/.match(file.to_s) ||
/cache\/index\.php$/.match(file.to_s)
end
end
end
def sites
files.group_by do |file|
elements = []
file.each_filename { |f| elements << f }
elements[1]
end
end
def message
@message ||= begin
message = "#{Time.now.strftime('%H:%M:%S')}: #{files.length} PHP file#{'s' if files.length != 1} modified across #{sites.length} site#{'s' if sites.length != 1}\n\n"
sites.each do |site, site_files|
message << "On #{site}:\n"
site_files.each do |file|
elements = []
file.each_filename { |f| elements << f }
elements = elements[2..-1]
relative_path = elements.join("/")
message << "\t" << relative_path << "\n"
end
end
message
end
end
end
Watcher.new.call
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment