vamp-cloud-enum 1.0__tar.gz → 1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vamp_cloud_enum-1.1/LICENSE +21 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/PKG-INFO +3 -1
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/pyproject.toml +1 -1
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.egg-info/PKG-INFO +3 -1
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.egg-info/SOURCES.txt +1 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.py +167 -3
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/README.md +0 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/setup.cfg +0 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.egg-info/dependency_links.txt +0 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.egg-info/entry_points.txt +0 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.egg-info/requires.txt +0 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vamp_cloud_enum.egg-info/top_level.txt +0 -0
- {vamp_cloud_enum-1.0 → vamp_cloud_enum-1.1}/vampsec_report.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VampSecure Studios
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vamp-cloud-enum
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1
|
|
4
4
|
Summary: Cloud asset enumeration and exposure analysis for authorized audits
|
|
5
5
|
Author-email: VampSecure Studios <contact@vampsecurestudios.com>
|
|
6
6
|
License: MIT
|
|
@@ -16,8 +16,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Topic :: Security
|
|
17
17
|
Requires-Python: >=3.9
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
19
20
|
Requires-Dist: aiohttp>=3.9.0
|
|
20
21
|
Requires-Dist: rich>=13.7.0
|
|
22
|
+
Dynamic: license-file
|
|
21
23
|
|
|
22
24
|
<p align="center">
|
|
23
25
|
<img src="https://img.shields.io/badge/version-1.0-crimson?style=flat-square" />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vamp-cloud-enum
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1
|
|
4
4
|
Summary: Cloud asset enumeration and exposure analysis for authorized audits
|
|
5
5
|
Author-email: VampSecure Studios <contact@vampsecurestudios.com>
|
|
6
6
|
License: MIT
|
|
@@ -16,8 +16,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Topic :: Security
|
|
17
17
|
Requires-Python: >=3.9
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
19
20
|
Requires-Dist: aiohttp>=3.9.0
|
|
20
21
|
Requires-Dist: rich>=13.7.0
|
|
22
|
+
Dynamic: license-file
|
|
21
23
|
|
|
22
24
|
<p align="center">
|
|
23
25
|
<img src="https://img.shields.io/badge/version-1.0-crimson?style=flat-square" />
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
vamp_cloud_enum.py — Enumerador de Buckets/Blobs Cloud Públicos
|
|
4
4
|
================================================================
|
|
5
5
|
VampSecure Labs · VampSecure Studios
|
|
6
|
-
Para Uso Exclusivo en Pruebas de Penetración Autorizadas — v1.
|
|
6
|
+
Para Uso Exclusivo en Pruebas de Penetración Autorizadas — v1.1
|
|
7
7
|
|
|
8
8
|
DESCRIPCIÓN GENERAL
|
|
9
9
|
-------------------
|
|
@@ -99,7 +99,7 @@ from vampsec_report import (
|
|
|
99
99
|
# CONSTANTES Y CONFIGURACIÓN
|
|
100
100
|
# =============================================================================
|
|
101
101
|
|
|
102
|
-
VERSION = "1.
|
|
102
|
+
VERSION = "1.1"
|
|
103
103
|
TOOL_NAME = "vamp-cloud-enum"
|
|
104
104
|
AUTHOR = "© VampSecure Studios — VampSecure Labs Security Research Division"
|
|
105
105
|
|
|
@@ -111,7 +111,7 @@ __ ___ __ __ ___ ___ ___ ___ _ _ ___ ___ _ _ ___ ___
|
|
|
111
111
|
\ V / _ \| |\/| | _/\__ \ _| (__| |_| | / _|| |__ / _ \| _ \__ \
|
|
112
112
|
\_/_/ \_\_| |_|_| |___/___\___|\___/|_|_\___|____/_/ \_\___/___/
|
|
113
113
|
by Antonio Hernandez "Belky" — VampSecure Studios
|
|
114
|
-
vamp-cloud-enum v1.
|
|
114
|
+
vamp-cloud-enum v1.1 · Cloud Bucket Enumerator
|
|
115
115
|
────────────────────────────────────────────────────────────────────────
|
|
116
116
|
USO EXCLUSIVO EN AUDITORÍAS AUTORIZADAS · El uso no autorizado es ilegal
|
|
117
117
|
"""
|
|
@@ -1428,6 +1428,15 @@ def parse_args() -> argparse.Namespace:
|
|
|
1428
1428
|
dest="html_out",
|
|
1429
1429
|
help="Guardar informe HTML dark-theme",
|
|
1430
1430
|
)
|
|
1431
|
+
p.add_argument(
|
|
1432
|
+
"--check-misconfigs",
|
|
1433
|
+
action="store_true",
|
|
1434
|
+
dest="check_misconfigs",
|
|
1435
|
+
help=(
|
|
1436
|
+
"Comprobar malas configuraciones en S3/Azure/GCS sin credenciales "
|
|
1437
|
+
"(acceso público, listado de contenedores) — v1.1"
|
|
1438
|
+
),
|
|
1439
|
+
)
|
|
1431
1440
|
|
|
1432
1441
|
add_report_args(p)
|
|
1433
1442
|
return p.parse_args()
|
|
@@ -1465,6 +1474,134 @@ def _load_wordlist(path: str) -> List[str]:
|
|
|
1465
1474
|
# FUNCIÓN PRINCIPAL
|
|
1466
1475
|
# =============================================================================
|
|
1467
1476
|
|
|
1477
|
+
# =============================================================================
|
|
1478
|
+
# COMPROBACIONES DE MALA CONFIGURACIÓN (v1.1) — urllib.request sin credenciales
|
|
1479
|
+
# =============================================================================
|
|
1480
|
+
|
|
1481
|
+
def _check_s3_public_access(
|
|
1482
|
+
bucket_names: List[str],
|
|
1483
|
+
findings: List[BucketResult],
|
|
1484
|
+
) -> None:
|
|
1485
|
+
"""
|
|
1486
|
+
Comprueba acceso público en buckets S3 sin credenciales (v1.1).
|
|
1487
|
+
|
|
1488
|
+
Realiza peticiones GET anónimas a las URLs canónicas de S3 y clasifica
|
|
1489
|
+
el resultado según la respuesta HTTP.
|
|
1490
|
+
|
|
1491
|
+
Severidad:
|
|
1492
|
+
CRITICAL — La respuesta contiene ListBucketResult (listado público)
|
|
1493
|
+
HIGH — Respuesta 200 OK sin listado (contenido accesible)
|
|
1494
|
+
INFO — 403/404 (bucket privado o inexistente)
|
|
1495
|
+
"""
|
|
1496
|
+
import urllib.request
|
|
1497
|
+
import urllib.error
|
|
1498
|
+
|
|
1499
|
+
for nombre in bucket_names:
|
|
1500
|
+
url_raiz = f"https://{nombre}.s3.amazonaws.com/"
|
|
1501
|
+
try:
|
|
1502
|
+
req = urllib.request.Request(
|
|
1503
|
+
url_raiz, headers={"User-Agent": f"VampSecureLabs/{VERSION}"}
|
|
1504
|
+
)
|
|
1505
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
1506
|
+
codigo = resp.status
|
|
1507
|
+
cuerpo = resp.read(512).decode("utf-8", errors="ignore")
|
|
1508
|
+
if "ListBucketResult" in cuerpo:
|
|
1509
|
+
findings.append(BucketResult(
|
|
1510
|
+
name=nombre, provider="s3", url=url_raiz,
|
|
1511
|
+
status="LISTING", http_code=codigo,
|
|
1512
|
+
headers={}, body_snippet=cuerpo[:200],
|
|
1513
|
+
severity="CRITICAL", finding_id="CLOUD-MC-S3-001",
|
|
1514
|
+
))
|
|
1515
|
+
else:
|
|
1516
|
+
findings.append(BucketResult(
|
|
1517
|
+
name=nombre, provider="s3", url=url_raiz,
|
|
1518
|
+
status="PUBLIC", http_code=codigo,
|
|
1519
|
+
headers={}, body_snippet=cuerpo[:200],
|
|
1520
|
+
severity="HIGH", finding_id="CLOUD-MC-S3-002",
|
|
1521
|
+
))
|
|
1522
|
+
except urllib.error.HTTPError as exc:
|
|
1523
|
+
if exc.code not in (403, 404):
|
|
1524
|
+
# Error inesperado; ignorar silenciosamente
|
|
1525
|
+
pass
|
|
1526
|
+
except Exception:
|
|
1527
|
+
# Error de red o DNS; ignorar
|
|
1528
|
+
pass
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
def _check_azure_blob_public(
|
|
1532
|
+
storage_accounts: List[str],
|
|
1533
|
+
findings: List[BucketResult],
|
|
1534
|
+
) -> None:
|
|
1535
|
+
"""
|
|
1536
|
+
Comprueba acceso público en cuentas Azure Blob Storage sin credenciales (v1.1).
|
|
1537
|
+
|
|
1538
|
+
Realiza peticiones GET anónimas a la API de listado de contenedores.
|
|
1539
|
+
|
|
1540
|
+
Severidad:
|
|
1541
|
+
HIGH — La respuesta XML contiene EnumerationResults (listado público)
|
|
1542
|
+
"""
|
|
1543
|
+
import urllib.request
|
|
1544
|
+
import urllib.error
|
|
1545
|
+
|
|
1546
|
+
for cuenta in storage_accounts:
|
|
1547
|
+
url = f"https://{cuenta}.blob.core.windows.net/?comp=list"
|
|
1548
|
+
try:
|
|
1549
|
+
req = urllib.request.Request(
|
|
1550
|
+
url, headers={"User-Agent": f"VampSecureLabs/{VERSION}"}
|
|
1551
|
+
)
|
|
1552
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
1553
|
+
codigo = resp.status
|
|
1554
|
+
cuerpo = resp.read(512).decode("utf-8", errors="ignore")
|
|
1555
|
+
if "EnumerationResults" in cuerpo:
|
|
1556
|
+
findings.append(BucketResult(
|
|
1557
|
+
name=cuenta, provider="azure", url=url,
|
|
1558
|
+
status="LISTING", http_code=codigo,
|
|
1559
|
+
headers={}, body_snippet=cuerpo[:200],
|
|
1560
|
+
severity="HIGH", finding_id="CLOUD-MC-AZ-001",
|
|
1561
|
+
))
|
|
1562
|
+
except urllib.error.HTTPError:
|
|
1563
|
+
pass # 403/404 esperado para cuentas privadas
|
|
1564
|
+
except Exception:
|
|
1565
|
+
pass # Error de red
|
|
1566
|
+
|
|
1567
|
+
|
|
1568
|
+
def _check_gcs_public(
|
|
1569
|
+
bucket_names: List[str],
|
|
1570
|
+
findings: List[BucketResult],
|
|
1571
|
+
) -> None:
|
|
1572
|
+
"""
|
|
1573
|
+
Comprueba acceso público en buckets GCS sin credenciales (v1.1).
|
|
1574
|
+
|
|
1575
|
+
Realiza peticiones GET anónimas a la API JSON de Cloud Storage.
|
|
1576
|
+
|
|
1577
|
+
Severidad:
|
|
1578
|
+
HIGH — La respuesta JSON 200 devuelve metadatos del bucket (acceso público)
|
|
1579
|
+
"""
|
|
1580
|
+
import urllib.request
|
|
1581
|
+
import urllib.error
|
|
1582
|
+
|
|
1583
|
+
for nombre in bucket_names:
|
|
1584
|
+
url = f"https://storage.googleapis.com/{nombre}?alt=json"
|
|
1585
|
+
try:
|
|
1586
|
+
req = urllib.request.Request(
|
|
1587
|
+
url, headers={"User-Agent": f"VampSecureLabs/{VERSION}"}
|
|
1588
|
+
)
|
|
1589
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
1590
|
+
codigo = resp.status
|
|
1591
|
+
cuerpo = resp.read(512).decode("utf-8", errors="ignore")
|
|
1592
|
+
if codigo == 200:
|
|
1593
|
+
findings.append(BucketResult(
|
|
1594
|
+
name=nombre, provider="gcp", url=url,
|
|
1595
|
+
status="PUBLIC", http_code=codigo,
|
|
1596
|
+
headers={}, body_snippet=cuerpo[:200],
|
|
1597
|
+
severity="HIGH", finding_id="CLOUD-MC-GCS-001",
|
|
1598
|
+
))
|
|
1599
|
+
except urllib.error.HTTPError:
|
|
1600
|
+
pass # 403/404 esperado para buckets privados
|
|
1601
|
+
except Exception:
|
|
1602
|
+
pass # Error de red
|
|
1603
|
+
|
|
1604
|
+
|
|
1468
1605
|
async def run(args: argparse.Namespace) -> int:
|
|
1469
1606
|
"""
|
|
1470
1607
|
Orquesta la enumeración completa de buckets cloud.
|
|
@@ -1538,6 +1675,33 @@ async def run(args: argparse.Namespace) -> int:
|
|
|
1538
1675
|
)
|
|
1539
1676
|
all_results.append(result)
|
|
1540
1677
|
|
|
1678
|
+
# ── Comprobaciones de mala configuración (v1.1) ───────────────────────────
|
|
1679
|
+
if getattr(args, "check_misconfigs", False) and args.domains:
|
|
1680
|
+
console.print("\n[bold cyan]Comprobando malas configuraciones cloud (sin credenciales)…[/]\n")
|
|
1681
|
+
misconfig_findings: List[BucketResult] = []
|
|
1682
|
+
# Generar nombres de bucket candidatos a partir de los dominios objetivo
|
|
1683
|
+
nombres_mc: List[str] = []
|
|
1684
|
+
for dominio in args.domains:
|
|
1685
|
+
norm = re.sub(r"[^a-z0-9\-]", "-", dominio.lower().strip())
|
|
1686
|
+
norm = re.sub(r"-+", "-", norm).strip("-")
|
|
1687
|
+
if norm:
|
|
1688
|
+
nombres_mc.append(norm)
|
|
1689
|
+
|
|
1690
|
+
if "s3" in providers:
|
|
1691
|
+
_check_s3_public_access(nombres_mc, misconfig_findings)
|
|
1692
|
+
if "azure" in providers:
|
|
1693
|
+
_check_azure_blob_public(nombres_mc, misconfig_findings)
|
|
1694
|
+
if "gcp" in providers:
|
|
1695
|
+
_check_gcs_public(nombres_mc, misconfig_findings)
|
|
1696
|
+
|
|
1697
|
+
if misconfig_findings:
|
|
1698
|
+
console.print(
|
|
1699
|
+
f" [yellow]Malas configuraciones detectadas:[/] {len(misconfig_findings)}"
|
|
1700
|
+
)
|
|
1701
|
+
found_all.extend(misconfig_findings)
|
|
1702
|
+
else:
|
|
1703
|
+
console.print(" [green]Sin malas configuraciones detectadas.[/]")
|
|
1704
|
+
|
|
1541
1705
|
# ── Salida en consola ─────────────────────────────────────────────────────
|
|
1542
1706
|
print_summary_table(found_all)
|
|
1543
1707
|
print_critical_panels(found_all)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|