Ruby Server Monitor

Ruby Server Monitor

README

This was a post requested by a visitor of this website, here I speak about some tools that I use usually in my work administrating servers and preventing vulnerabilities in the company’s web applications. Well, basically as a server administrator we need to be vigilant to possible disk space problems, memory exceeding or hacking attempts, so that I decided to write this script in Ruby (because I love Ruby) to get a real-time information about:

  • Disk space in server’s disk partitions (only in SDA/HDA),
  • Uptime, users on-line and load average,
  • Finally I included a basic access.log viewer which colorize suspicious requests, IP address (configurable to use with commonly proxies), unusual HTTP response codes, and unusual URI access (configurable for web scanners fuzzers),

I don’t pretend to use this script to stop all the problems in my job, because obviously there are a lot of good hackers with very good knowledges in server vulnerabilities and because unfortunately the script spend approximately 1.8MB pulling the process, but well, this is a good step to begin :D. Here is the list of tools that I use commonly in a normal day:

  • Top: is the Linux native tool that provide an ongoing look at processor activity in real time of a computer; it displays a listing of the most CPU-interactive tasks on the system, and can provide an interactive interface for manipulating processes (try to read the manual man top to get the full feature list and the colorized interface),
  • HTop: this is a very good interactive process viewer for Linux which use NCurses and good coloring for X Terminals, a good choice for administrators that doesn’t like the classic black and white terminal window,
  • RKHunter, it’s a Rootkit Hunter for systems that change frequently; also it give us good tips to take in account for system optimization.

Additionally you may want to use God Ruby, an easy to configure and extend monitoring framework: GodRB.com, recommended by the The Ruby Toolbox project in its server monitoring category.

Code

#!/usr/bin/env ruby
class SystemMonitor
    def initialize(access_log, sleep_time, lines)
        while( 1 ) do
            system('clear')
            self.uptime()
            self.disk_usage()
            puts '    ========== Last 10 Requests =========='
            self.access_log(lines, access_log)
            sleep sleep_time
        end
    end
    def colorize(type, value)
        suspicious = false
        case type
        when 'uri' then
            suspicious = [ 'hack', 'cgi-bin' ]
        when 'http_code' then
            return "\033[1;31m#{value}\033[0m" if ![200, 301, 302].include?(value.to_i)
        when 'user_agent' then
            suspicious = [ 'libcurl', 'nikto' ]
        when 'ip_address' then
            suspicious = []
        end
        if suspicious!=false then
            suspicious.each do |s|
                if !value.to_s.index(s.to_s).nil? then
                    return "\033[1;31m#{value}\033[0m"
                end
            end
        end
        return value
    end
    def disk_usage()
        %x{df -ah}.split("\n").each do |line|
            match = line.chomp.match(/^(\/dev\/[s|h]da[\d+])\s(.*)/)
            if !match.nil?
                part = match[0].split(' ')
                puts "[+] \033[1;36m#{part[0]}\033[0m mounted in \033[1;33m#{part[5]}\033[0m"
                puts "    Available: #{100 - part[4].gsub('[M|G]', '').to_i}% [#{part[3]} of #{part[1]}]"
                puts "    Used.....: #{part[4]} = #{part[2]}"
            end
        end
    end
    def uptime()
        uptime = %x{uptime}.match(/\s(.*),[ ]+(\d+ users),[ ]+load average: (.*)/)
        puts "[+] Uptime:"
        puts "    #{uptime[1]} with #{uptime[2]}"
        puts "    Load average: #{uptime[3]}"
    end
    def access_log(lines, access_log)
        %x{tail -n #{lines} #{access_log}}.split("\n").each do |line|
            match = line.chomp.match(/(.*) - - \[(.*)\] "([A-Z]+) (.*) (.*)" (\d+) (\d+) "(.*)" "(.*)"/)
            puts "[+] " + self.colorize('ip_address', match[3]) + " request from #{match[1]} at #{match[2]}"
            puts "    URI path: " + self.colorize('uri', match[4])
            puts "      HTTP response: Got " + self.colorize('http_code', match[6]) + " HTTP response code with #{match[5]} version"
            puts "      User-agent: " + self.colorize('user_agent', match[9])
            puts "      Response size: #{match[7]}"
            puts "      Redirect: #{match[8]}" if !match[8].empty? and match[8]!='-'
        end
    end
end
system_monitor = SystemMonitor.new(ARGV[0], 1, 7)
Do you have a project idea? Let's make it together!