Skip to content

Commit ce7a401

Browse files
committed
chore: Upgrade modules
1 parent f1379e4 commit ce7a401

18 files changed

+613
-563
lines changed

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Censys recon-ng Modules
1+
# Censys `recon-ng` Modules
22

33
[![License](https://img.shields.io/github/license/censys/censys-recon-ng)](LICENSE)
44
[![Code Style](https://img.shields.io/badge/code%20style-black-000000)](https://github.com/psf/black)
@@ -12,7 +12,7 @@ We have written several modules for [`recon-ng`](https://github.com/lanmaster53/
1212
We have provided two pieces you need to install these modules and begin using them.
1313

1414
- `requirements.txt` - Use this via `pip install -r requirements.txt` to install Python dependencies.
15-
- `install.sh`- Run this script and it will both install the modules in your home directory (recon-ng supports modules added for the local user in `~/.recon-ng`) and configures the database to add support for your Censys API ID and secret. See your Censys [account](https://censys.io/account/api) for your credentials, and add them to the database as you would any other credential - `keys add ...`.
15+
- `install.sh`- Run this script and it will both install the modules in your home directory (recon-ng supports modules added for the local user in `~/.recon-ng`) and configures the database to add support for your Censys API ID and secret. See your Censys [account](https://search.censys.io/account/api) for your credentials, and add them to the database as you would any other credential - `keys add ...`.
1616

1717
One you have completed these you can fire up `recon-ng`.
1818

@@ -30,8 +30,9 @@ These are normal recon-ng modules, use them like any other. Pivot away! This rep
3030
-----
3131
recon/companies-contacts/censys_email_address
3232
recon/companies-domains/censys_subdomains
33-
recon/companies-hosts/censys_org
34-
recon/companies-hosts/censys_tls_subjects
33+
recon/companies-multi/censys_org
34+
recon/companies-multi/censys_tls_subjects
35+
recon/contacts-domains/censys_email_to_domains
3536
recon/domains-companies/censys_companies
3637
recon/domains-hosts/censys_domain
3738
recon/hosts-hosts/censys_query

censys_companies.py

+39-47
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,54 @@
11
from recon.core.module import BaseModule
22

3-
from censys.ipv4 import CensysIPv4
4-
from censys.base import CensysException
3+
from censys.search import CensysHosts
4+
from censys.common.exceptions import CensysException
55

66

77
class Module(BaseModule):
88
meta = {
9-
'name': 'Censys companies by domain',
10-
'author': 'J Nazario',
11-
'version': '1.1',
12-
'description': 'Retrieves the TLS certificates for a domain. Updates the \'companies\' table with the values from the subject organization information.',
13-
'query': 'SELECT DISTINCT domain FROM domains WHERE domain IS NOT NULL',
14-
'dependencies': ['censys'],
15-
'required_keys': ['censysio_id', 'censysio_secret'],
9+
"name": "Censys - Companies by Domain",
10+
"author": "Censys, Inc. <[email protected]>",
11+
"version": 2.1,
12+
"description": (
13+
"Retrieves the TLS certificates for a domain. This module queries"
14+
" the 'services.tls.certificates.leaf_data.names' field and"
15+
" updates the 'companies' table with the results."
16+
),
17+
"query": (
18+
"SELECT DISTINCT domain FROM domains WHERE domain IS NOT NULL"
19+
),
20+
"options": [
21+
(
22+
"num_buckets",
23+
"100",
24+
False,
25+
"maximum number of buckets to retrieve",
26+
)
27+
],
28+
"required_keys": ["censysio_id", "censysio_secret"],
29+
"dependencies": ["censys>=2.1.2"],
1630
}
1731

1832
def module_run(self, domains):
19-
api_id = self.get_key('censysio_id')
20-
api_secret = self.get_key('censysio_secret')
21-
c = CensysIPv4(api_id, api_secret, timeout=self._global_options['timeout'])
22-
IPV4_FIELDS = [
23-
'443.https.tls.certificate.parsed.subject.organization',
24-
'25.smtp.starttls.tls.certificate.parsed.subject.organization',
25-
'110.pop3.starttls.tls.certificate.parsed.subject.organization',
26-
'465.smtp.tls.tls.certificate.parsed.subject.organization',
27-
'587.smtp.starttls.tls.certificate.parsed.subject.organization',
28-
'1521.oracle.banner.tls.certificate.parsed.subject.organization',
29-
'3306.mysql.banner.tls.certificate.parsed.subject.organization',
30-
'3389.rdp.banner.tls.certificate.parsed.subject.organization',
31-
'5432.postgres.banner.tls.certificate.parsed.subject.organization',
32-
'8883.mqtt.banner.tls.certificate.parsed.subject.organization',
33-
]
34-
SEARCH_FIELDS = [
35-
'443.https.tls.certificate.parsed.names',
36-
'25.smtp.starttls.tls.certificate.parsed.names',
37-
'110.pop3.starttls.tls.certificate.parsed.names',
38-
'465.smtp.tls.tls.certificate.parsed.names',
39-
'587.smtp.starttls.tls.certificate.parsed.names',
40-
'1521.oracle.banner.tls.certificate.parsed.names',
41-
'3306.mysql.banner.tls.certificate.parsed.names',
42-
'3389.rdp.banner.tls.certificate.parsed.names',
43-
'5432.postgres.banner.tls.certificate.parsed.names',
44-
'8883.mqtt.banner.tls.certificate.parsed.names',
45-
]
33+
api_id = self.get_key("censysio_id")
34+
api_secret = self.get_key("censysio_secret")
35+
c = CensysHosts(api_id, api_secret)
4636
for domain in domains:
37+
domain = domain.strip('"')
4738
self.heading(domain, level=0)
4839
try:
49-
query = 'mx:"{0}" OR '.format(domain) + ' OR '.join(
50-
['{0}:"{1}"'.format(x, domain) for x in SEARCH_FIELDS]
40+
report = c.aggregate(
41+
"same_service(services.tls.certificates.leaf_data.names:"
42+
f" {domain} and"
43+
" services.tls.certificates.leaf_data.subject.organization: *)",
44+
field="services.tls.certificates.leaf_data.subject.organization",
45+
num_buckets=int(self.options.get("NUM_BUCKETS", "100")),
5146
)
52-
payload = c.search(query, IPV4_FIELDS)
5347
except CensysException:
48+
self.print_exception()
5449
continue
55-
for result in payload:
56-
orgs = set()
57-
for k, v in result.items():
58-
if k.endswith('.parsed.subject.organization'):
59-
for org in v:
60-
orgs.add(org)
61-
for org in orgs:
62-
self.insert_companies(company=org)
50+
for bucket in report.get("buckets", []):
51+
company = bucket.get("key")
52+
self.insert_companies(
53+
company=company, description=f"Domain: {domain}"
54+
)

censys_company_netname.py

-65
This file was deleted.

censys_domain.py

+64-56
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,81 @@
11
from recon.core.module import BaseModule
22

3-
from censys.ipv4 import CensysIPv4
4-
from censys.base import CensysException
3+
from censys.search import CensysHosts
4+
from censys.common.exceptions import CensysException
55

66

77
class Module(BaseModule):
88
meta = {
9-
'name': 'Censys hosts and subdomains by domain',
10-
'author': 'J Nazario',
11-
'version': '1.1',
12-
'description': 'Retrieves the MX, SMTPS, POP3S, and HTTPS records for a domain. Updates the \'hosts\' and the \'ports\' tables with the results.',
13-
'query': 'SELECT DISTINCT domain FROM domains WHERE domain IS NOT NULL',
14-
'dependencies': ['censys'],
15-
'required_keys': ['censysio_id', 'censysio_secret'],
9+
"name": "Censys - Hosts by domain",
10+
"author": "Censys, Inc. <[email protected]>",
11+
"version": 2.1,
12+
"description": (
13+
"Retrieves hosts for a domain. This module queries queries domain"
14+
" names and updates the 'hosts' and the 'ports' tables with the"
15+
" results."
16+
),
17+
"query": (
18+
"SELECT DISTINCT domain FROM domains WHERE domain IS NOT NULL"
19+
),
20+
"required_keys": ["censysio_id", "censysio_secret"],
21+
"options": [
22+
(
23+
"virtual_hosts",
24+
"ONLY",
25+
False,
26+
"Whether to include virtual hosts in the results",
27+
),
28+
(
29+
"per_page",
30+
"100",
31+
False,
32+
"The number of results to return per page",
33+
),
34+
(
35+
"pages",
36+
"1",
37+
False,
38+
"The number of pages to retrieve",
39+
),
40+
],
41+
"dependencies": ["censys>=2.1.2"],
1642
}
1743

1844
def module_run(self, domains):
19-
api_id = self.get_key('censysio_id')
20-
api_secret = self.get_key('censysio_secret')
21-
c = CensysIPv4(api_id, api_secret, timeout=self._global_options['timeout'])
22-
IPV4_FIELDS = [
23-
'ip',
24-
'protocols',
25-
'location.country',
26-
'location.latitude',
27-
'location.longitude',
28-
'location.province',
29-
]
30-
SEARCH_FIELDS = [
31-
'443.https.tls.certificate.parsed.names',
32-
'25.smtp.starttls.tls.certificate.parsed.names',
33-
'110.pop3.starttls.tls.certificate.parsed.names',
34-
]
45+
api_id = self.get_key("censysio_id")
46+
api_secret = self.get_key("censysio_secret")
47+
c = CensysHosts(api_id, api_secret)
3548
for domain in domains:
49+
domain = domain.strip('"')
3650
self.heading(domain, level=0)
3751
try:
38-
query = 'mx:"{0}" OR '.format(domain) + ' OR '.join(
39-
['{0}:"{1}"'.format(x, domain) for x in SEARCH_FIELDS]
52+
query = c.search(
53+
f"{domain}",
54+
per_page=int(self.options.get("PER_PAGE", "100")),
55+
pages=int(self.options.get("PAGES", "1")),
56+
virtual_hosts=self.options.get("VIRTUAL_HOSTS", "ONLY"),
4057
)
41-
payload = c.search(query, IPV4_FIELDS + SEARCH_FIELDS)
4258
except CensysException:
59+
self.print_exception()
4360
continue
44-
for result in payload:
45-
names = set()
46-
for k, v in result.items():
47-
if k.endswith('.parsed.names'):
48-
for name in v:
49-
names.add(name)
50-
if len(names) < 1:
51-
# make sure we have at least a blank name
52-
names.add('')
53-
for name in names:
54-
if name.startswith('*.'):
55-
self.insert_domains(name.replace('*.', ''))
56-
continue
57-
self.insert_hosts(
58-
host=name,
59-
ip_address=result['ip'],
60-
country=result.get('location.country', ''),
61-
region=result.get('location.province', ''),
62-
latitude=result.get('location.latitude', ''),
63-
longitude=result.get('location.longitude', ''),
64-
)
65-
66-
for protocol in result['protocols']:
67-
port, service = protocol.split('/')
61+
for hit in query():
62+
common_kwargs = {
63+
"ip_address": hit["ip"],
64+
"host": hit.get("name"),
65+
}
66+
location = hit.get("location", {})
67+
coords = location.get("coordinates", {})
68+
self.insert_hosts(
69+
region=location.get("continent"),
70+
country=location.get("country"),
71+
latitude=coords.get("latitude"),
72+
longitude=coords.get("longitude"),
73+
**common_kwargs,
74+
)
75+
for service in hit.get("services", []):
6876
self.insert_ports(
69-
ip_address=result['ip'],
70-
host=name,
71-
port=port,
72-
protocol=service,
77+
port=service["port"],
78+
protocol=service["transport_protocol"],
79+
notes=service["service_name"],
80+
**common_kwargs,
7381
)

0 commit comments

Comments
 (0)