diff --git a/Changelog.md b/Changelog.md
@@ -1,3 +1,8 @@
+## v0.0.4
+
+- feat(scan): saving wappalyzer results to file ~ @djnnvx
+- feat(scan): adding cvemap module ~ @djnnvx
+
## v0.0.3
- feat: bumping gobuster to latest version (unstable) ~ @djnnvx
diff --git a/README.md b/README.md
@@ -9,7 +9,7 @@
-------- ⠀⠀⢸⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⣙⢿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠻⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀
djnn.sh⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⢹⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀
- ⠀v0.0.3 ⠀⠀⢠⣿⣿⣿⣿⡟⠹⠿⠟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀
+ ⠀v0.0.4 ⠀⠀⢠⣿⣿⣿⣿⡟⠹⠿⠟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡿⠋⡬⢿⣿⣷⣤⣤⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡇⢸⡇⢸⣿⣿⣿⠟⠁⢀⣬⢽⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣧⣈⣛⣿⣿⣿⡇⠀⠀⣾⠁⢀⢻⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀
@@ -44,11 +44,16 @@ Please use at your own risk, in a controlled environnement. Thanks<3
For next version, i want to take care of at least two items described here:
-* `scan`: integrate browser-dependant tools (katana, ...),
-* `scan`: integrate a runner for nuclei that will automatically fetch new rules,
-* `scan`: port third-party tools (smbenum, ldapsearch, enum4linux),
-* `scan`: add a CVE query system
-* `scan`: port some quick win, such as anonymous ftp
+* `scan`: add toolbox scan script to automatically integrate it with
+ nmap and other CLI tools
+* `scan`: integrate browser-dependant tools (katana, ...) (still TBD),
+
+* `osint`: add support for more dorks
+* `osint`: shodan API integration
+
+### Bugfixes
+
+* `sitemap` should be stored to a file & fetch robots.txt
> feel free to suggest more ideas. :)~
>
@@ -57,8 +62,8 @@ For next version, i want to take care of at least two items described here:
### Contributing
This software's code is public, but not open to contributions.
-The reason for that is that if something is integrated, I want to make sure I am able to maintain it
-afterwards.
+The reason for that is that if something is integrated, I want to make sure I
+am able to maintain it afterwards.
## Installing
@@ -128,6 +133,19 @@ Run scans against the target actively.
```bash
./yellow scan --help
-# or, if in a hurry
-./yellow scan -d djnn.sh/scans --file djnn.sh/scans/domains.txt
+# run scan on ports 80, 443, 8080 & 8443
+nmap -T4 -Pn -p 80,443,8080,8443 --open -oA domains -iL djnn.sh/scans/domains.txt
+cat *.gnmap | grep -i "open/tcp" | cut -d " " -f2 | sort -u > djnn.sh/scans/web-targets.txt
+
+# you can also just run the domains.txt file directly
+
+./yellow scan -d djnn.sh/scans/infra --file djnn.sh/scans/web-targets.txt
```
+
+#### Retrieving CVEs automatically
+
+We use [vulnx](https://github.com/projectdiscovery/cvemap/tree/main) under the hood to query CVEs based on
+initial fingerprinting. To get this feature working, you will need to create an account
+on [ProjectDiscovery](https://cloud.projectdiscovery.io/) and retrieve an API key.
+
+Then you should set this key in your `.bashrc` or equivalent to `VULNX_API_KEY`.
diff --git a/go.mod b/go.mod
@@ -5,6 +5,7 @@ go 1.25
require (
github.com/OJ/gobuster/v3 v3.8.2
github.com/bogdzn/gork v0.0.5
+ github.com/projectdiscovery/cvemap v1.0.0
github.com/projectdiscovery/dnsx v1.2.2
github.com/projectdiscovery/goflags v0.1.74
github.com/projectdiscovery/httpx v1.7.1
@@ -15,7 +16,7 @@ require (
)
require (
- aead.dev/minisign v0.2.0 // indirect
+ aead.dev/minisign v0.2.1 // indirect
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect
@@ -39,7 +40,7 @@ require (
github.com/charmbracelet/glamour v0.8.0 // indirect
github.com/charmbracelet/lipgloss v0.13.0 // indirect
github.com/charmbracelet/x/ansi v0.3.2 // indirect
- github.com/cheggaaa/pb/v3 v3.1.4 // indirect
+ github.com/cheggaaa/pb/v3 v3.1.5 // indirect
github.com/cloudflare/cfssl v1.6.4 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a // indirect
@@ -50,6 +51,7 @@ require (
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
+ github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/gaissmai/bart v0.25.0 // indirect
github.com/go-faker/faker/v4 v4.6.1 // indirect
@@ -76,6 +78,7 @@ require (
github.com/hdm/jarm-go v0.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
+ github.com/jedib0t/go-pretty/v6 v6.6.7 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kataras/jwt v0.1.10 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
diff --git a/go.sum b/go.sum
@@ -1,5 +1,6 @@
-aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
+aead.dev/minisign v0.2.1 h1:Z+7HA9dsY/eGycYj6kpWHpcJpHtjAwGiJFvbiuO9o+M=
+aead.dev/minisign v0.2.1/go.mod h1:oCOjeA8VQNEbuSCFaaUXKekOusa/mll6WtMoO5JY4M4=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -68,8 +69,8 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
-github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY=
-github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs=
+github.com/bits-and-blooms/bloom/v3 v3.6.0 h1:dTU0OVLJSoOhz9m68FTXMFfA39nR8U/nTCs1zb26mOI=
+github.com/bits-and-blooms/bloom/v3 v3.6.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
@@ -88,8 +89,8 @@ github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyf
github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30=
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
-github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
-github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA=
+github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk=
+github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -121,6 +122,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
+github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg=
+github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
@@ -230,6 +233,8 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/jawher/mow.cli v1.1.0/go.mod h1:aNaQlc7ozF3vw6IJ2dHjp2ZFiA4ozMIYY6PyuRJwlUg=
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
+github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=
+github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@@ -330,6 +335,8 @@ github.com/projectdiscovery/chaos-client v0.5.2 h1:dN+7GXEypsJAbCD//dBcUxzAEAEH1
github.com/projectdiscovery/chaos-client v0.5.2/go.mod h1:KnoJ/NJPhll42uaqlDga6oafFfNw5l2XI2ajRijtDuU=
github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE=
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
+github.com/projectdiscovery/cvemap v1.0.0 h1:0PVbaWozUNM4oislukPdeKrmeQKbdGwhWGpRNBQ5tpg=
+github.com/projectdiscovery/cvemap v1.0.0/go.mod h1:QQ/tnIoUewT+l9h5yaJyEgwmKEPjjY+0de/RJOGyDis=
github.com/projectdiscovery/dnsx v1.2.2 h1:ZjUov0GOyrS8ERlKAAhk+AOkqzaYHBzCP0qZfO+6Ihg=
github.com/projectdiscovery/dnsx v1.2.2/go.mod h1:3iYm86OEqo0WxeGDkVl5WZNmG0qYE5TYNx8fBg6wX1I=
github.com/projectdiscovery/dsl v0.5.0 h1:3HHY14FNmdwWXq3pi9dd8JjUHQzskZjLD/pZKVx5Vi4=
diff --git a/main.go b/main.go
@@ -13,7 +13,7 @@ const ASCII_ART = `
-------- ⠀⠀⢸⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⣙⢿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠻⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀
djnn.sh⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⢹⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀
- ⠀v0.0.3 ⠀⠀⢠⣿⣿⣿⣿⡟⠹⠿⠟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀
+ ⠀v0.0.4 ⠀⠀⢠⣿⣿⣿⣿⡟⠹⠿⠟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡿⠋⡬⢿⣿⣷⣤⣤⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡇⢸⡇⢸⣿⣿⣿⠟⠁⢀⣬⢽⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣧⣈⣛⣿⣿⣿⡇⠀⠀⣾⠁⢀⢻⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀
diff --git a/quick-run.sh b/quick-run.sh
@@ -9,4 +9,4 @@ set -euo
./yellow osint -d ${1}
-./yellow scan -d ${1}/scans --file ${1}/scans/domains.txt
+./yellow scan -d ${1}/scans/infra --file ${1}/scans/domains.txt
diff --git a/scan/cvemap.go b/scan/cvemap.go
@@ -0,0 +1,119 @@
+package scan
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/projectdiscovery/cvemap/pkg/runner"
+ "github.com/projectdiscovery/cvemap/pkg/types"
+)
+
+type Cvemap struct {
+ HTTPProxy string
+ scanPath string
+ Limit int
+ Offset int
+ Verbose bool
+ Debug bool
+}
+
+func (c *Cvemap) Info(target string) {
+ fmt.Println("[+] Running cvemap for", target)
+}
+
+func (c *Cvemap) Configure(cfg any) {
+ if cfg == nil {
+ return
+ }
+ m := cfg.(map[string]any)
+
+ if v, ok := m["Proxy"].(string); ok {
+ c.HTTPProxy = v
+ }
+ if v, ok := m["Limit"].(int); ok {
+ c.Limit = v
+ }
+ if v, ok := m["Offset"].(int); ok {
+ c.Offset = v
+ }
+ if v, ok := m["Verbose"].(bool); ok {
+ c.Verbose = v
+ }
+ if v, ok := m["Debug"].(bool); ok {
+ c.Debug = v
+ }
+ if v, ok := m["ScanPath"].(string); ok {
+ c.scanPath = v
+ }
+}
+
+func (c *Cvemap) Run(techs []string) {
+ runner.PDCPApiKey = os.Getenv("VULNX_API_KEY")
+ if runner.PDCPApiKey == "" {
+ println("[!] Automatic CVE research requires VULNX_API_KEY to be set in env...skipping")
+ return
+ }
+
+ options := runner.Options{
+ HTTPProxy: c.HTTPProxy,
+ Limit: c.Limit,
+ Offset: c.Offset,
+ Verbose: c.Verbose,
+ Debug: c.Debug,
+ }
+
+ rn, err := runner.New(&options)
+ if err != nil {
+ panic(err)
+ }
+
+ if len(techs) == 0 {
+ fmt.Println("[+] no technologies provided")
+ return
+ }
+
+ for _, tech := range techs {
+ tech = strings.TrimSpace(tech)
+ if tech == "" {
+ continue
+ }
+
+ c.Info(tech)
+
+ rn.Options.Search = tech
+
+ cvesResp, err := rn.GetCves()
+ if err != nil {
+ fmt.Printf("[ERROR] query for '%s' failed: %v\n", tech, err)
+ continue
+ }
+ if cvesResp == nil {
+ fmt.Printf("[SCAN %s] no results\n\n", tech)
+ continue
+ }
+
+ total := 0
+ if cvesResp.TotalResults > 0 {
+ total = cvesResp.TotalResults
+ } else if cvesResp.Cves != nil {
+ total = len(cvesResp.Cves)
+ }
+
+ c.saveResults(cvesResp.Cves)
+ fmt.Printf("[SCAN %s] total results: %d (returned: %d)\n\n", tech, total, len(cvesResp.Cves))
+ }
+}
+
+func (c *Cvemap) saveResults(names []types.CVEData) {
+ data, err := json.MarshalIndent(names, "", "\t")
+ if err != nil {
+ return
+ }
+
+ filename := c.scanPath + "/cves.json"
+ if err := os.WriteFile(filename, data, 0644); err != nil {
+ panic(err)
+ }
+}
diff --git a/scan/run.go b/scan/run.go
@@ -1,8 +1,10 @@
package scan
import (
- "evil.djnn.sh/djnn/yellow/helpers"
"fmt"
+ "os"
+
+ "evil.djnn.sh/djnn/yellow/helpers"
)
type ScanOpts struct {
@@ -15,6 +17,15 @@ type ScanOpts struct {
forceInsecure bool
}
+/*
+ save in shared memory to avoid having to read a write from files
+
+all the time
+*/
+var (
+ wappalyzerResults []string
+)
+
func (opts *ScanOpts) SetForceInsecure(data bool) {
opts.forceInsecure = data
}
@@ -58,16 +69,33 @@ func (opts ScanOpts) runRobots() {
}
func (opts ScanOpts) runWappalyzerGo() {
+ wappalyzerResults = make([]string, 0)
wp := WappalyzerGo{}
wpCfg := make(map[string]any)
wpCfg["Proxy"] = opts.proxy
+ wpCfg["ScanPath"] = opts.scanPath
wp.Configure(wpCfg)
wp.Info(opts.domain)
if !opts.dryRun {
- wp.Run(opts.domain)
+ wappalyzerResults = wp.Run(opts.domain)
+ }
+}
+
+func (opts ScanOpts) runCvemap() {
+ cv := Cvemap{}
+ cvCfg := make(map[string]any)
+
+ cvCfg["Proxy"] = opts.proxy
+ cvCfg["ScanPath"] = opts.scanPath
+ cv.Configure(cvCfg)
+ cv.Info(opts.domain)
+
+ if !opts.dryRun {
+ cv.Run(wappalyzerResults)
+ wappalyzerResults = make([]string, 0)
}
}
@@ -89,7 +117,7 @@ func (opts *ScanOpts) runHttpx() {
httpx := Httpx{}
httpxCfg := make(map[string]any)
- httpxOutdir := fmt.Sprintf("%s/infra/httpx", opts.scanPath)
+ httpxOutdir := fmt.Sprintf("%s/httpx", opts.scanPath)
httpxCfg["OutDirPath"] = httpxOutdir
httpxCfg["Proxy"] = opts.proxy
@@ -125,22 +153,33 @@ func (opts ScanOpts) runGobusterDir() {
func (opts *ScanOpts) Run() {
fmt.Printf("\n[SCAN] domain: %s\n", opts.domain)
+ fullDomain := "https://" + opts.domain
if opts.forceInsecure {
- opts.SetDomain("http://" + opts.domain)
- } else {
- opts.SetDomain("https://" + opts.domain)
+ fullDomain = "http://" + opts.domain
}
- if !helper.HasUnavailableWebInterface(opts.domain) {
+ if !helper.HasUnavailableWebInterface(fullDomain) {
+ initialPath := opts.scanPath
fmt.Printf("[SCAN %s] web panel online....running web scans\n", opts.domain)
+ pathForDomain := opts.scanPath + "/" + opts.domain
+ opts.SetScanPath(pathForDomain)
+ err := os.MkdirAll(opts.scanPath, 0755)
+ if err != nil {
+ panic(err)
+ }
+
+ opts.SetDomain(fullDomain)
+
opts.runSitemap()
opts.runRobots()
opts.runWappalyzerGo()
+ opts.runCvemap()
opts.runHttpx()
opts.runGobusterDir()
+ opts.SetScanPath(initialPath)
} else {
fmt.Printf("[SCAN %s] => no web panel online. skipping\n", opts.domain)
}
diff --git a/scan/wappalyzergo.go b/scan/wappalyzergo.go
@@ -2,16 +2,21 @@ package scan
import (
"crypto/tls"
+ "encoding/json"
"fmt"
"io"
"net/http"
+ "os"
+ "reflect"
+ "sort"
- "evil.djnn.sh/djnn/yellow/helpers"
+ helper "evil.djnn.sh/djnn/yellow/helpers"
wappalyzer "github.com/projectdiscovery/wappalyzergo"
)
type WappalyzerGo struct {
- Proxy string
+ Proxy string
+ ScanPath string
}
func (d *WappalyzerGo) Info(url string) {
@@ -20,35 +25,127 @@ func (d *WappalyzerGo) Info(url string) {
func (d *WappalyzerGo) Configure(c any) {
d.Proxy = c.(map[string]any)["Proxy"].(string)
+ d.ScanPath = c.(map[string]any)["ScanPath"].(string)
}
-func (d *WappalyzerGo) Run(url string) {
+func (d *WappalyzerGo) Run(targetURL string) []string {
+ var names = make([]string, 0)
+ client := d.newHTTPClient()
+
+ resp, body, err := d.fetchResponse(client, targetURL)
+ if err != nil {
+ fmt.Printf("error fetching %s: %v\n", targetURL, err)
+ fmt.Printf("[SCAN %s] WappalyzerGo scan for %s completed\n\n", targetURL, targetURL)
+ return names
+ }
+ if resp != nil {
+ defer resp.Body.Close()
+ }
+
+ results, err := d.fingerprint(resp, body)
+ if err != nil {
+ fmt.Printf("error fingerprinting %s: %v\n", targetURL, err)
+ fmt.Printf("[SCAN %s] WappalyzerGo scan for %s completed\n\n", targetURL, targetURL)
+ return names
+ }
+
+ names = techNamesFromResults(results)
+ filename, err := d.saveNames(names, targetURL)
+ if err != nil {
+ fmt.Printf("error saving results for %s: %v\n", targetURL, err)
+ } else {
+ fmt.Printf("[SCAN %s] WappalyzerGo results are stored in %s\n", targetURL, filename)
+ }
+
+ fmt.Printf("%v\n", names)
+ fmt.Printf("[SCAN %s] WappalyzerGo scan for %s completed\n\n", targetURL, targetURL)
+ return names
+}
+
+func (d *WappalyzerGo) newHTTPClient() *http.Client {
transport := helper.GetHttpTransport()
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
- client := &http.Client{
+ return &http.Client{
Transport: transport,
}
+}
- req, err := http.NewRequest("GET", url, nil)
+func (d *WappalyzerGo) fetchResponse(client *http.Client, targetURL string) (*http.Response, []byte, error) {
+ req, err := http.NewRequest("GET", targetURL, nil)
+ if err != nil {
+ return nil, nil, fmt.Errorf("creating request: %w", err)
+ }
req.Header.Add("User-Agent", helper.GetUserAgent())
resp, err := client.Do(req)
if err != nil {
- fmt.Printf("%v", err)
+ return resp, nil, fmt.Errorf("performing request: %w", err)
}
- if resp != nil {
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- fmt.Printf("%v", err)
+ if resp == nil {
+ return nil, nil, fmt.Errorf("no response received")
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return resp, nil, fmt.Errorf("reading response body: %w", err)
+ }
+
+ return resp, body, nil
+}
+
+func (d *WappalyzerGo) fingerprint(resp *http.Response, body []byte) (any, error) {
+ wappalyzerClient, err := wappalyzer.New()
+ if err != nil {
+ return nil, fmt.Errorf("initializing wappalyzer client: %w", err)
+ }
+
+ results := wappalyzerClient.Fingerprint(resp.Header, body)
+ return results, nil
+}
+
+func (d *WappalyzerGo) saveNames(names []string, targetURL string) (string, error) {
+ data, err := json.MarshalIndent(names, "", "\t")
+ if err != nil {
+ return "", fmt.Errorf("marshal names: %w", err)
+ }
+
+ filename := d.ScanPath + "/wappalyzer.json"
+ if err := os.WriteFile(filename, data, 0644); err != nil {
+ return "", fmt.Errorf("write file %s: %w", filename, err)
+ }
+
+ return filename, nil
+}
+
+func techNamesFromResults(results any) []string {
+ if s, ok := results.([]string); ok {
+ out := make([]string, len(s))
+ copy(out, s)
+ sort.Strings(out)
+ return out
+ }
+
+ if si, ok := results.([]interface{}); ok {
+ out := make([]string, 0, len(si))
+ for _, v := range si {
+ out = append(out, fmt.Sprint(v))
}
+ sort.Strings(out)
+ return out
+ }
- wappalyzerClient, err := wappalyzer.New()
- fingerprints := wappalyzerClient.Fingerprint(resp.Header, body)
- fmt.Printf("%v\n", fingerprints)
+ val := reflect.ValueOf(results)
+ if val.Kind() == reflect.Map {
+ out := make([]string, 0, val.Len())
+ for _, k := range val.MapKeys() {
+ out = append(out, fmt.Sprint(k.Interface()))
+ }
+ sort.Strings(out)
+ return out
}
- fmt.Printf("[SCAN %s] WappalyzerGo scan for %s completed\n\n", url, url)
+ return []string{fmt.Sprint(results)}
}
| | | | | | | | |