Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
352 lines (288 sloc) 9.61 KB
#!/usr/bin/env python3
"""
poriluk.py 0.2 - Info Leakage Tactical Exploitation Tool
Copyright (c) 2017 Marco Ivaldi <raptor@0xdeadbeef.info>
"The Other Way to Pen-Test" --HD Moore & Valsmith
I've always been a big proponent of a tactical approach
to penetration testing that does not focus on exploiting
known software vulnerabilities, but relies on old school
techniques such as information gathering and brute force.
Poriluk is a helper script that provides a comfortable
interface to exploit common info leakage vulnerabilities.
At the moment, the following attacks are supported:
SMTP: dictionary-based user enumeration via VRFY
SMTP: dictionary-based user enumeration via EXPN
SMTP: dictionary-based user enumeration via RCPT
HTTP: dictionary-based user enumeration via UserDir
Based on:
http://www.0xdeadbeef.info/code/brutus.pl
Requirements:
Python 3 (https://pythonclock.org/ is ticking...)
Example usage:
$ ./poriluk.py smtp -f hosts.txt -r -w users.txt
$ ./poriluk.py http -f hosts.txt -u -w users.txt
TODO:
Implement user enumeration via Microsoft RDP (rdpy)
Implement user enumeration via Cisco Telnet (telnetlib)
Introduce support for multi-threading?
Get the latest version at:
https://github.com/0xdea/tactical-exploitation/
"""
VERSION = "0.2"
BANNER = """
poriluk.py {0} - Info Leakage Tactical Exploitation Tool
Copyright (c) 2017 Marco Ivaldi <raptor@0xdeadbeef.info>
""".format(VERSION)
import sys
import argparse
import smtplib
import urllib.request
import urllib.error
def smtp_enum(args):
"""
SMTP protocol exploitation
"""
wordlist = [u.rstrip() for u in args.w]
targets = get_targets(args)
port = args.P
ssl = args.S
timeout = args.T
debug = args.D
found_glob = 0
if args.vrfy:
cmd = "VRFY"
elif args.expn:
cmd = "EXPN"
elif args.rcpt:
cmd = "RCPT TO:"
if ssl:
call = smtplib.SMTP_SSL
else:
call = smtplib.SMTP
for host in targets:
found_host = 0
print("*** SMTP users on {0} ***\n".format(host))
found_host += smtp_do(call, cmd, wordlist, host, port, timeout, debug)
found_glob += found_host
print("\n*** {0} users found on {1} ***\n".format(found_host, host))
print("*** {0} users found globally ***\n".format(found_glob))
def smtp_do(call, cmd, wordlist, host, port, timeout, debug):
"""
SMTP user enumeration via VRFY/EXPN/RCPT
"""
found = 0
for username in wordlist:
try:
# speed hack: opening a new connection for each user is much faster
with call(
host=host,
port=port,
timeout=timeout,
local_hostname="test.com") as smtp:
# activate debug?
smtp.set_debuglevel(debug)
# initial helo turned out to be needed
smtp.helo("test.com")
if cmd == "RCPT TO:":
smtp.docmd("MAIL FROM:", args="<test@test.com>")
(res, msg) = smtp.docmd(cmd, args=username)
if str(res)[0] == "2": # user found
found += 1
if cmd == "RCPT TO:":
print(username)
else:
print(res, msg.decode(sys.stdout.encoding))
except (KeyboardInterrupt, SystemExit):
if username:
print("// error: interrupted at username '{0}'\n"
.format(username))
sys.exit(1)
except smtplib.SMTPException as err:
if username: # retry current user if timed out
found += smtp_do(
call, cmd, [username], host, port, timeout, debug)
except Exception as err:
print("// error: {0}".format(err))
return found
return found
def http_enum(args):
"""
HTTP protocol exploitation
"""
wordlist = [u.rstrip() for u in args.w]
targets = get_targets(args)
port = args.P
ssl = args.S
timeout = args.T
found_glob = 0
for host in targets:
found_host = 0
print("*** HTTP users on {0} ***\n".format(host))
if ssl:
website = "https://" + host
else:
website = "http://" + host
if port:
website += ":" + port
found_host += http_do(wordlist, website, timeout)
found_glob += found_host
print("\n*** {0} users found on {1} ***\n".format(found_host, host))
print("*** {0} users found globally ***\n".format(found_glob))
def http_do(wordlist, website, timeout):
"""
HTTP user enumeration via UserDir
"""
found = 0
for username in wordlist:
url = website + "/~" + username
try:
# this is blazingly fast
with urllib.request.urlopen(
url=url,
timeout=timeout) as http:
if http.read(1000).decode(sys.stdout.encoding): # user found
found += 1
print(username)
except (KeyboardInterrupt, SystemExit):
if username:
print("// error: interrupted at username '{0}'\n"
.format(username))
sys.exit(1)
except urllib.error.HTTPError as err:
if err.code == 403: # user found
found += 1
print(username)
except Exception as err:
print("// error: {0}".format(err))
return found
return found
def get_targets(args):
"""
Get targets from command line or file
"""
if args.t: return [args.t]
return [t.rstrip() for t in args.f]
def get_args():
"""
Get command line arguments
"""
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(
title="commands",
help="choose target network protocol")
# smtp mode
parser_smtp = subparsers.add_parser(
"smtp",
help="SMTP protocol exploitation")
parser_smtp.set_defaults(func=smtp_enum)
# smtp: actions
group_smtp_actions = parser_smtp.add_mutually_exclusive_group(required=True)
group_smtp_actions.add_argument(
"-v", "--vrfy",
action="store_true",
help="user enumeration via VRFY")
group_smtp_actions.add_argument(
"-e", "--expn",
action="store_true",
help="user enumeration via EXPN")
group_smtp_actions.add_argument(
"-r", "--rcpt",
action="store_true",
help="user enumeration via RCPT")
# smtp: targets
group_smtp_targets = parser_smtp.add_mutually_exclusive_group(required=True)
group_smtp_targets.add_argument(
"-t",
metavar="HOST",
help="specify target hostname or IP address")
group_smtp_targets.add_argument(
"-f",
metavar="FILE",
type=argparse.FileType("r"),
help="specify file containing a list of targets")
# smtp: other arguments
parser_smtp.add_argument(
"-w",
metavar="WORDLIST",
type=argparse.FileType("r"),
required=True,
help="specify username wordlist")
parser_smtp.add_argument(
"-T",
metavar="TIMEOUT",
type=int,
default=5,
help="specify timeout in seconds (default: 5)")
parser_smtp.add_argument(
"-P",
metavar="PORT",
type=int,
default=0,
help="specify port to use (default: 25 or 465)")
parser_smtp.add_argument(
"-S",
action="store_true",
help="enable SMTPS")
parser_smtp.add_argument(
"-D",
action="store_true",
help="enable debug mode")
# http mode
parser_http = subparsers.add_parser(
"http",
help="HTTP protocol exploitation")
parser_http.set_defaults(func=http_enum)
# http: actions
group_http_actions = parser_http.add_mutually_exclusive_group(required=True)
group_http_actions.add_argument(
"-u", "--userdir",
action="store_true",
help="user enumeration via Apache mod_userdir")
# http: targets
group_http_targets = parser_http.add_mutually_exclusive_group(required=True)
group_http_targets.add_argument(
"-t",
metavar="HOST",
help="specify target hostname or IP address")
group_http_targets.add_argument(
"-f",
metavar="FILE",
type=argparse.FileType("r"),
help="specify file containing a list of targets")
# http: other arguments
parser_http.add_argument(
"-w",
metavar="WORDLIST",
type=argparse.FileType("r"),
required=True,
help="specify username wordlist")
parser_http.add_argument(
"-T",
metavar="TIMEOUT",
type=int,
default=5,
help="specify timeout in seconds (default: 5)")
parser_http.add_argument(
"-P",
metavar="PORT",
help="specify port to use (default: 80 or 443)")
parser_http.add_argument(
"-S",
action="store_true",
help="enable HTTPS")
if len(sys.argv) == 1:
parser.print_help()
sys.exit(0)
return parser.parse_args()
def main():
"""
Main function
"""
print(BANNER)
if sys.version_info[0] != 3:
print("// error: this script requires python 3")
sys.exit(1)
args = get_args()
args.func(args)
if __name__ == "__main__":
main()