#!/usr/bin/env/ruby #Author: SkyOut #Date: June 2007 #Contact: skyout[-at-]smash-the-stack[-dot-]net #Websites: http://www.smash-the-stack.net/ # #RFICK, which stands for Ruby File Integrity ChecKer is #a simple proof-of-concept ruby script, that saves hash #values in a specified directory (which you have to set #before using it) and afterwards can check whether the #hashvalues have changed. If so a warning will be displayed #to make you recognize the change! # #DO NOT FORGET TO MODIFY THE VARIABLE 'homepath', in #this directory a folder 'rfick' will be created, where #the files 'md5.txt' and/or 'sha1.txt' and/or 'rmd160.txt' #will be stored. They contain the hashvalues and the paths #to the files of those values. Afterwards they will be used #to check if the hashvalue has changed, the most important #part of the script. # #To start the script the first time you for example do something #like: # #$ ruby rfick.rb -create MD5 /home/user # #This will store the hashvalues of the files in your home #directory to 'homepath'/rfick/md5.txt! To recheck those #values later you just have to type: # #$ ruby rfick.rb -check MD5 # #and all values will be compared with the current hashvalues #of the files. If anything has changed you will get a warning. require 'digest/md5' require 'digest/sha1' require 'digest/rmd160' # Display the usage dialogue def usage() puts "" puts "-----------------------------------------" puts "| Ruby File Integrity ChecKer by SkyOut |" puts "-----------------------------------------" puts "" puts "-----------------------------------------------------------------------" puts "| Usage: ruby rfick.rb [-check|-create] [MD5|SHA1|RMD160] [directory] |" puts "-----------------------------------------------------------------------" puts "" exit(0) end # Check if the right parameters have been set if (ARGV[0] == nil) || (ARGV[1] == nil) usage end if (ARGV[0] == "-create") && (ARGV[2] == nil) usage end ############################################### # HAS TO BE SET BY THE USER AT FIRST USE!!! # ############################################### # WILL CREATE A FOLDER "rfick" FOR THE FILES # ############################################### homepath = "/home/user" # ############################################### # Create the directory to store our files if !File.exist?("#{homepath}/rfick") Dir.mkdir("#{homepath}/rfick") end # Check whether the MD5, SHA1 or RMD160 has been chosen if (ARGV[0] == "-create") if (ARGV[1] == "MD5") md5hash = File.open("#{homepath}/rfick/md5.txt", File::WRONLY|File::TRUNC|File::CREAT, 0777) elsif (ARGV[1] == "SHA1") sha1hash = File.open("#{homepath}/rfick/sha1.txt", File::WRONLY|File::TRUNC|File::CREAT, 0777) elsif (ARGV[1] == "RMD160") rmd160hash = File.open("#{homepath}/rfick/rmd160.txt", File::WRONLY|File::TRUNC|File::CREAT, 0777) else usage end end # Create the file with the hash values if (ARGV[0] == "-create") Dir.open(ARGV[2]) do |dir| dir.each do |file| next if file == "." || file == ".." if (ARGV[2] == "/") path = ARGV[2] + file else path = ARGV[2] + "/" + file end if !File.directory?("#{path}") if (ARGV[1] == "MD5") md5 = Digest::MD5.hexdigest(File.open("#{path}", "rb") { |f| f.read }) md5hash.puts "#{path} | MD5 | " + md5 elsif (ARGV[1] == "SHA1") sha1 = Digest::SHA1.hexdigest(File.open("#{path}", "rb") { |f| f.read }) sha1hash.puts "#{path} | SHA1 | " + sha1 else (ARGV[1] == "RMD160") rmd160 = Digest::RMD160.hexdigest(File.open("#{path}", "rb") { |f| f.read }) rmd160hash.puts "#{path} | RMD160 | " + rmd160 end end end end # Check whether the hash values have changed or not elsif (ARGV[0] == "-check") # Check for MD5 ('md5.txt') if (ARGV[1] == "MD5") # Make sure the file 'md5.txt' really exists if !File.exist?("#{homepath}/rfick/md5.txt") puts "FILE \'md5.txt\' DOES NOT EXIST IN THE SPECIFIED DIRECTORY!" puts "EXITING ..." exit(0) end warnings = 0 md5hash2 = File.open("#{homepath}/rfick/md5.txt", File::RDONLY) begin puts "" puts "--- STARTING FILE INTEGRITY CHECK USING MD5 ---" puts "" while (line = md5hash2.readline) $filepath = line $filepath = $filepath.split(" ") $filepath = $filepath.fetch(0) $hash = line $hash = $hash.split(" ") $hash = $hash.fetch(4) $currenthash = Digest::MD5.hexdigest(File.open("#{$filepath}", "rb") { |f| f.read}) # Compare the current hash with the saved hash if ($hash == $currenthash) next elsif warnings += 1 puts "(!)WARNING(!) HASH CHANGED FOR #{$filepath}" end end rescue EOFError md5hash2.close end puts "" puts "--- FILE INTEGRITY CHECK FINISHED ---" puts "WARNING(S): #{warnings}" puts "" # Check for SHA1 ('sha1.txt') elsif (ARGV[1] == "SHA1") # Make sure the file 'sha1.txt' really exists if !File.exist?("#{homepath}/rfick/sha1.txt") puts "FILE \'sha1.txt\' DOES NOT EXIST IN THE SPECIFIED DIRECTORY!" puts "EXITING ..." exit(0) end warnings = 0 sha1hash2 = File.open("#{homepath}/rfick/sha1.txt", File::RDONLY) begin puts "" puts "--- STARTING FILE INTEGRITY CHECK USING SHA1 ---" puts "" while (line = sha1hash2.readline) $filepath = line $filepath = $filepath.split(" ") $filepath = $filepath.fetch(0) $hash = line $hash = $hash.split(" ") $hash = $hash.fetch(4) $currenthash = Digest::SHA1.hexdigest(File.open("#{$filepath}", "rb") { |f| f.read}) # Compare the current hash with the saved hash if ($hash == $currenthash) next elsif warnings += 1 puts "(!)WARNING(!) HASH CHANGED FOR #{$filepath}" end end rescue EOFError sha1hash2.close end puts "" puts "--- FILE INTEGRITY CHECK FINISHED ---" puts "WARNING(S): #{warnings}" puts "" # Check for RMD160 ('rmd160.txt') elsif (ARGV[1] == "RMD160") # Make sure the file 'rmd160.txt' really exists if !File.exist?("#{homepath}/rfick/rmd160.txt") puts "FILE \'rmd160.txt\' DOES NOT EXIST IN THE SPECIFIED DIRECTORY!" puts "EXITING ..." exit(0) end warnings = 0 rmd160hash2 = File.open("#{homepath}/rfick/rmd160.txt", File::RDONLY) begin puts "" puts "--- STARTING FILE INTEGRITY CHECK USING RMD160 ---" puts "" while (line = rmd160hash2.readline) $filepath = line $filepath = $filepath.split(" ") $filepath = $filepath.fetch(0) $hash = line $hash = $hash.split(" ") $hash = $hash.fetch(4) $currenthash = Digest::RMD160.hexdigest(File.open("#{$filepath}", "rb") { |f| f.read}) # Compare the current hash with the saved hash if ($hash == $currenthash) next elsif warnings += 1 puts "(!)WARNING(!) HASH CHANGED FOR #{$filepath}" end end rescue EOFError rmd160hash2.close end puts "" puts "--- FILE INTEGRITY CHECK FINISHED ---" puts "WARNING(S): #{warnings}" puts "" end else usage end # Check whether MD5, SHA1 or RMD160 has been chosen # and close the file handler finally if (ARGV[0] == "-create") if (ARGV[1] == "MD5") md5hash.close elsif (ARGV[1] == "SHA1") sha1hash.close else (ARGV[1] == "RMD160") rmd160hash.close end end exit(0)