diff --git a/README.md b/README.md index d4748e5..35d3086 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ + + # spyse.py ![Build Status](https://travis-ci.org/zeropwn/spyse.py.svg?branch=master) [![Python 3.6](https://img.shields.io/badge/Python-3.6-blue.svg)](https://www.python.org/download/releases/3.0/) [![GitHub license](https://img.shields.io/github/license/zeropwn/spyse.py.svg)](https://github.com/zeropwn/spyse.py/blob/master/LICENSE) -![](https://i.imgur.com/vpgzWEi.png) +![](https://i.imgur.com/0zQ8OCP.png) Python API wrapper and command-line client for the tools hosted on spyse.com. @@ -19,6 +21,12 @@ Supports the following APIs: #### NOTE: This API is currently under active development. +## What's New +#### July 6th 2019 +- Query searches. +- Parameter detection. +- Support for the ```domains_starts_with*``` options (library only) +- Default parameters. ## Installation @@ -26,20 +34,43 @@ Supports the following APIs: pip3 install spyse.py ``` +## Updating +```bash +pip3 install spyse.py --upgrade +``` + ## Using the client #### Required Arguments * ```-target``` -* ```-param``` #### Optional Arguments +* ```-param``` * ```-page``` * ```-apikey``` * ```--raw``` #### What is the param argument? -Spyse allows you to search their database for IPs, IP ranges, domain names, URLs, etc. The parameter argument is meant to specify the type of your input. +Spyse allows you to search their database for IPs, IP ranges, domain names, URLs, etc. The parameter argument is meant to specify the type of your input. + +As of July 6th 2019, most of the functions do not require you to set a parameter unless you'd like to override the default one. + +For example, the default parameter for ```--domains-on-ip``` is ```ip```, however you can override this parameter and search by CIDR, or organization instead. You should only need to do this if you're getting an error message, as parameter detection has also been added. + +The detection is quite simple: + +```python +# detect whether input is cidr or ip or search query (q) +if "/" in args.target: + param = "cidr" +elif ":" in args.target: + param = "q" +else: + param = "ip" +``` + +The detection varies from function to function, as certain functions require different default parameters. #### List of parameters * ```cidr``` @@ -51,43 +82,48 @@ Spyse allows you to search their database for IPs, IP ranges, domain names, URLs * ```q``` #### Using search queries -Much like Shodan, Spyse allows you to use search queries. To do this, you must supply the "q" parameter. From there, it's as simple as supplying "org: Microsoft" as the target. +Much like Shodan, Spyse allows you to use search queries. ```bash -spyse -target "org: Microsoft" -param q --ssl-certificates +spyse -target "org: Microsoft" --ssl-certificates ``` #### Searching for subdomains ```bash -spyse -target xbox.com -param domain --subdomains +spyse -target xbox.com --subdomains ``` #### Reverse IP Lookup ```bash -spyse -target 52.14.144.171 -param ip --domains-on-ip +spyse -target 52.14.144.171 --domains-on-ip ``` #### Searching for SSL certificates ```bash -spyse -target hotmail.com -param domain --ssl-certificates +spyse -target hotmail.com --ssl-certificates ``` ```bash -spyse -target "org: Microsoft" -param q --ssl-certificates +spyse -target "org: Microsoft" --ssl-certificates ``` #### Getting all DNS records ```bash -spyse -target xbox.com -param domain --dns-all +spyse -target xbox.com --dns-all +``` + +### Manually overriding the parameter argument +``` +spyse -target hackerone.com -param domain --subdomains ``` #### Navigating multiple pages using your API key ```bash export SPYSEKEY="yourkeyhere" -spyse -target xbox.com -param domain -apikey $SPYSEKEY -page 2 ---ssl-certificates +spyse -target xbox.com -apikey $SPYSEKEY -page 2 ---ssl-certificates ``` #### Piping to jq and aquatone Initially when I decided to write this client I really wanted it to focus on flexibility within the command-line, which is why there is the ```--raw``` option. From there you can work with the raw JSON returned by the API. ```bash -spyse -target hackerone.com -param domain --dns-soa --raw | jq +spyse -target hackerone.com --dns-soa --raw | jq ``` [![asciicast](https://asciinema.org/a/253602.svg)](https://asciinema.org/a/253602) @@ -149,7 +185,7 @@ optional arguments: --ssl-certificates show ssl certificates associated with a target --subdomains show subdomains -Usage: spyse -target -param --subdomains +Usage: spyse -target hackerone.com --subdomains ``` ## Using the library @@ -202,43 +238,43 @@ print(results) All of the methods listed on https://api-doc.spyse.com/ ```python - API_METHODS = { - "DNS_PTR": "/dns-ptr", - "DNS_SOA": "/dns-soa", - "DNS_MX": "/dns-mx", - "DNS_AAAA": "/dns-aaaa", - "DNS_NS": "/dns-ns", - "DNS_A": "/dns-a", - "DNS_TXT": "/dns-txt", - "domains_with_same_ns": "/domains-with-same-ns", - "domains_using_as_mx": "/domains-using-as-mx", - "domains_on_ip": "/domains-on-ip", - "domains_with_same_mx": "/domains-with-same-mx", - "domains_using_as_ns": "/domains-using-as-ns", - "download_dns_aaaa": "/download-dns-aaaa", - "download_dns_soa": "/download-dns-soa", - "download_dns_ns": "/download-dns-ns", - "download_dns_ptr": "/download-ns-ptr", - "download_dns_mx": "/download-dns-mx", - "download_dns_a": "/download-dns-a", - "download_dns_txt": "/download-dns-txt", - "download_domains_with_same_mx": "/download-domains-with-same-mx", - "download_domains_on_ip": "/download-domains-on-ip", - "download_domains_with_same_ns": "/download-domains-with-same-ns", - "download_domains_using_as_ns": "/download-domains-using-as-ns", - "download_domains_using_as_mx": "/download-domains-using-as-mx", - "ip_port_lookup_aggregate": "/ip-port-lookup-aggregate", - "ip_port_lookup": "/ip-port-lookup", - "ssl_certificates": "/ssl-certificates", - "ssl_certificate_raw": "/ssl-certificate-raw", - "ssl_certificates_aggregate": "ssl-certificates-aggregate", - "ssl_certificate": "/ssl-certificate", - "ssl_certificate_public_key": "/ssl-certificate-public-key", - "ssl_certificate_json": "/ssl-certificate-json", - "subdomains": "/subdomains", - "subdomains_aggregate": "/subdomains-aggregate", - "domains_starts_with": "/domains-starts-with", - "domains_starts_with_aggregate": "/domains-starts-with-aggregate" - } + API_METHODS = { + "DNS_PTR": "/dns-ptr", + "DNS_SOA": "/dns-soa", + "DNS_MX": "/dns-mx", + "DNS_AAAA": "/dns-aaaa", + "DNS_NS": "/dns-ns", + "DNS_A": "/dns-a", + "DNS_TXT": "/dns-txt", + "domains_with_same_ns": "/domains-with-same-ns", + "domains_using_as_mx": "/domains-using-as-mx", + "domains_on_ip": "/domains-on-ip", + "domains_with_same_mx": "/domains-with-same-mx", + "domains_using_as_ns": "/domains-using-as-ns", + "download_dns_aaaa": "/download-dns-aaaa", + "download_dns_soa": "/download-dns-soa", + "download_dns_ns": "/download-dns-ns", + "download_dns_ptr": "/download-ns-ptr", + "download_dns_mx": "/download-dns-mx", + "download_dns_a": "/download-dns-a", + "download_dns_txt": "/download-dns-txt", + "download_domains_with_same_mx": "/download-domains-with-same-mx", + "download_domains_on_ip": "/download-domains-on-ip", + "download_domains_with_same_ns": "/download-domains-with-same-ns", + "download_domains_using_as_ns": "/download-domains-using-as-ns", + "download_domains_using_as_mx": "/download-domains-using-as-mx", + "ip_port_lookup_aggregate": "/ip-port-lookup-aggregate", + "ip_port_lookup": "/ip-port-lookup", + "ssl_certificates": "/ssl-certificates", + "ssl_certificate_raw": "/ssl-certificate-raw", + "ssl_certificates_aggregate": "ssl-certificates-aggregate", + "ssl_certificate": "/ssl-certificate", + "ssl_certificate_public_key": "/ssl-certificate-public-key", + "ssl_certificate_json": "/ssl-certificate-json", + "subdomains": "/subdomains", + "subdomains_aggregate": "/subdomains-aggregate", + "domains_starts_with": "/domains-starts-with", + "domains_starts_with_aggregate": "/domains-starts-with-aggregate" + } ``` diff --git a/bin/spyse b/bin/spyse index 134ff52..f51f3d8 100644 --- a/bin/spyse +++ b/bin/spyse @@ -21,7 +21,7 @@ def banner(): parser = argparse.ArgumentParser( description="Client for Spyse.com", - epilog="Usage: spyse -target -param --subdomains") + epilog="Usage: spyse -target hackerone.com --subdomains") parser.add_argument('-target', help="target") parser.add_argument('-param', help="parameter to use (ip, domain, cidr, url, hash)") parser.add_argument('-page', help="page") @@ -356,83 +356,113 @@ def get_ip_port_lookup_aggregate(target, param, page): -if args.target and args.param: +if args.target: if args.page: page = args.page else: page = 1 target = args.target - param = args.param + + if args.param: + param = args.param + else: + param = "domain" if args.dns_ptr: - print(get_dns_ptr(args.target, args.param, page, raw=args.raw)) + print(get_dns_ptr(args.target, param, page, raw=args.raw)) if args.dns_soa: - print(get_dns_soa(args.target, args.param, page, raw=args.raw)) + print(get_dns_soa(args.target, param, page, raw=args.raw)) if args.dns_mx: - print(get_dns_mx(args.target, args.param, page, raw=args.raw)) + print(get_dns_mx(args.target, param, page, raw=args.raw)) if args.dns_aaaa: - print(get_dns_aaaa(args.target, args.param, page, raw=args.raw)) + print(get_dns_aaaa(args.target, param, page, raw=args.raw)) if args.dns_ns: - print(get_dns_ns(args.target, args.param, page, raw=args.raw)) + print(get_dns_ns(args.target, param, page, raw=args.raw)) if args.dns_a: - print(get_dns_a(args.target, args.param, page, raw=args.raw)) + print(get_dns_a(args.target, param, page, raw=args.raw)) if args.dns_txt: - print(get_dns_txt(args.target, args.param, page, raw=args.raw)) + print(get_dns_txt(args.target, param, page, raw=args.raw)) if args.domains_with_same_ns: - print(get_domains_with_same_ns(args.target, args.param, page, raw=args.raw)) + print(get_domains_with_same_ns(args.target, param, page, raw=args.raw)) if args.domains_using_as_mx: - print(get_domains_using_as_mx(args.target, args.param, page, raw=args.raw)) + print(get_domains_using_as_mx(args.target, param, page, raw=args.raw)) if args.domains_on_ip: - print(get_domains_on_ip(args.target, args.param, page, raw=args.raw)) + # detect whether input is cidr or ip or q + if "/" in args.target: + param = "cidr" + elif ":" in args.target: + param = "q" + else: + param = "ip" + print(get_domains_on_ip(args.target, param, page, raw=args.raw)) if args.subdomains: - print(get_subdomains_aggregate(args.target, args.param, page, raw=args.raw)) + print(get_subdomains_aggregate(args.target, param, page, raw=args.raw)) if args.dns_all: - print(get_dns_all(args.target, args.param, page)) + print(get_dns_all(args.target, param, page)) if args.domains_using_as_ns: - print(get_domains_using_as_ns(args.target, args.param, page)) + print(get_domains_using_as_ns(args.target, param, page)) if args.download_dns_aaaa: - print(get_download_dns_aaaa(args.target, args.param, page)) + print(get_download_dns_aaaa(args.target, param, page)) if args.download_dns_soa: - print(get_download_dns_soa(args.target, args.param, page)) + print(get_download_dns_soa(args.target, param, page)) if args.download_dns_ns: - print(get_download_dns_ns(args.target, args.param, page)) + print(get_download_dns_ns(args.target, param, page)) if args.download_dns_ptr: - print(get_download_dns_ptr(args.target, args.param, page)) + print(get_download_dns_ptr(args.target, param, page)) if args.download_dns_mx: - print(get_download_dns_mx(args.target, args.param, page)) + print(get_download_dns_mx(args.target, param, page)) if args.download_dns_a: - print(get_download_dns_a(args.target, args.param, page)) + print(get_download_dns_a(args.target, param, page)) if args.download_dns_txt: - print(get_download_dns_txt(args.target, args.param, page)) + print(get_download_dns_txt(args.target, param, page)) if args.download_dns_all: - print(get_download_dns_all(args.target, args.param, page)) + print(get_download_dns_all(args.target, param, page)) if args.ssl_certificates: - print(get_ssl_certificates(args.target, args.param, page)) + # detect whether input is cidr or ip or q + if "/" in args.target: + param = "cidr" + elif ":" in args.target: + param = "q" + print(get_ssl_certificates(args.target, param, page)) if args.ip_port_lookup: - print(get_ip_port_lookup(args.target, args.param, page)) + # detect whether input is cidr or ip or q + if "/" in args.target: + param = "cidr" + elif ":" in args.target: + param = "q" + else: + param = "ip" + print(get_ip_port_lookup(args.target, param, page)) if args.ip_port_lookup_aggregate: - print(get_ip_port_lookup_aggregate(args.target, args.param, page)) + # detect whether input is cidr or ip or q + if "/" in args.target: + param = "cidr" + elif ":" in args.target: + param = "q" + else: + param = "ip" + print(get_ip_port_lookup_aggregate(args.target, param, page)) diff --git a/setup.py b/setup.py index 67eaee9..8a23a43 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ long_description = f.read() setup(name='spyse.py', - version='0.13.3.8', + version='0.13.3.9', description='API wrapper & client for spyse.com', long_description=long_description, long_description_content_type='text/markdown', diff --git a/spyse/spyse.py b/spyse/spyse.py index e71e6ef..5241cfb 100644 --- a/spyse/spyse.py +++ b/spyse/spyse.py @@ -50,6 +50,7 @@ class spyse: API_TARGET_PARAMS = [ 'cidr', 'domain', + 'sdword', 'ip', 'page', 'url', @@ -202,7 +203,7 @@ def domains_using_as_mx(self, target, param='domain', page=1): # Provides information about domains on same IP/CIDR. If domain is provided, # method will return domains that have matching IPs. If two or more parameters # are provided, method will return domains satisfying each of the conditions. - def domains_on_ip(self, target, param='domain', page=1): + def domains_on_ip(self, target, param='ip', page=1): if param not in self.API_TARGET_PARAMS: return "Invalid parameter." r = requests.get("{}/{}?api_token={}&{}={}&page={}".format( @@ -356,7 +357,7 @@ def download_domains_with_same_mx(self, target, param='domain', page=1): return r.text # Downloading domains on same IP in .txt or .tsv format. - def download_domains_on_ip(self, target, param='domain', page=1): + def download_domains_on_ip(self, target, param='ip', page=1): if param not in self.API_TARGET_PARAMS: return "Invalid parameter." r = requests.get("{}/{}?api_token={}&{}={}&page={}".format( @@ -440,7 +441,7 @@ def ip_port_lookup(self, target, param='domain', page=1): return r.json() # Provides list of SSL certificates. - def ssl_certificates(self, target, param='url', page=1): + def ssl_certificates(self, target, param='domain', page=1): if param not in self.API_TARGET_PARAMS: return "Invalid parameter." if param == 'domain': @@ -456,7 +457,7 @@ def ssl_certificates(self, target, param='url', page=1): return r.json() # Returns raw ssl certificate. - def ssl_certificate_raw(self, target, param='url', page=1): + def ssl_certificate_raw(self, target, param='domain', page=1): if param not in self.API_TARGET_PARAMS: return "Invalid parameter." if param == 'domain': @@ -560,7 +561,7 @@ def subdomains_aggregate(self, target, param='domain', page=1): return r.json() # Returns a list of domains that starts with provided sdword. - def domains_starts_with(self, target, param='domain', page=1): + def domains_starts_with(self, target, param='sdword', page=1): if param not in self.API_TARGET_PARAMS: return "Invalid parameter." r = requests.get("{}/{}?api_token={}&{}={}&page={}".format( @@ -577,7 +578,7 @@ def domains_starts_with(self, target, param='domain', page=1): # with provided sdword, list of IPs of subdomains and subdomain count on every IP, # list of AS numbers and subdomain count on every AS number, list of countries and # subdomain count from it, list of CIDRs /24, /16 and subdomain list on every CIDR. - def domains_starts_with_aggregate(self, target, param='domain', page=1): + def domains_starts_with_aggregate(self, target, param='sdword', page=1): if param not in self.API_TARGET_PARAMS: return "Invalid parameter." r = requests.get("{}/{}?api_token={}&{}={}&page={}".format(