Skip to content

Commit

Permalink
puncia[0.25]
Browse files Browse the repository at this point in the history
  • Loading branch information
g147 committed Nov 24, 2024
1 parent b75b159 commit 099117c
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 53 deletions.
72 changes: 47 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,86 @@
# The Panthera(P.)uncia of Cybersecurity
# The Panthera(P.)uncia of Cybersecurity

### Official CLI utility for Subdomain Center & Exploit Observer

[![Downloads](https://pepy.tech/badge/puncia)](https://pepy.tech/project/puncia)
<img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/ARPSyndicate/puncia">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/ARPSyndicate/puncia">
<br>
<img src="https://raw.githubusercontent.com/ARPSyndicate/puncia/master/puncia.png" width=25%>
<img src="https://raw.githubusercontent.com/ARPSyndicate/puncia/master/puncia.png" width=25%>
<br>
Puncia utilizes two of our intelligent APIs to gather the results - <br>
- [Subdomain Center - The World's Fastest Growing Subdomain & Shadow IT Intelligence Database](https://subdomain.center)<br>

- [Subdomain Center - The World's Largest Subdomain & Shadow IT Intelligence Database](https://subdomain.center)<br>
- [Exploit Observer - The World's Largest Exploit & Vulnerability Intelligence Database](https://exploit.observer)

**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.**

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

## Installation

1. From PyPi - `pip3 install puncia`
2. From Source - `pip3 install .`<br>

## Usage
1. Store an API key (storekey) - `puncia storekey <api-key>`
2. Query Domains (subdomain) - `puncia subdomain <domain> <output-file>`
3. Query Exploit & Vulnerability Identifiers (exploit)

1. Store an API key (storekey) - `puncia storekey <api-key>`
2. Query Domains (subdomain) - `puncia subdomain <domain> <output-file>`
3. Query Exploit & Vulnerability Identifiers (exploit)
- Russian VIDs with no associated CVEs (^RU_NON_CVE) - `puncia exploit ^RU_NON_CVE <output-file>`
- Chinese VIDs with no associated CVEs (^CN_NON_CVE) - `puncia exploit ^CN_NON_CVE <output-file>`
- Vulnerability & Exploit Identifers Watchlist (^WATCHLIST_IDES) - `puncia exploit ^WATCHLIST_IDES <output-file>`
- Vulnerable Technologies Watchlist (^WATCHLIST_TECH) - `puncia exploit ^WATCHLIST_TECH <output-file>`
- [Supported Vulnerability Identifiers](https://github.com/ARPSyndicate/docs?tab=readme-ov-file#supported-vulnerability-identifiers) - `puncia exploit <eoidentifier> <output-file>`
4. Enrich CVE/GHSA Identifiers (enrich) - `puncia enrich <cve-id/ghsa-id> <output-file>`
5. Multiple Queries (bulk/sbom)
4. Enrich CVE/GHSA Identifiers (enrich) - `puncia enrich <cve-id/ghsa-id> <output-file>`
5. Multiple Queries (bulk/sbom)

- Bulk Input JSON File Format - `puncia bulk <json-file> <output-directory>`
```
{
"subdomain": [
"domainA.com",
"domainB.com"
],
"exploit": [
"eoidentifierA",
"eoidentifierB"
],
"enrich": [
"eoidentifierA",
"eoidentifierB"
]
}
```
```
{
"subdomain": [
"domainA.com",
"domainB.com"
],
"exploit": [
"eoidentifierA",
"eoidentifierB"
],
"enrich": [
"eoidentifierA",
"eoidentifierB"
]
}
```
- [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>`
6. External Import
```
import puncia
# Without API Key
print(puncia.query_api("exploit","CVE-2021-3450"))
print(puncia.query_api("subdomain","arpsyndicate.io"))
# With API Key
puncia.store_key("ARPS-xxxxxxxxxx")
print(puncia.query_api("subdomain","arpsyndicate.io", apikey=puncia.read_key()))
print(puncia.query_api("exploit","CVE-2021-3450", apikey=puncia.read_key()))
```
<br>
## Noteworthy Mentions
- [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)
- [Utilizing GitHub Actions for gathering Subdomain & Exploit Intelligence](https://blog.arpsyndicate.io/utilizing-github-actions-for-gathering-subdomain-exploit-intelligence-bbc79c19bb85)
- [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)
- [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)
- [Subdomain Enumeration Tool Face-off - 2023 Edition](https://blog.blacklanternsecurity.com/p/subdomain-enumeration-tool-face-off-4e5)
## More from [A.R.P. Syndicate](https://www.arpsyndicate.io)
- [Open Source Intelligence](https://asm.arpsyndicate.io/intelligence.html)
- [Attack Surface Management](https://asm.arpsyndicate.io)
- [Vulnerability Advisories AI](https://advisories.arpsyndicate.io)
3 changes: 3 additions & 0 deletions puncia/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .__main__ import query_api, store_key, read_key

__all__ = ["query_api", "store_key", "read_key"]
67 changes: 40 additions & 27 deletions puncia/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,16 @@ def read_key():
try:
home = os.path.expanduser("~")
with open(home + "/.puncia", "r") as f:
key = f.read()
return key
except:
pass
return ""
return f.read().strip()
except FileNotFoundError:
return ""


def query_api(mode, query, output_file=None, cid=None, akey=""):
if len(akey) > 0 and mode in ["exploit", "subdomain", "enrich"]:
url = API_URLS.get("auth_" + mode).format(akey)
def query_api(mode, query, output_file=None, cid=None, apikey=""):
if len(apikey) > 0 and mode in ["exploit", "subdomain", "enrich"]:
url = API_URLS.get("auth_" + mode).format(apikey)
else:
time.sleep(60)
time.sleep(25)
url = API_URLS.get(mode)
if "^" in query and "exploit" in mode:
if query == "^RU_NON_CVE":
Expand All @@ -65,16 +63,21 @@ def query_api(mode, query, output_file=None, cid=None, akey=""):
cid = "Vulnerable Technologies Watchlist"
if not url:
sys.exit("Invalid Mode")
try:
response = requests.get(url + query).json()
except:
print("An exception happened while requesting: " + query)
return
retries = 3
counter = 0
response = {}
while counter <= retries:
try:
response = requests.get(url + query).json()
if len(response) > 0:
break
except:
print("An exception happened while requesting: " + query)
counter = counter + 1
time.sleep(60)
if not response or len(response) == 0:
print("Null response from the API")
print("Null response from the API for: " + query)
return
result = json.dumps(response, indent=4, sort_keys=True)
print(result)
if mode in ["spec_exploit"]:
os.system("rm " + output_file)
for reurl in response:
Expand All @@ -83,7 +86,7 @@ def query_api(mode, query, output_file=None, cid=None, akey=""):
reurl,
output_file,
cid,
akey,
apikey,
)
return
if output_file:
Expand Down Expand Up @@ -147,6 +150,8 @@ def query_api(mode, query, output_file=None, cid=None, akey=""):

with open(output_file, "w") as f:
json.dump(existing_data, f, indent=4, sort_keys=True)
return existing_data
return response


def sbom_process(sbom):
Expand All @@ -167,7 +172,7 @@ def add_component(name, version):
def main():
try:
print("---------")
print("Panthera(P.)uncia [v0.24]")
print("Panthera(P.)uncia [v0.25]")
print("A.R.P. Syndicate [https://www.arpsyndicate.io]")
print("---------")

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

if (
mode not in API_URLS
Expand Down Expand Up @@ -207,35 +212,41 @@ def main():
if "subdomain" in input_file:
for bulk_query in input_file["subdomain"]:
try:
query_api(
rdata = query_api(
"subdomain",
bulk_query,
output_file + "/subdomain/" + bulk_query + ".json",
akey=akey,
apikey=apikey,
)
if len(rdata) > 0:
print(json.dumps(rdata, indent=4, sort_keys=True))
except Exception as ne:
sys.exit(f"Error: {str(ne)}")
continue
if "exploit" in input_file:
for bulk_query in input_file["exploit"]:
try:
query_api(
rdata = query_api(
"exploit",
bulk_query,
output_file + "/exploit/" + bulk_query + ".json",
akey=akey,
apikey=apikey,
)
if len(rdata) > 0:
print(json.dumps(rdata, indent=4, sort_keys=True))
except Exception as ne:
sys.exit(f"Error: {str(ne)}")
if "enrich" in input_file:
for bulk_query in input_file["enrich"]:
try:
query_api(
rdata = query_api(
"enrich",
bulk_query,
output_file + "/enrich/" + bulk_query + ".json",
akey=akey,
apikey=apikey,
)
if len(rdata) > 0:
print(json.dumps(rdata, indent=4, sort_keys=True))
except Exception as ne:
sys.exit(f"Error: {str(ne)}")

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

else:
query_api(mode, query, output_file, akey=akey)
rdata = query_api(mode, query, output_file, apikey=apikey)
if len(rdata) > 0:
print(json.dumps(rdata, indent=4, sort_keys=True))
except Exception as e:
sys.exit(f"Error: {str(e)}")

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="puncia",
version="0.24",
version="0.25",
author="A.R.P. Syndicate",
author_email="[email protected]",
keywords="subdomains subdomain exploits exploit sbom cyclonedx arpsyndicate panthera uncia puncia snow leopard",
Expand Down

0 comments on commit 099117c

Please sign in to comment.