Skip to content

Commit 099117c

Browse files
committed
puncia[0.25]
1 parent b75b159 commit 099117c

File tree

4 files changed

+91
-53
lines changed

4 files changed

+91
-53
lines changed

README.md

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,86 @@
1-
# The Panthera(P.)uncia of Cybersecurity
1+
# The Panthera(P.)uncia of Cybersecurity
2+
23
### Official CLI utility for Subdomain Center & Exploit Observer
34

45
[![Downloads](https://pepy.tech/badge/puncia)](https://pepy.tech/project/puncia)
56
<img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat">
6-
<img alt="GitHub stars" src="https://img.shields.io/github/stars/ARPSyndicate/puncia">
7+
<img alt="GitHub stars" src="https://img.shields.io/github/stars/ARPSyndicate/puncia">
78
<br>
8-
<img src="https://raw.githubusercontent.com/ARPSyndicate/puncia/master/puncia.png" width=25%>
9+
<img src="https://raw.githubusercontent.com/ARPSyndicate/puncia/master/puncia.png" width=25%>
910
<br>
1011
Puncia utilizes two of our intelligent APIs to gather the results - <br>
11-
- [Subdomain Center - The World's Fastest Growing Subdomain & Shadow IT Intelligence Database](https://subdomain.center)<br>
12+
13+
- [Subdomain Center - The World's Largest Subdomain & Shadow IT Intelligence Database](https://subdomain.center)<br>
1214
- [Exploit Observer - The World's Largest Exploit & Vulnerability Intelligence Database](https://exploit.observer)
1315

1416
**Please note that although these results can sometimes be pretty inaccurate & unreliable, they can greatly differ from time to time due to their self-improvement capabilities.**
1517

1618
**Aggressive rate-limits can be avoided with an API key: https://www.arpsyndicate.io/pricing.html**
1719

1820
## Installation
21+
1922
1. From PyPi - `pip3 install puncia`
2023
2. From Source - `pip3 install .`<br>
2124

2225
## Usage
23-
1. Store an API key (storekey) - `puncia storekey <api-key>`
24-
2. Query Domains (subdomain) - `puncia subdomain <domain> <output-file>`
25-
3. Query Exploit & Vulnerability Identifiers (exploit)
26+
27+
1. Store an API key (storekey) - `puncia storekey <api-key>`
28+
2. Query Domains (subdomain) - `puncia subdomain <domain> <output-file>`
29+
3. Query Exploit & Vulnerability Identifiers (exploit)
2630
- Russian VIDs with no associated CVEs (^RU_NON_CVE) - `puncia exploit ^RU_NON_CVE <output-file>`
2731
- Chinese VIDs with no associated CVEs (^CN_NON_CVE) - `puncia exploit ^CN_NON_CVE <output-file>`
2832
- Vulnerability & Exploit Identifers Watchlist (^WATCHLIST_IDES) - `puncia exploit ^WATCHLIST_IDES <output-file>`
2933
- Vulnerable Technologies Watchlist (^WATCHLIST_TECH) - `puncia exploit ^WATCHLIST_TECH <output-file>`
3034
- [Supported Vulnerability Identifiers](https://github.com/ARPSyndicate/docs?tab=readme-ov-file#supported-vulnerability-identifiers) - `puncia exploit <eoidentifier> <output-file>`
31-
4. Enrich CVE/GHSA Identifiers (enrich) - `puncia enrich <cve-id/ghsa-id> <output-file>`
32-
5. Multiple Queries (bulk/sbom)
35+
4. Enrich CVE/GHSA Identifiers (enrich) - `puncia enrich <cve-id/ghsa-id> <output-file>`
36+
5. Multiple Queries (bulk/sbom)
37+
3338
- Bulk Input JSON File Format - `puncia bulk <json-file> <output-directory>`
34-
```
35-
{
36-
"subdomain": [
37-
"domainA.com",
38-
"domainB.com"
39-
],
40-
"exploit": [
41-
"eoidentifierA",
42-
"eoidentifierB"
43-
],
44-
"enrich": [
45-
"eoidentifierA",
46-
"eoidentifierB"
47-
]
48-
}
49-
```
39+
```
40+
{
41+
"subdomain": [
42+
"domainA.com",
43+
"domainB.com"
44+
],
45+
"exploit": [
46+
"eoidentifierA",
47+
"eoidentifierB"
48+
],
49+
"enrich": [
50+
"eoidentifierA",
51+
"eoidentifierB"
52+
]
53+
}
54+
```
5055
- [SBOM Input JSON File Format](https://github.com/CycloneDX/bom-examples/blob/master/SBOM/protonmail-webclient-v4-0912dff/bom.json) - `puncia sbom <json-file> <output-directory>`
56+
57+
6. External Import
58+
```
59+
import puncia
60+
61+
# Without API Key
62+
print(puncia.query_api("exploit","CVE-2021-3450"))
63+
print(puncia.query_api("subdomain","arpsyndicate.io"))
64+
65+
# With API Key
66+
puncia.store_key("ARPS-xxxxxxxxxx")
67+
print(puncia.query_api("subdomain","arpsyndicate.io", apikey=puncia.read_key()))
68+
print(puncia.query_api("exploit","CVE-2021-3450", apikey=puncia.read_key()))
5169
70+
```
71+
5272
<br>
5373
5474
## Noteworthy Mentions
75+
5576
- [Around 1000 exploitable cybersecurity vulnerabilities that MITRE & NIST ‘might’ have missed but China or Russia didn’t.](https://blog.arpsyndicate.io/over-a-1000-vulnerabilities-that-mitre-nist-might-have-missed-but-china-or-russia-did-not-871b2364a526)
5677
- [Utilizing GitHub Actions for gathering Subdomain & Exploit Intelligence](https://blog.arpsyndicate.io/utilizing-github-actions-for-gathering-subdomain-exploit-intelligence-bbc79c19bb85)
5778
- [Introducing Exploit Observer — More than Shodan Exploits, Less than Vulners](https://blog.arpsyndicate.io/introducing-exploit-observer-more-than-shodan-exploits-less-than-vulners-23eaea466e4a)
5879
- [PUNCIA — The Panthera(P.)uncia of Cybersecurity](https://blog.arpsyndicate.io/puncia-the-panthera-p-uncia-of-cybersecurity-ft-puncia-subdomain-center-exploit-observer-9a9d8cca9576)
5980
- [Subdomain Enumeration Tool Face-off - 2023 Edition](https://blog.blacklanternsecurity.com/p/subdomain-enumeration-tool-face-off-4e5)
6081
6182
## More from [A.R.P. Syndicate](https://www.arpsyndicate.io)
83+
6284
- [Open Source Intelligence](https://asm.arpsyndicate.io/intelligence.html)
6385
- [Attack Surface Management](https://asm.arpsyndicate.io)
6486
- [Vulnerability Advisories AI](https://advisories.arpsyndicate.io)

puncia/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .__main__ import query_api, store_key, read_key
2+
3+
__all__ = ["query_api", "store_key", "read_key"]

puncia/__main__.py

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,16 @@ def read_key():
2929
try:
3030
home = os.path.expanduser("~")
3131
with open(home + "/.puncia", "r") as f:
32-
key = f.read()
33-
return key
34-
except:
35-
pass
36-
return ""
32+
return f.read().strip()
33+
except FileNotFoundError:
34+
return ""
3735

3836

39-
def query_api(mode, query, output_file=None, cid=None, akey=""):
40-
if len(akey) > 0 and mode in ["exploit", "subdomain", "enrich"]:
41-
url = API_URLS.get("auth_" + mode).format(akey)
37+
def query_api(mode, query, output_file=None, cid=None, apikey=""):
38+
if len(apikey) > 0 and mode in ["exploit", "subdomain", "enrich"]:
39+
url = API_URLS.get("auth_" + mode).format(apikey)
4240
else:
43-
time.sleep(60)
41+
time.sleep(25)
4442
url = API_URLS.get(mode)
4543
if "^" in query and "exploit" in mode:
4644
if query == "^RU_NON_CVE":
@@ -65,16 +63,21 @@ def query_api(mode, query, output_file=None, cid=None, akey=""):
6563
cid = "Vulnerable Technologies Watchlist"
6664
if not url:
6765
sys.exit("Invalid Mode")
68-
try:
69-
response = requests.get(url + query).json()
70-
except:
71-
print("An exception happened while requesting: " + query)
72-
return
66+
retries = 3
67+
counter = 0
68+
response = {}
69+
while counter <= retries:
70+
try:
71+
response = requests.get(url + query).json()
72+
if len(response) > 0:
73+
break
74+
except:
75+
print("An exception happened while requesting: " + query)
76+
counter = counter + 1
77+
time.sleep(60)
7378
if not response or len(response) == 0:
74-
print("Null response from the API")
79+
print("Null response from the API for: " + query)
7580
return
76-
result = json.dumps(response, indent=4, sort_keys=True)
77-
print(result)
7881
if mode in ["spec_exploit"]:
7982
os.system("rm " + output_file)
8083
for reurl in response:
@@ -83,7 +86,7 @@ def query_api(mode, query, output_file=None, cid=None, akey=""):
8386
reurl,
8487
output_file,
8588
cid,
86-
akey,
89+
apikey,
8790
)
8891
return
8992
if output_file:
@@ -147,6 +150,8 @@ def query_api(mode, query, output_file=None, cid=None, akey=""):
147150

148151
with open(output_file, "w") as f:
149152
json.dump(existing_data, f, indent=4, sort_keys=True)
153+
return existing_data
154+
return response
150155

151156

152157
def sbom_process(sbom):
@@ -167,7 +172,7 @@ def add_component(name, version):
167172
def main():
168173
try:
169174
print("---------")
170-
print("Panthera(P.)uncia [v0.24]")
175+
print("Panthera(P.)uncia [v0.25]")
171176
print("A.R.P. Syndicate [https://www.arpsyndicate.io]")
172177
print("---------")
173178

@@ -179,7 +184,7 @@ def main():
179184
mode = sys.argv[1]
180185
query = sys.argv[2]
181186
output_file = sys.argv[3] if len(sys.argv) == 4 else None
182-
akey = read_key()
187+
apikey = read_key()
183188

184189
if (
185190
mode not in API_URLS
@@ -207,35 +212,41 @@ def main():
207212
if "subdomain" in input_file:
208213
for bulk_query in input_file["subdomain"]:
209214
try:
210-
query_api(
215+
rdata = query_api(
211216
"subdomain",
212217
bulk_query,
213218
output_file + "/subdomain/" + bulk_query + ".json",
214-
akey=akey,
219+
apikey=apikey,
215220
)
221+
if len(rdata) > 0:
222+
print(json.dumps(rdata, indent=4, sort_keys=True))
216223
except Exception as ne:
217224
sys.exit(f"Error: {str(ne)}")
218225
continue
219226
if "exploit" in input_file:
220227
for bulk_query in input_file["exploit"]:
221228
try:
222-
query_api(
229+
rdata = query_api(
223230
"exploit",
224231
bulk_query,
225232
output_file + "/exploit/" + bulk_query + ".json",
226-
akey=akey,
233+
apikey=apikey,
227234
)
235+
if len(rdata) > 0:
236+
print(json.dumps(rdata, indent=4, sort_keys=True))
228237
except Exception as ne:
229238
sys.exit(f"Error: {str(ne)}")
230239
if "enrich" in input_file:
231240
for bulk_query in input_file["enrich"]:
232241
try:
233-
query_api(
242+
rdata = query_api(
234243
"enrich",
235244
bulk_query,
236245
output_file + "/enrich/" + bulk_query + ".json",
237-
akey=akey,
246+
apikey=apikey,
238247
)
248+
if len(rdata) > 0:
249+
print(json.dumps(rdata, indent=4, sort_keys=True))
239250
except Exception as ne:
240251
sys.exit(f"Error: {str(ne)}")
241252

@@ -244,7 +255,9 @@ def main():
244255
print("Successful!")
245256

246257
else:
247-
query_api(mode, query, output_file, akey=akey)
258+
rdata = query_api(mode, query, output_file, apikey=apikey)
259+
if len(rdata) > 0:
260+
print(json.dumps(rdata, indent=4, sort_keys=True))
248261
except Exception as e:
249262
sys.exit(f"Error: {str(e)}")
250263

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name="puncia",
5-
version="0.24",
5+
version="0.25",
66
author="A.R.P. Syndicate",
77
author_email="ayush@arpsyndicate.io",
88
keywords="subdomains subdomain exploits exploit sbom cyclonedx arpsyndicate panthera uncia puncia snow leopard",

0 commit comments

Comments
 (0)