View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0005467 | Kali Linux | New Tool Requests | public | 2019-05-29 14:11 | 2019-09-30 13:29 |
| Reporter | altjx | Assigned To | |||
| Priority | normal | Severity | major | Reproducibility | N/A |
| Status | closed | Resolution | won't fix | ||
| Product Version | 2019.2 | ||||
| Summary | 0005467: [Tool Submission] Leprechaun - Post-exploitation tool to help identify valuable services and systems | ||||
| Description | Leprechaun is a tool created by Alton Johnson (@altonjx) to help penetration testers identify valuable resources on an internal network penetration test. For example, when obtaining domain administrator with a tool such as Bloodhound, the user is able to run recursive netstat commands on multiple hosts and use Leprechaun to aggregate the results, spitting out a nice beautiful graph to display what connections are established within the environment. Essentially, they're able to map out the data flow. Reddit post: https://www.reddit.com/r/netsec/comments/bu2470/postexploitation_with_leprechaun_finding/ I also have a previous tool that was submitted in Kali, called iSMTP, in case that helps expedite the process for me. Thanks! Regards, | ||||
| Steps To Reproduce | Simply run the command with the following arguments: ./leprechaun.rb -p 80 -f netstat_results.txt -t internal | ||||
| Attached Files | leprechuan.rb (6,721 bytes)
just wanted to say i really appreciate being part of a good family here over the last 4 years. i'm officially moving to ATL in a little less than two weeks (planning on leaving out June 7th) to continue growing my business. i've been talking about it and wanting to for years, but now is the perfect time. with the additional of another full-time employee on my team, the pressure is on -- shit's about to get real, lol.#!/usr/bin/env ruby
#
# This tool was intended to be used during post-exploitation.
# Essentially, once you have elevated privileges, you can run a recursive netstat
# using tools such as winexe, smbexec, psexec, whatever., and parse it here.
#
# See the GitHub or blog page for more information.
#
# Author; Alton Johnson (@altonjx)
# Company: Vonahi Security (@vonahi_security)
# Created: 05/22/2019
# Version: 1.0
#
['securerandom','terminal-table','getopt/std'].each(&method(:require))
def help
puts "\n " + "-" * 61
puts " \e[1;34mLeprechaun v1.0 - Alton Johnson (@altonjx)\e[0;00m"
puts " " + "-" * 61
puts "\n Usage: #{$0} -f /path/to/netstat_results.txt -p <port>"
puts "\n -f\tFile containing the output of netstat results."
puts " -p\tPort you're interested in. e.g., 80. Specify \"all\", \"common\", or separate ports with commas"
puts " -t\tThe type of destination IP addresses you want to see connections to (e.g. external/internal/all)."
puts "\n Example: #{$0} -f netstat_output.txt -p 80"
puts " Example: #{$0} -f netstat_output.txt -p all"
puts " Example: #{$0} -f netstat_output.txt -p common"
puts " Example: #{$0} -f netstat_output.txt -p 80,443 -t external"
puts "\n"
exit
end
PRIVATE_IPS = [
IPAddr.new('10.0.0.0/8'),
IPAddr.new('172.16.0.0/12'),
IPAddr.new('192.168.0.0/16'),
].freeze
class Leprechaun
def initialize(netstat_results, ports, ip_type)
@servers = {}
@clients = {}
@dest_port_mappings = []
@source_port_mappings = []
@ip_type = ip_type
@data = File.open(netstat_results).read.split("\n")
if ports.include? ","
@ports = ports.split(",")
else
@ports = ports
end
@digraph = "digraph {\n"
@digraph += "\toverlap = false;\n\n"
@digraph_headers = "\t# Servers and clients are defined here.\n"
@digraph_data = "\t# Connections are defined here.\n"
end
def private_ip?(ip_address)
if ip_address.is_a?(String)
ip_address = IPAddr.new(ip_address)
end
PRIVATE_IPS.any? { |private_ip| private_ip.include?(ip_address) }
end
def parse_data
@data.each do |line|
routes = line.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}:\d+\b/)
next if routes.empty? or routes.nil?
begin
source_ip = routes[0].split(":")[0] # source IP address
source_port = routes[0].split(":")[1] # source port
dest_ip = routes[1].split(":")[0] # destination IP address
dest_port = routes[1].split(":")[1] # destination port
rescue
next
end
next if dest_ip == "0.0.0.0"
# Skip depending on type of traffic the user wants.
if @ip_type == "internal"
next unless private_ip? dest_ip
elsif @ip_type == "external"
next if private_ip? dest_ip
end
protocol = (line.downcase.include?("tcp") ? "tcp" : "udp")
well_known = [17,21,22,23,25,53,69,80,81,86,110,123,135,139,143,161,389,443,445,587,636,1311,1433,1434,1720,2301,2381,3306,3389,4443,47001,5060,5061,5432,5500,5900,5901,5985,5986,7080,8080,8081,8082,8089,8000,8180,8443]
if @ports.include? "common"
next unless well_known.include? dest_port.to_i
end
if [email protected]? "all" and [email protected]? "common"
if [email protected]? dest_port
next
end
end
if @servers[dest_ip].nil? # avoid adding duplicate connections
server_hex = SecureRandom.hex(2)
@servers[dest_ip] = {:hex => "", :ports => {}, :client_count => 0}
@servers[dest_ip][:hex] = "s#{server_hex}"
@digraph_headers += "\t#{@servers[dest_ip][:hex]} [label = < <b>#{dest_ip}</b> >, fillcolor=gold3, fontcolor=white, style=filled, shape=egg];\n"
end
if @servers[dest_ip][:ports]["#{dest_port}/#{protocol}"].nil?
@servers[dest_ip][:ports]["#{dest_port}/#{protocol}"] = {:clients => [], :client_count => 0}
end
unless @servers[dest_ip][:ports]["#{dest_port}/#{protocol}"][:clients].include? source_ip
@servers[dest_ip][:ports]["#{dest_port}/#{protocol}"][:clients] << source_ip # add source IP
@servers[dest_ip][:ports]["#{dest_port}/#{protocol}"][:client_count] += 1
@servers[dest_ip][:client_count] += 1
end
if @clients[source_ip].nil? # avoid adding duplicate connections
client_hex = SecureRandom.hex(2)
@clients[source_ip] = "c#{client_hex}"
@digraph_headers += "\t#{@clients[source_ip]} [label = \"#{source_ip}\", fillcolor=green3, style=filled];\n"
end
if @dest_port_mappings.include? [dest_ip, "#{dest_port}/#{protocol}"]
unless @source_port_mappings.include? [source_ip, "#{dest_port}/#{protocol}"]
@digraph_data += "\t\"#{@clients[source_ip]}\" -> \"#{dest_port}/#{protocol}\";\n"
@source_port_mappings << [source_ip, "#{dest_port}/#{protocol}"]
end
else
@dest_port_mappings << [dest_ip, "#{dest_port}/#{protocol}"]
@source_port_mappings << [source_ip, "#{dest_port}/#{protocol}"]
@digraph_data += "\t\"#{@clients[source_ip]}\" -> \"#{dest_port}/#{protocol}\" -> #{@servers[dest_ip][:hex]};\n"
end
end
@digraph += "#{@digraph_headers}\n #{@digraph_data}"
@digraph += "}"
end
def print_table
# Most connected clients.
headers = ['Server','Number of connected clients','Highest traffic destination port']
data = [] # server IP address, connected clients, connected ports
@servers.each do |ip, server_values|
connected_clients = server_values[:client_count]
ports = [] # port, # of connected clients
server_values[:ports].each do |port, port_values|
ports << [port, port_values[:client_count]]
end
ports.sort {|a,b| a[1] <=> b[1]}
data << [ip, connected_clients, ports[0]]
end
data = data.sort {|a,b| a[1] <=> b[1]}.reverse
table = Terminal::Table.new do |t|
t.add_row headers
t.add_separator
data.each do |line|
t.add_row [line[0], line[1], "#{line[2][0]} (#{line[2][1]} connections)"]
end
end
puts table
end
def write_to_file
puts "\n [*] Completed! Graph output file located at: ./network_diagram.png\n\n"
File.open("data.dot", "w") {|f| f.write(@digraph)}
`sfdp -Tpng data.dot -o network_diagram.png -Grankdir=LR`
end
end
if $0 == __FILE__
if ARGV.length == 0
help
end
opt = Getopt::Std.getopts("f:p:t:")
fail "Please specify a netstat output file (-f) as well as a port (-p)." unless opt['f'] and opt['p']
opt['t'] = "all" if opt['t'].nil?
lep = Leprechaun.new(opt['f'], opt['p'], opt['t'])
lep.parse_data
lep.write_to_file
lep.print_table
end | ||||
|
Some additional information (based on what I saw in another issue): To help speed up the process of evaluating the tool, please make sure to include the following information (the more information you include, the more beneficial it will for us): Name: Leprechaun
|
|
|
Thank you for the submission, however we haven't got the cycles to add this in |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2019-05-29 14:11 | altjx | New Issue | |
| 2019-05-29 14:11 | altjx | File Added: leprechuan.rb | |
| 2019-05-29 14:15 | altjx | Note Added: 0010638 | |
| 2019-09-30 13:29 | g0tmi1k | Status | new => closed |
| 2019-09-30 13:29 | g0tmi1k | Resolution | open => won't fix |
| 2019-09-30 13:29 | g0tmi1k | Note Added: 0011150 |