| Initial commit. - honeypot - A custom version of kippo used for SSH honeypot an… | |
| Log | |
| Files | |
| Refs | |
| README | |
| --- | |
| commit 03dc4267c9106f78667c8cefba995d4f74d643b4 | |
| Author: Jay Scott <[email protected]> | |
| Date: Sat, 1 Sep 2018 22:18:53 +0100 | |
| Initial commit. | |
| Diffstat: | |
| A README | 51 +++++++++++++++++++++++++++++… | |
| A blacklist.rb | 49 +++++++++++++++++++++++++++++… | |
| A current-charts.rb | 99 +++++++++++++++++++++++++++++… | |
| A dump.php | 37 +++++++++++++++++++++++++++++… | |
| A report.php | 250 +++++++++++++++++++++++++++++… | |
| A snippets.php | 76 +++++++++++++++++++++++++++++… | |
| 6 files changed, 562 insertions(+), 0 deletions(-) | |
| --- | |
| diff --git a/README b/README | |
| @@ -0,0 +1,51 @@ | |
| + | |
| + __ ___ __ __ ___ | |
| +|__| / \ |\ | |__ \ / |__) / \ | | |
| +| | \__/ | \| |___ | | \__/ | | |
| + | |
| + | |
| +--- | |
| + | |
| + | |
| +This is the source code I used for my honeypot project. A lot of it is | |
| +hacked together but hopefully someone will find it useful! To get the | |
| +Ruby scripts to work you will need to install mysql and gruff gems. | |
| + | |
| + | |
| + $ gem install mysql | |
| + $ gem install gruff | |
| + | |
| + | |
| +The script to report an IP address uses PEAR mail but this is actually | |
| +not needed, I only used it to send mail via gmail. You can simply | |
| +change this to PHP's mail() function. | |
| + | |
| + | |
| +> blacklist.rb | |
| + | |
| +Generates list of IP's that have been carrying out SSH attacks, useful | |
| +for creating blacklists for IPTables, IOS etc | |
| + | |
| + | |
| +> report.php | |
| + | |
| +Gets the IP address from the kippo DB and reports the IP for abuse if | |
| +certain conditions are met. Then saves the information to a 'report' | |
| +table for displaying the information at a later date. | |
| + | |
| + | |
| +> dump.php | |
| + | |
| +This was used to output the UML blobs in the Kippo DB to a file to be | |
| +read by ajaxterm. | |
| + | |
| + | |
| +> current-charts.rb | |
| + | |
| +Ruby script I used to create the graphs for the front page. | |
| + | |
| + | |
| +> snippets.php | |
| + | |
| +This is just wee snippets of code I used through-out my code that | |
| +I think might be useful to some people :-) | |
| diff --git a/blacklist.rb b/blacklist.rb | |
| @@ -0,0 +1,49 @@ | |
| +#!/usr/bin/ruby | |
| + | |
| + | |
| +require 'rubygems' | |
| +require 'mysql' | |
| + | |
| +# Set the dates we want to start at | |
| +date = Time.new | |
| + | |
| +# Change pass to your password. | |
| +con_kippo = Mysql.new('localhost', 'kippo', 'pass', 'kippo') | |
| + | |
| +rs_list = con_kippo.query("SELECT ip | |
| + FROM sessions | |
| + WHERE starttime LIKE '2011-#{date.month}%' | |
| + GROUP BY ip | |
| + ORDER BY ip") | |
| + | |
| +ip_list = Array.new | |
| + | |
| +while row = rs_list.fetch_row do | |
| + ip_list.push row[0] | |
| +end | |
| + | |
| +rs_list.free | |
| + | |
| +# You may want to define the absolute path in the following code blocks. | |
| +File.open('ip-list.txt', 'w') do |f2| | |
| + ip_list.each do|ip| | |
| + f2.puts ip | |
| + end | |
| +end | |
| + | |
| +File.open('ip-list-iptables.txt', 'w') do |f2| | |
| + ip_list.each do|ip| | |
| + f2.puts "iptables -A INPUT -s #{ip} -j LOG --log-prefix \"Blocked: JayScot… | |
| + f2.puts "iptables -A INPUT -s #{ip} -j DROP" | |
| + end | |
| +end | |
| + | |
| +File.open('ip-list-cisco.txt', 'w') do |f2| | |
| + ip_list.each do|ip| | |
| + f2.puts "access-list 1 deny host #{ip}" | |
| + end | |
| + f2.puts "access-list 1 permit any" | |
| +end | |
| + | |
| + | |
| +con_kippo.close | |
| diff --git a/current-charts.rb b/current-charts.rb | |
| @@ -0,0 +1,99 @@ | |
| +#!/usr/bin/ruby | |
| +# | |
| +# Generates the current graph. | |
| +# | |
| +# gem install gruff | |
| +# gem install mysql | |
| +# | |
| + | |
| +require 'rubygems' | |
| +require 'gruff' | |
| +require 'mysql' | |
| + | |
| +# Set the dates we want | |
| +date = Time.new | |
| +current_date = "#{date.year}-0#{date.month}" | |
| +string_month = Date::MONTHNAMES[date.month] | |
| + | |
| +puts current_date | |
| +g = Gruff::Line.new("600x300") | |
| +g.title = "#{string_month} 2012 Attacks" | |
| + | |
| +# Set the font options | |
| +g.font = 'LiberationMono-Regular.ttf' | |
| +g.marker_font_size = 12 | |
| +g.legend_font_size = 12 | |
| +g.title_font_size = 12 | |
| + | |
| +# Set the chart colours | |
| +@green = '#339933' | |
| +@purple = '#cc99cc' | |
| +@blue = '#336699' | |
| +@yellow = '#a21764' | |
| +@red = '#ff0000' | |
| +@orange = '#cf5910' | |
| +@black = 'black' | |
| +@colors = [@yellow, @blue, @green, @red, @black, @purple, @orange] | |
| + | |
| +# Set the chart look | |
| +g.legend_box_size = 12 | |
| +g.marker_count = 12 | |
| +g.line_width = 1 | |
| +g.dot_radius = 2 | |
| +g.theme = { | |
| + :colors => @colors, | |
| + :marker_color => '#aea9a9', | |
| + :font_color => 'black', | |
| + :background_colors => 'white' | |
| +} | |
| + | |
| +# Change the password to the kippo DB | |
| +con_kippo = Mysql.new('localhost', 'kippo', 'your-pass', 'kippo') | |
| + | |
| +rs_sensors = con_kippo.query("SELECT id, ip FROM sensors") | |
| + | |
| +while row_sensor = rs_sensors.fetch_row do | |
| + | |
| + rs_current = con_kippo.query("SELECT DISTINCT DATE(starttime) AS Date, COUNT… | |
| + FROM sessions | |
| + WHERE starttime | |
| + LIKE '#{current_date}%' | |
| + AND sensor=#{row_sensor[0]} | |
| + GROUP BY Date | |
| + ORDER BY Date") | |
| + | |
| + attack_list = [] | |
| + total_attacks = 0 | |
| + | |
| + puts "Current sensor is #{row_sensor[1]}" | |
| + puts "Number of rows #{rs_current.num_rows}" | |
| + while row = rs_current.fetch_row do | |
| + #puts "Row 1 = #{row[1]} Row 2 = #{row[0]}" | |
| + attack_list << row[1].to_i | |
| + total_attacks = total_attacks + row[1].to_i | |
| + end | |
| + | |
| + #puts "Attack list is #{attack_list}" | |
| + | |
| + if total_attacks > 0 then | |
| + legend = "#{row_sensor[1]} (#{total_attacks})" | |
| + g.data(legend, attack_list) | |
| + end | |
| + | |
| + rs_current.free | |
| + | |
| +end | |
| + | |
| +x = 0 | |
| +days_list = {} | |
| + | |
| +while x < 31 do | |
| + days_list[x] = "#{x +1}" | |
| + x = x + 1 | |
| +end | |
| + | |
| +g.labels = days_list | |
| +g.write('current-month.png') | |
| + | |
| +con_kippo.close | |
| + | |
| diff --git a/dump.php b/dump.php | |
| @@ -0,0 +1,37 @@ | |
| +<?php | |
| + | |
| +/* | |
| + * Script that I ran on the cron to dump the .log files into a directory for | |
| + * ajax-term to read. | |
| + * | |
| + */ | |
| + | |
| +# Change to your information. | |
| +$db = mysql_pconnect("localhost","kippo","your-password"); | |
| +mysql_select_db("kippo",$db); | |
| + | |
| +# I found that if the log was < 85 there was normally no command issued. | |
| +$QUERY_TTY = mysql_query("SELECT id, session FROM ttylog WHERE LENGTH(ttylog) … | |
| + | |
| +if($QUERY_TTY) | |
| + echo "Query Complete\n"; | |
| +else | |
| + echo "Query Failed\n"; | |
| + | |
| +$num_rows = mysql_num_rows($QUERY_TTY); | |
| + | |
| +echo "Rows = $num_rows \n"; | |
| +echo mysql_error(); | |
| + | |
| +# Change location-to-store-logs to where you want to store the Kippo log files… | |
| +while($tty_row = mysql_fetch_array($QUERY_TTY)) { | |
| + mysql_query("SELECT ttylog FROM ttylog WHERE id=" . $tty_row['id'] . " into … | |
| + if($tty_row){ | |
| + echo " Command is successful \n"; | |
| + echo "ttylog = " . $tty_row['id'] . "\n"; | |
| + } | |
| + else | |
| + echo " Command not successful \n"; | |
| +} | |
| + | |
| +?> | |
| diff --git a/report.php b/report.php | |
| @@ -0,0 +1,250 @@ | |
| +<?php | |
| + | |
| +/* | |
| + * Gets the IP address from the kippo DB and reports the IP for abuse if certa… | |
| + * conditions are met. Then saves the information to a 'report' table for | |
| + * displaying information at a later date. | |
| + * | |
| + * I still have debugging echo statements etc floating about :p | |
| + * | |
| + * | |
| + * report table - added to kippo database | |
| + * | |
| + * CREATE TABLE IF NOT EXISTS `report` ( | |
| + * `id` int(11) NOT NULL AUTO_INCREMENT, | |
| + * `name` char(50) NOT NULL, | |
| + * `ip` varchar(15) NOT NULL, | |
| + * `contact` varchar(200) NOT NULL, | |
| + * `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMES… | |
| + * `replied` tinyint(1) NOT NULL DEFAULT '0', | |
| + * `contacted` tinyint(1) NOT NULL DEFAULT '1', | |
| + * `notes` text NOT NULL, | |
| + * PRIMARY KEY (`id`) | |
| + * ); | |
| + * | |
| + * | |
| + * Uses pears Mail script, this can be easily change to PHP's mail(). | |
| + * | |
| + * pear install Mail | |
| + * | |
| + */ | |
| + | |
| +error_reporting(0); | |
| + | |
| +require_once "Mail.php"; | |
| + | |
| +function attackAttempts($id, $db) | |
| +{ | |
| + $result = mysql_query("SELECT COUNT(id) AS IPCOUNT FROM sessions WHERE ip ='… | |
| + if ($row = mysql_fetch_array($result)) | |
| + return (int) $row['IPCOUNT']; | |
| +} | |
| + | |
| +function attackSuccessful($id, $db) | |
| +{ | |
| + $result = mysql_query("SELECT auth.session, auth.success FROM auth | |
| + INNER JOIN sessions ON auth.session… | |
| + WHERE auth.success=1 AND sessions.ip='$id'"); | |
| + | |
| + $num_rows = (int) mysql_num_rows($result); | |
| + return $num_rows; | |
| +} | |
| + | |
| +/* Change to your Kippo DB password */ | |
| +$db = mysql_pconnect("localhost", "kippo", "yourpassword"); | |
| +mysql_select_db("kippo", $db); | |
| + | |
| +$previous_date = date("Y-m-d", strtotime("-1 day")); | |
| + | |
| +$QUERY_ATTACKS = mysql_query("SELECT auth.session, auth.`timestamp`, MAX(sessi… | |
| + sessions.ip, sessions.sensor | |
| + FROM auth INNER JOIN sessions ON auth.session = … | |
| + WHERE timestamp >= '$previous_date' | |
| + GROUP BY sessions.ip | |
| + ORDER BY auth.id "); | |
| + | |
| +while ($ROW_ATTACKER = mysql_fetch_array($QUERY_ATTACKS)) | |
| + { | |
| + $IPADDRESS = $ROW_ATTACKER["ip"]; | |
| + $START = $ROW_ATTACKER["MAXTIME"]; | |
| + $END = $ROW_ATTACKER["MINTIME"]; | |
| + $SENSOR = $ROW_ATTACKER["sensor"]; | |
| + $SESSION = $ROW_ATTACKER["session"]; | |
| + $TIMESTAMP = $ROW_ATTACKER["timestamp"]; | |
| + | |
| + /* Already in the DB? dont report again */ | |
| + $IP_EXISTS = mysql_query("SELECT contacted FROM report WHERE ip='$IPADDRES… | |
| + | |
| + if ($ROW_EXISTS = mysql_fetch_array($IP_EXISTS)) { | |
| + continue; | |
| + } | |
| + | |
| + echo "IP = $IPADDRESS\n"; | |
| + | |
| + $attack_success = 0; | |
| + $total_attacks = attackAttempts($IPADDRESS, $db); | |
| + $attack_success = attackSuccessful($IPADDRESS, $db); | |
| + | |
| + if ($total_attacks > 10 ) | |
| + echo "More than 10 attempts ($total_attacks) ($attack_success)\n"; | |
| + else if ($attack_success > 0) | |
| + echo "Attack Success ($total_attacks) ($attack_success)\n"; | |
| + else { | |
| + echo "Less than 10 attempts ($total_attacks) ($attack_success)\n"; | |
| + continue; | |
| + } | |
| + | |
| + $email = array(); | |
| + | |
| + unset($f); | |
| + /* Shouldn't need to sanitise the IP address */ | |
| + exec("whois $IPADDRESS ", $f); | |
| + unset($tmpname); | |
| + unset($output); | |
| + | |
| + foreach ($f as $output) { | |
| + if (stripos($output, "netname:") === 0) | |
| + $tmpname = explode(':',$output); | |
| + else if (stripos($output, "owner:") === 0) | |
| + $tmpname = explode(':',$output); | |
| + | |
| + preg_match('/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i', $output, $matches); | |
| + | |
| + $email[] = strtolower($matches[0]); | |
| + $email = array_filter($email); | |
| + } | |
| + | |
| + $email = array_filter($email); | |
| + $email = array_unique($email); | |
| + | |
| + $EMAILS = implode(" ",$email); | |
| + $NAME = trim($tmpname[1]); | |
| + $email_parts = explode(" ", $EMAILS); | |
| + | |
| + foreach ($email_parts as $b_email) { | |
| + | |
| + $EMAIL_ABUSE = 0; | |
| + $tmp_username = substr($b_email, 0, strpos($b_email, '@')); | |
| + $tmp_username = strtolower($tmp_username); | |
| + if ( $tmp_username == "abuse" || $tmp_username == "support") { | |
| + $EMAIL_ABUSE = 1; | |
| + $EMAILS = $b_email; | |
| + } | |
| + } | |
| + | |
| + if (empty($email)) { | |
| + $INSERT_REPORT = mysql_query("INSERT INTO report (name, ip, contact, con… | |
| + continue; | |
| + } else { | |
| + $INSERT_REPORT = mysql_query("INSERT INTO report (name, ip, contact, d… | |
| + } | |
| + | |
| + unset($to); | |
| + $parts = explode(" ", $EMAILS); | |
| + if (sizeof($parts) == 1) | |
| + $to = rtrim($parts[0],'.'); | |
| + else { | |
| + foreach ($parts as $send_cc) { | |
| + $send_cc = rtrim($send_cc,'.'); | |
| + $to .= "$send_cc,"; | |
| + } | |
| + | |
| + $to = substr($to, 0, -1); | |
| + } | |
| + echo "TO = $to"; | |
| + | |
| + /* Kippo stored the IP of the sensor as a name in the 'sensors' table, get | |
| + * the sensor ID and then identify IP. | |
| + */ | |
| + switch ($SENSOR) | |
| + { | |
| + case 1: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 2: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 3: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 4: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 5: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 6: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 7: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + case 8: | |
| + $TARGET = "ip-removed"; | |
| + break; | |
| + } | |
| + | |
| + /* My SMTP information, change to yours or remove and add the default | |
| + PHP mail() command */ | |
| + $host = "ssl://smtp.gmail.com"; | |
| + $port = "465"; | |
| + $username = ""; | |
| + $password = ''; | |
| + | |
| + $subject = "SSH attack from $IPADDRESS"; | |
| + $from = '[email protected]'; | |
| + $headers = "From: $from \r\n" . "Reply-To: $from \r\n"; | |
| + | |
| + $message = "To abuse/support,"; | |
| + | |
| + if ($EMAIL_ABUSE = 0) { | |
| + $message .= " | |
| + | |
| + Please note I could not find a abuse or support email address in an | |
| + WHOIS lookup."; | |
| + } | |
| + | |
| + $message .= " | |
| + | |
| + I run a honeypot network that reports any attacking IP address or | |
| + successful logins from unauthorised IP address. | |
| + | |
| + The IP $IPADDRESS first gained access or attempted to access the | |
| + honeypot on $START GMT against the IP address $TARGET."; | |
| + | |
| + $message .= " | |
| + | |
| + It maybe that $IPADDRESS has been compromised, is an active | |
| + participant in a botnet or is being used as a SSH tunnel. | |
| + | |
| + You may wish to monitor the IP Address. You can view more details about | |
| + the attack such as any more attacks carried out, amount of attacks and | |
| + even watch the attack if they successfully logged in here: | |
| + | |
| + http://honeypot.jayscott.co.uk/ip/$IPADDRESS | |
| + | |
| + If you would like any advice or require further information please | |
| + feel free to contact me, [email protected]. | |
| + | |
| + Regards, | |
| + Jay Scott"; | |
| + | |
| + $headers = array ('From' => $from, | |
| + 'To' => $to, | |
| + 'Subject' => $subject); | |
| + $smtp = Mail::factory('smtp', | |
| + array ('host' => $host, | |
| + 'port' => $port, | |
| + 'auth' => true, | |
| + 'username' => $username, | |
| + 'password' => $password)); | |
| + | |
| + $mail = $smtp->send($to, $headers, $message); | |
| + | |
| + if (PEAR::isError($mail)) { | |
| + echo(" - " . $mail->getMessage() . "\n"); | |
| + } else { | |
| + echo(" - Message sent\n\n"); | |
| + } | |
| + } | |
| +?> | |
| diff --git a/snippets.php b/snippets.php | |
| @@ -0,0 +1,76 @@ | |
| +<? | |
| + | |
| +/* | |
| + * Various code snippets I used in pages through-out the project, didn't think | |
| + * there was much point in displaying all of the HTML etc. | |
| + */ | |
| + | |
| + | |
| +/* === Get unique Malware links === */ | |
| + | |
| +$QUERY_DOWNLOAD = mysql_query("SELECT input.input, input.timestamp, sessions.ip | |
| + FROM input INNER JOIN sessions | |
| + ON input.session = sessions.id | |
| + WHERE input.input LIKE '%wget%' | |
| + GROUP BY input.input | |
| + ORDER BY input.timestamp DESC "); | |
| + | |
| +while ($DOWNLOAD_ROW = mysql_fetch_array($QUERY_DOWNLOAD)) { | |
| + if (strlen($DOWNLOAD_ROW['input']) > 8) { | |
| + | |
| + $Date = strtotime($DOWNLOAD_ROW["timestamp"]); | |
| + $myDate = date('D jS M, G:i:s', $Date); | |
| + | |
| + $URL = htmlspecialchars($DOWNLOAD_ROW['input']); | |
| + | |
| + echo "<tr><td>$myDate</td> | |
| + <td>" . substr($URL, 5) . "</td></tr>"; | |
| + } | |
| +} | |
| + | |
| + | |
| + | |
| +/* === Get unique passwords === */ | |
| + | |
| +$sql_date = mysql_real_escape_string($_GET['date']); | |
| + | |
| +if ($sql_date == 'all') { | |
| + $previous_date = "2011-02-01"; /* date I started logging via sql */ | |
| +} else if ($sql_date == 'week') { | |
| + $previous_date = date("Y-m-d", strtotime("-7 day")); | |
| +} else if ($sql_date == 'month') { | |
| + $previous_date = date("Y-m-d", strtotime("-30 day")); | |
| +} else { | |
| + $previous_date = date("Y-m-d", strtotime("-1 day")); | |
| +} | |
| + | |
| +/* simply change password to username for username stats */ | |
| +$query_passwords = mysql_query("SELECT COUNT(password) AS PCOUNT, password | |
| + FROM auth WHERE password <> '' | |
| + AND timestamp >= '$previous_date' | |
| + GROUP BY password | |
| + ORDER BY PCOUNT DESC LIMIT 20"); | |
| + | |
| + | |
| +/* === Showing information on the attack === */ | |
| + | |
| +$QUERY_CLIENT = mysql_query("SELECT version FROM clients | |
| + WHERE id = '$CLIENT' | |
| + LIMIT 1"); | |
| + | |
| +$CLIENT_SEARCH = strtolower($ROWS_CLIENT['version']); | |
| + | |
| + if (strpos($CLIENT_SEARCH, "putty")) | |
| + echo "<b>Connected Manually</b> "; | |
| + else if (strpos($CLIENT_SEARCH, "libssh")) | |
| + echo "<b>Used a C scanner</b> "; | |
| + else if (strpos($CLIENT_SEARCH, "winscp")) | |
| + echo "<b>Used WinSCP</b> "; | |
| + else if (strpos($CLIENT_SEARCH, "openssh")) | |
| + echo "<b>Connected Manually</b> "; | |
| + else if (strpos($CLIENT_SEARCH, "nmap")) | |
| + echo "<b>NMap Scan</b> "; | |
| + | |
| + | |
| + | |
| +?> |