What is AutoPWN Suite?
AutoPWN Suite is a project for scanning vulnerabilities and exploiting systems automatically.
Demo
AutoPWN Suite has a very user friendly easy to read output.
How does it work?
AutoPWN Suite uses nmap TCP-SYN scan to enumerate the host and detect the version of softwares running on it. After gathering enough information about the host, AutoPWN Suite automatically generates a list of “keywords” to search NIST vulnerability database.
Scanning
To create nmap scans in python we use nmap module for python.
Host Discovery
To start doing host discovery, we first have to figure out which scan type we should use. Here’s how it’s done:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def InitArgsScanType(args, log):
scantype = ScanType.Ping
if args.scan_type == "arp":
if is_root():
scantype = ScanType.ARP
else:
log.logger(
"warning",
"You need to be root in order to run arp scan.\n"
+ "Changed scan mode to Ping Scan.",
)
elif args.scan_type is None or args.scan_type == "":
if is_root():
scantype = ScanType.ARP
return scantype
We now know which scan type to use for host discovery. Let’s also get our target to scan.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def InitArgsTarget(args, log):
if args.target:
target = args.target
else:
if args.host_file:
# read targets from host file and insert all of them into an array
try:
with open(args.host_file, "r", encoding="utf-8") as target_file:
target = target_file.read().splitlines()
except FileNotFoundError:
log.logger("error", "Host file not found!")
except PermissionError:
log.logger("error", "Permission denied while trying to read host file!")
except Exception:
log.logger("error", "Unknown error while trying to read host file!")
else:
return target
target = DetectIPRange()
else:
if DontAskForConfirmation:
try:
target = DetectIPRange()
except Exception as e:
log.logger("error", e)
target = input("Enter target range to scan : ")
else:
try:
target = input("Enter target range to scan : ")
except KeyboardInterrupt:
raise SystemExit("Ctrl+C pressed. Exiting.")
return target
Here’s how we detect target IP address range automatically:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def GetIpAdress() -> str:
s = socket(AF_INET, SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
PrivateIPAdress = str(s.getsockname()[0])
return PrivateIPAdress
def DetectIPRange() -> str:
PrivateIPAdress = GetIpAdress().split(".")
target = (
f"{PrivateIPAdress[0]}."
+ f"{PrivateIPAdress[1]}."
+ f"{PrivateIPAdress[2]}.0/24"
)
return target
Now we know our target and scan type we are going to use. So let’s get to scanning!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def DiscoverHosts(target, console, scantype=ScanType.ARP, mode=ScanMode.Normal) -> list:
if isinstance(target, list):
banner(
f"Scanning {len(target)} target(s) using {scantype.name} scan ...",
"green",
console,
)
else:
banner(f"Scanning {target} using {scantype.name} scan ...", "green", console)
if scantype == ScanType.ARP:
OnlineHosts = TestArp(target, mode)
else:
OnlineHosts = TestPing(target, mode)
return OnlineHosts
Online hosts in our network is returned from the function.
Port Scanning
In the previous part we ran a scan in our network to detect hosts that are online. But that information on it’s own is not enough. We need to detect the version of softwares running on the target machine. In order to do that, we scan the target machine for open ports.
It’s actually pretty straight forward.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def PortScan(
target,
log,
scanspeed=5,
host_timeout=240,
mode=ScanMode.Normal,
customflags="",
) -> PortScanner:
log.logger("info", f"Scanning {target} for open ports ...")
nm = PortScanner()
try:
if is_root():
if mode == ScanMode.Evade:
nm.scan(
hosts=target,
arguments=" ".join(
[
"-sS",
"-sV",
"-O",
"-Pn",
"-T",
"2",
"-f",
"-g",
"53",
"--data-length",
"10",
customflags,
]
),
)
else:
nm.scan(
hosts=target,
arguments=" ".join(
[
"-sS",
"-sV",
"--host-timeout",
str(host_timeout),
"-Pn",
"-O",
"-T",
str(scanspeed),
customflags,
]
),
)
else:
nm.scan(
hosts=target,
arguments=" ".join(
[
"-sV",
"--host-timeout",
str(host_timeout),
"-Pn",
"-T",
str(scanspeed),
customflags,
]
),
)
except Exception as e:
raise SystemExit(f"Error: {e}")
else:
return nm
Analyzing the Results
We ran a port scan on the host, but we didn’t print any information on the screen yet. We are going to use a custom function to analyze results and print them on to screen.
As I documented in the code snippet, we returned a PortScanner
object as results, let’s analyze it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def AnalyseScanResults(nm, log, console, target=None) -> list:
"""
Analyse and print scan results.
"""
HostArray = []
if target is None:
target = nm.all_hosts()[0]
try:
nm[target]
except KeyError:
log.logger("warning", f"Target {target} seems to be offline.")
return []
CurrentTargetInfo = InitHostInfo(nm[target])
if is_root():
if nm[target]["status"]["reason"] in ["localhost-response", "user-set"]:
log.logger("info", f"Target {target} seems to be us.")
elif GetIpAdress() == target:
log.logger("info", f"Target {target} seems to be us.")
if len(nm[target].all_tcp()) == 0:
log.logger("warning", f"Target {target} seems to have no open ports.")
return HostArray
banner(f"Portscan results for {target}", "green", console)
if not CurrentTargetInfo.mac == "Unknown" and not CurrentTargetInfo.os == "Unknown":
console.print(CurrentTargetInfo.colored(), justify="center")
table = Table(box=box.MINIMAL)
table.add_column("Port", style="cyan")
table.add_column("State", style="white")
table.add_column("Service", style="blue")
table.add_column("Product", style="red")
table.add_column("Version", style="purple")
for port in nm[target]["tcp"].keys():
state, service, product, version = InitPortInfo(nm[target]["tcp"][port])
table.add_row(str(port), state, service, product, version)
if state == "open":
HostArray.insert(len(HostArray), [target, port, service, product, version])
console.print(table, justify="center")
return HostArray
Vulnerability detection
We scanned our host and now we now its open ports and some additional information on those ports.
Now this part is where I consider to be the actual magic. This part is essentially what makes vulnerability detection work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def GenerateKeyword(product: str, version: str) -> str:
if product == "Unknown":
product = ""
if version == "Unknown":
version = ""
keyword = ""
dontsearch = [
"ssh",
"vnc",
"http",
"https",
"ftp",
"sftp",
"smtp",
"smb",
"smbv2",
"linux telnetd",
"microsoft windows rpc",
"metasploitable root shell",
"gnu classpath grmiregistry",
]
if product.lower() not in dontsearch and product != "":
keyword = f"{product} {version}".rstrip()
return keyword
def GenerateKeywords(HostArray: list) -> list:
keywords = []
for port in HostArray:
product = str(port[3])
version = str(port[4])
keyword = GenerateKeyword(product, version)
if not keyword == "" and not keyword in keywords:
keywords.append(keyword)
return keywords
We generated our list of keywords, now it’s time to turn them into search queries and throw them at the NIST vulnerability database as a POST request then see what we get.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def SearchSploits(HostArray: list, log, console, console2, apiKey=None) -> list:
VulnsArray = []
target = str(HostArray[0][0])
term_width = get_terminal_width()
if not CheckConnection(log):
return []
keywords = GenerateKeywords(HostArray)
if len(keywords) == 0:
log.logger("warning", f"Insufficient information for {target}")
return []
log.logger(
"info", f"Searching vulnerability database for {len(keywords)} keyword(s) ..."
)
printed_banner = False
with console2.status(
"[white]Searching vulnerabilities ...[/white]", spinner="bouncingBar"
) as status:
for keyword in keywords:
status.start()
status.update(
"[white]Searching vulnerability database for[/white] "
+ f"[red]{keyword}[/red] [white]...[/white]"
)
ApiResponseCVE = SearchKeyword(keyword, log, apiKey)
status.stop()
if len(ApiResponseCVE) == 0:
continue
if not printed_banner:
banner(f"Possible vulnerabilities for {target}", "red", console)
printed_banner = True
console.print(f"┌─ [yellow][ {keyword} ][/yellow]")
CVEs = []
for CVE in ApiResponseCVE:
CVEs.append(CVE.CVEID)
console.print(f"│\n├─────┤ [red]{CVE.CVEID}[/red]\n│")
wrapped_description = wrap(CVE.description, term_width - 50)
console.print(f"│\t\t[cyan]Description: [/cyan]")
for line in wrapped_description:
console.print(f"│\t\t\t{line}")
console.print(
f"│\t\t[cyan]Severity: [/cyan]{CVE.severity} - {CVE.severity_score}\n"
+ f"│\t\t[cyan]Exploitability: [/cyan] {CVE.exploitability}\n"
+ f"│\t\t[cyan]Details: [/cyan] {CVE.details_url}"
)
VulnObject = VulnerableSoftware(title=keyword, CVEs=CVEs)
VulnsArray.append(VulnObject)
console.print("└" + "─" * (term_width - 1))
return VulnsArray
Automatically downloading exploits
We scanned our host and found some vulnerabilities. Now it’s time for exploitation! To exploit our target we will need to download “exploit codes”.
Here’s the structre of what an exploit code will look like in our program.
1
2
3
4
5
6
7
8
9
10
@dataclass
class ExploitInfo:
Platform: str
PublishDate: str
Type: str
ExploitDBID: int
Author: str
Metasploit: bool
Verified: bool
Link: str
Getting our exploits
This part is pretty straight forward. Just passing every “vulnerability” object to our GetExploitAsFile
function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def GetExploitsFromArray(VulnsArray, log, console, console2, target=None) -> None:
if target:
banner(f"Downloading exploits for {target}...", "blue", console)
else:
banner(f"Downloading exploits...", "blue", console)
with console2.status(
"[red]Downloading exploits ...[/red]", spinner="bouncingBar"
) as status:
for vulnerability in VulnsArray:
status.start()
status.update(
f"[white]Downloading exploits for[/white] "
+ f"[red]{vulnerability.title}[/red] [white]...[/white]"
)
try:
GetExploitAsFile(vulnerability, log, console, status)
except KeyboardInterrupt:
log.logger("warning", f"Skipping exploits for {vulnerability.title}")
Getting some info about our exploit
We will gather some information about our exploit to print it onto terminal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def GetExploitAsFile(vulnerability, log, console, status) -> None:
SoftwareName = vulnerability.title
CVEs = vulnerability.CVEs
term_width = get_terminal_width()
if not exists("exploits"):
mkdir("exploits")
printed_software = []
for CVE in CVEs:
Exploits = GetExploitInfo(CVE, log)
if len(Exploits) == 0:
continue
status.stop()
if SoftwareName not in printed_software:
console.print(f"┌─[yellow][ {SoftwareName} ][/yellow]\n│")
printed_software.append(SoftwareName)
console.print(f"│\n├─────┤ [red]{str(CVE)}[/red]\n│")
for exploit in Exploits:
content, filename = GetExploitContents(exploit.Link, log)
if content is None:
continue
if not exists(f"exploits/{SoftwareName}"):
mkdir(f"exploits/{SoftwareName}")
if not exists(f"exploits/{SoftwareName}/{CVE}"):
mkdir(f"exploits/{SoftwareName}/{CVE}")
with open(f"exploits/{SoftwareName}/{CVE}/{filename}", "wb") as exploitfile:
console.print(
f"├──────────# [white]exploits/{SoftwareName}/{CVE}/{filename}[/white]\n"
+ f"│\t\t [cyan]Platform: [/cyan] {exploit.Platform}\n"
+ f"│\t\t [cyan]Type: [/cyan] {exploit.Type}\n"
+ f"│\t\t [cyan]Author: [/cyan] {exploit.Author}\n"
+ f"│\t\t [cyan]Date: [/cyan] [bright_cyan]{exploit.PublishDate}[/bright_cyan]\n"
+ f"│\t\t [cyan]Metasploit: [/cyan] {exploit.Metasploit}\n"
+ f"│\t\t [cyan]Verified: [/cyan]{exploit.Verified}\n"
+ f"│\t\t [cyan]Link: [/cyan] {exploit.Link}\n│"
)
exploitfile.write(content)
if SoftwareName in printed_software:
console.print("└" + "─" * (term_width - 1) + "\n")
Noise mode
This mode is for generating a lot of suspicious activity in the network to cause a lot of false positives in IDS/IPS and network logs.
Creating noisy processes
This part we use multi threading module that is built into python to create separate processes for each host.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def NoiseScan(target, log, console, scantype=ScanType.ARP, noisetimeout=None) -> None:
banner("Creating noise...", "green", console)
Uphosts = TestPing(target)
if scantype == ScanType.ARP:
if is_root():
Uphosts = TestArp(target)
try:
with console.status("Creating noise ...", spinner="line"):
NoisyProcesses = []
for host in Uphosts:
log.logger("info", f"Started creating noise on {host}...")
P = Process(target=CreateNoise, args=(host,))
NoisyProcesses.append(P)
P.start()
if noisetimeout:
sleep(noisetimeout)
else:
while True:
sleep(1)
log.logger("info", "Noise scan complete!")
for P in NoisyProcesses:
P.terminate()
raise SystemExit
except KeyboardInterrupt:
log.logger("error", "Noise scan interrupted!")
raise SystemExit
Creating the noise
This part is also pretty straight forward. We spawn a nmap process with speed set to 5.
1
2
3
4
5
6
7
8
9
10
11
12
def CreateNoise(target):
nm = PortScanner()
while True:
try:
if is_root():
nm.scan(hosts=target, arguments="-A -T 5 -D RND:10")
else:
nm.scan(hosts=target, arguments="-A -T 5")
except KeyboardInterrupt:
raise SystemExit("Ctr+C, aborting.")
else:
break
Installation
You can install it using pip. (sudo recommended)
1
sudo pip install autopwn-suite
OR
You can clone the repo.
1
2
3
git clone https://github.com/GamehunterKaan/AutoPWN-Suite.git
cd AutoPWN-Suite
sudo pip install -r requirements.txt
OR
You can download debian (deb) package from releases.
1
2
sudo pip install requests rich python-nmap bs4 distro
sudo apt-get install ./autopwn-suite_2.1.1.deb
OR
You can use Google Cloud Shell.
Usage
Running with root privileges (sudo) is always recommended.
Automatic mode
1
autopwn-suite -y
Help Menu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
$ autopwn-suite -h
usage: autopwn.py [-h] [-v] [-y] [-c CONFIG] [-nc] [-t TARGET] [-hf HOST_FILE] [-sd] [-st {arp,ping}] [-nf NMAP_FLAGS] [-s {0,1,2,3,4,5}] [-ht HOST_TIMEOUT] [-a API] [-m {evade,noise,normal}] [-nt TIMEOUT]
[-o OUTPUT] [-ot {html,txt,svg}] [-rp {email,webhook}] [-rpe EMAIL] [-rpep PASSWORD] [-rpet EMAIL] [-rpef EMAIL] [-rpes SERVER] [-rpesp PORT] [-rpw WEBHOOK]
AutoPWN Suite | A project for scanning vulnerabilities and exploiting systems automatically.
options:
-h, --help show this help message and exit
-v, --version Print version and exit.
-y, --yes-please Don't ask for anything. (Full automatic mode)
-c CONFIG, --config CONFIG
Specify a config file to use. (Default : None)
-nc, --no-color Disable colors.
Scanning:
Options for scanning
-t TARGET, --target TARGET
Target range to scan. This argument overwrites the hostfile argument. (192.168.0.1 or 192.168.0.0/24)
-hf HOST_FILE, --host-file HOST_FILE
File containing a list of hosts to scan.
-sd, --skip-discovery
Skips the host discovery phase.
-st {arp,ping}, --scan-type {arp,ping}
Scan type.
-nf NMAP_FLAGS, --nmap-flags NMAP_FLAGS
Custom nmap flags to use for portscan. (Has to be specified like : -nf="-O")
-s {0,1,2,3,4,5}, --speed {0,1,2,3,4,5}
Scan speed. (Default : 3)
-ht HOST_TIMEOUT, --host-timeout HOST_TIMEOUT
Timeout for every host. (Default :240)
-a API, --api API Specify API key for vulnerability detection for faster scanning. (Default : None)
-m {evade,noise,normal}, --mode {evade,noise,normal}
Scan mode.
-nt TIMEOUT, --noise-timeout TIMEOUT
Noise mode timeout.
Reporting:
Options for reporting
-o OUTPUT, --output OUTPUT
Output file name. (Default : autopwn.log)
-ot {html,txt,svg}, --output-type {html,txt,svg}
Output file type. (Default : html)
-rp {email,webhook}, --report {email,webhook}
Report sending method.
-rpe EMAIL, --report-email EMAIL
Email address to use for sending report.
-rpep PASSWORD, --report-email-password PASSWORD
Password of the email report is going to be sent from.
-rpet EMAIL, --report-email-to EMAIL
Email address to send report to.
-rpef EMAIL, --report-email-from EMAIL
Email to send from.
-rpes SERVER, --report-email-server SERVER
Email server to use for sending report.
-rpesp PORT, --report-email-server-port PORT
Port of the email server.
-rpw WEBHOOK, --report-webhook WEBHOOK
Webhook to use for sending report.
Module usage
1
2
3
4
5
from autopwn_suite.api import AutoScanner
scanner = AutoScanner()
json_results = scanner.scan("192.168.0.1")
scanner.save_to_file("autopwn.json")
TODO
Do you have a cool feature idea? Create a feature request!
- 22 Completed.
- Arch Linux package for Arch based systems like BlackArch and ArchAttack.
- Function to brute force common services like
ssh
,vnc
,ftp
. - GUI interface.
- Daemon mode.
Contributing to AutoPWN Suite
I would be glad if you are willing to contribute this project. I am looking forward to merge your pull request unless its something that is not needed or just a personal preference. Also minor changes and bug fixes will not be merged. Please create an issue for those and I will do it myself. Click here for more info!
Legal
You may not rent or lease, distribute, modify, sell or transfer the software to a third party. AutoPWN Suite is free for distribution, and modification with the condition that credit is provided to the creator and not used for commercial use. You may not use software for illegal or nefarious purposes. No liability for consequential damages to the maximum extent permitted by all applicable laws.
Support or Contact
Having trouble using this tool? You can reach me out on discord, create an issue or create a discussion!
Support & Hire Me!
If you want to support my work and also get your job done you can hire me on Fiverr! I do various things such as website pentesting, python programming, cleaning malware, PC optimization, file recovery and mentoring.