Home How does AutoPWN Suite work?
Post
Cancel

How does AutoPWN Suite work?

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.

Open in 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.

This post is licensed under CC BY 4.0 by the author.
Contents