mirror of
https://github.com/lunchcat/sif.git
synced 2026-03-12 21:23:04 -07:00
feat: implement api mode
This commit is contained in:
@@ -8,21 +8,22 @@ import (
|
||||
)
|
||||
|
||||
type Settings struct {
|
||||
Dirlist string
|
||||
Dnslist string
|
||||
Debug bool
|
||||
LogDir string
|
||||
NoScan bool
|
||||
Ports string
|
||||
Dorking bool
|
||||
Git bool
|
||||
Whois bool
|
||||
Threads int
|
||||
Nuclei bool
|
||||
Timeout time.Duration
|
||||
URLs goflags.StringSlice
|
||||
File string
|
||||
ApiMode bool
|
||||
Dirlist string
|
||||
Dnslist string
|
||||
Debug bool
|
||||
LogDir string
|
||||
NoScan bool
|
||||
Ports string
|
||||
Dorking bool
|
||||
Git bool
|
||||
Whois bool
|
||||
Threads int
|
||||
Nuclei bool
|
||||
JavaScript bool
|
||||
Timeout time.Duration
|
||||
URLs goflags.StringSlice
|
||||
File string
|
||||
ApiMode bool
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -60,6 +61,7 @@ func Parse() *Settings {
|
||||
flagSet.BoolVar(&settings.Nuclei, "nuclei", false, "Enable scanning using nuclei templates"),
|
||||
flagSet.BoolVar(&settings.NoScan, "noscan", false, "Do not perform base URL (robots.txt, etc) scanning"),
|
||||
flagSet.BoolVar(&settings.Whois, "whois", false, "Enable WHOIS lookup"),
|
||||
flagSet.BoolVar(&settings.JavaScript, "js", false, "Enable JavaScript scans"),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("runtime", "Runtime",
|
||||
|
||||
@@ -22,7 +22,12 @@ const (
|
||||
bigFile = "directory-list-2.3-big.txt"
|
||||
)
|
||||
|
||||
func Dirlist(size string, url string, timeout time.Duration, threads int, logdir string) {
|
||||
type DirectoryResult struct {
|
||||
Url string `json:"url"`
|
||||
StatusCode int `json:"status_code"`
|
||||
}
|
||||
|
||||
func Dirlist(size string, url string, timeout time.Duration, threads int, logdir string) ([]DirectoryResult, error) {
|
||||
|
||||
fmt.Println(styles.Separator.Render("📂 Starting " + styles.Status.Render("directory fuzzing") + "..."))
|
||||
|
||||
@@ -31,7 +36,7 @@ func Dirlist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
if logdir != "" {
|
||||
if err := logger.WriteHeader(sanitizedURL, logdir, size+" directory fuzzing"); err != nil {
|
||||
log.Errorf("Error creating log file: %v", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +60,7 @@ func Dirlist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
resp, err := http.Get(list)
|
||||
if err != nil {
|
||||
log.Errorf("Error downloading directory list: %s", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var directories []string
|
||||
@@ -71,6 +76,8 @@ func Dirlist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(threads)
|
||||
|
||||
results := []DirectoryResult{}
|
||||
for thread := 0; thread < threads; thread++ {
|
||||
go func(thread int) {
|
||||
defer wg.Done()
|
||||
@@ -93,9 +100,17 @@ func Dirlist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
if logdir != "" {
|
||||
logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s [%s]\n", strconv.Itoa(resp.StatusCode), directory))
|
||||
}
|
||||
|
||||
result := DirectoryResult{
|
||||
Url: resp.Request.URL.String(),
|
||||
StatusCode: resp.StatusCode,
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
}
|
||||
}(thread)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const (
|
||||
dnsBigFile = "subdomains-10000.txt"
|
||||
)
|
||||
|
||||
func Dnslist(size string, url string, timeout time.Duration, threads int, logdir string) {
|
||||
func Dnslist(size string, url string, timeout time.Duration, threads int, logdir string) ([]string, error) {
|
||||
|
||||
fmt.Println(styles.Separator.Render("📡 Starting " + styles.Status.Render("DNS fuzzing") + "..."))
|
||||
|
||||
@@ -45,7 +45,7 @@ func Dnslist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
resp, err := http.Get(list)
|
||||
if err != nil {
|
||||
log.Errorf("Error downloading DNS list: %s", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var dns []string
|
||||
@@ -60,7 +60,7 @@ func Dnslist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
if logdir != "" {
|
||||
if err := logger.WriteHeader(sanitizedURL, logdir, size+" subdomain fuzzing"); err != nil {
|
||||
log.Errorf("Error creating log file: %v", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ func Dnslist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(threads)
|
||||
|
||||
urls := []string{}
|
||||
for thread := 0; thread < threads; thread++ {
|
||||
go func(thread int) {
|
||||
defer wg.Done()
|
||||
@@ -80,10 +82,11 @@ func Dnslist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
}
|
||||
|
||||
log.Debugf("Looking up: %s", domain)
|
||||
_, err := client.Get("http://" + domain + "." + sanitizedURL)
|
||||
resp, err := client.Get("http://" + domain + "." + sanitizedURL)
|
||||
if err != nil {
|
||||
log.Debugf("Error %s: %s", domain, err)
|
||||
} else {
|
||||
urls = append(urls, resp.Request.URL.String())
|
||||
dnslog.Infof("%s %s.%s", styles.Status.Render("[http]"), styles.Highlight.Render(domain), sanitizedURL)
|
||||
|
||||
if logdir != "" {
|
||||
@@ -97,10 +100,11 @@ func Dnslist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
}
|
||||
}
|
||||
|
||||
_, err = client.Get("https://" + domain + "." + sanitizedURL)
|
||||
resp, err = client.Get("https://" + domain + "." + sanitizedURL)
|
||||
if err != nil {
|
||||
log.Debugf("Error %s: %s", domain, err)
|
||||
} else {
|
||||
urls = append(urls, resp.Request.URL.String())
|
||||
dnslog.Infof("%s %s.%s", styles.Status.Render("[https]"), styles.Highlight.Render(domain), sanitizedURL)
|
||||
if logdir != "" {
|
||||
logger.Write(sanitizedURL, logdir, fmt.Sprintf("[https] %s.%s\n", domain, sanitizedURL))
|
||||
@@ -110,4 +114,6 @@ func Dnslist(size string, url string, timeout time.Duration, threads int, logdir
|
||||
}(thread)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return urls, nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,12 @@ const (
|
||||
dorkFile = "dork.txt"
|
||||
)
|
||||
|
||||
func Dork(url string, timeout time.Duration, threads int, logdir string) {
|
||||
type DorkResult struct {
|
||||
Url string `json:"url"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
func Dork(url string, timeout time.Duration, threads int, logdir string) ([]DorkResult, error) {
|
||||
|
||||
fmt.Println(styles.Separator.Render("🤓 Starting " + styles.Status.Render("URL Dorking") + "..."))
|
||||
|
||||
@@ -30,7 +35,7 @@ func Dork(url string, timeout time.Duration, threads int, logdir string) {
|
||||
if logdir != "" {
|
||||
if err := logger.WriteHeader(sanitizedURL, logdir, "URL dorking"); err != nil {
|
||||
log.Errorf("Error creating log file: %v", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +48,7 @@ func Dork(url string, timeout time.Duration, threads int, logdir string) {
|
||||
resp, err := http.Get(dorkURL + dorkFile)
|
||||
if err != nil {
|
||||
log.Errorf("Error downloading dork list: %s", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var dorks []string
|
||||
@@ -56,6 +61,8 @@ func Dork(url string, timeout time.Duration, threads int, logdir string) {
|
||||
// util.InitProgressBar()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(threads)
|
||||
|
||||
dorkResults := []DorkResult{}
|
||||
for thread := 0; thread < threads; thread++ {
|
||||
go func(thread int) {
|
||||
defer wg.Done()
|
||||
@@ -71,9 +78,18 @@ func Dork(url string, timeout time.Duration, threads int, logdir string) {
|
||||
if logdir != "" {
|
||||
logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s dork results found for dork [%s]\n", strconv.Itoa(len(results)), dork))
|
||||
}
|
||||
|
||||
result := DorkResult{
|
||||
Url: dork,
|
||||
Count: len(results),
|
||||
}
|
||||
|
||||
dorkResults = append(dorkResults, result)
|
||||
}
|
||||
}
|
||||
}(thread)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return dorkResults, nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const (
|
||||
gitFile = "git.txt"
|
||||
)
|
||||
|
||||
func Git(url string, timeout time.Duration, threads int, logdir string) {
|
||||
func Git(url string, timeout time.Duration, threads int, logdir string) ([]string, error) {
|
||||
|
||||
fmt.Println(styles.Separator.Render("🌿 Starting " + styles.Status.Render("git repository scanning") + "..."))
|
||||
|
||||
@@ -29,7 +29,7 @@ func Git(url string, timeout time.Duration, threads int, logdir string) {
|
||||
if logdir != "" {
|
||||
if err := logger.WriteHeader(sanitizedURL, logdir, "git directory fuzzing"); err != nil {
|
||||
log.Errorf("Error creating log file: %v", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func Git(url string, timeout time.Duration, threads int, logdir string) {
|
||||
resp, err := http.Get(gitURL + gitFile)
|
||||
if err != nil {
|
||||
log.Errorf("Error downloading git list: %s", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var gitUrls []string
|
||||
@@ -59,6 +59,8 @@ func Git(url string, timeout time.Duration, threads int, logdir string) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(threads)
|
||||
|
||||
foundUrls := []string{}
|
||||
for thread := 0; thread < threads; thread++ {
|
||||
go func(thread int) {
|
||||
defer wg.Done()
|
||||
@@ -74,15 +76,19 @@ func Git(url string, timeout time.Duration, threads int, logdir string) {
|
||||
log.Debugf("Error %s: %s", repourl, err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 404 {
|
||||
if resp.StatusCode == 200 && !strings.HasPrefix(resp.Header.Get("Content-Type"), "text/html") {
|
||||
// log url, directory, and status code
|
||||
gitlog.Infof("%s git found at [%s]", styles.Status.Render(strconv.Itoa(resp.StatusCode)), styles.Highlight.Render(repourl))
|
||||
if logdir != "" {
|
||||
logger.Write(sanitizedURL, logdir, fmt.Sprintf("%s git found at [%s]\n", strconv.Itoa(resp.StatusCode), repourl))
|
||||
}
|
||||
|
||||
foundUrls = append(foundUrls, resp.Request.URL.String())
|
||||
}
|
||||
}
|
||||
}(thread)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return foundUrls, nil
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package js
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -16,15 +16,24 @@ import (
|
||||
urlutil "github.com/projectdiscovery/utils/url"
|
||||
)
|
||||
|
||||
func JavascriptScan(url string, timeout time.Duration, threads int, logdir string) {
|
||||
type JavascriptScanResult struct {
|
||||
SupabaseResults []supabaseScanResult `json:"supabase_results"`
|
||||
FoundEnvironmentVars map[string]string `json:"environment_variables"`
|
||||
}
|
||||
|
||||
func JavascriptScan(url string, timeout time.Duration, threads int, logdir string) (*JavascriptScanResult, error) {
|
||||
jslog := log.NewWithOptions(os.Stderr, log.Options{
|
||||
Prefix: "🚧 JavaScript",
|
||||
}).With("url", url)
|
||||
|
||||
baseUrl, err := urlutil.Parse(url)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -37,13 +46,13 @@ func JavascriptScan(url string, timeout time.Duration, threads int, logdir strin
|
||||
|
||||
doc, err := htmlquery.Parse(strings.NewReader(html))
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var scripts []string
|
||||
nodes, err := htmlquery.QueryAll(doc, "//script/@src")
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
var src = htmlquery.InnerText(node)
|
||||
@@ -61,9 +70,10 @@ func JavascriptScan(url string, timeout time.Duration, threads int, logdir strin
|
||||
|
||||
for _, script := range scripts {
|
||||
if strings.Contains(script, "/_buildManifest.js") {
|
||||
jslog.Infof("Detected Next.JS pages router! Getting all scripts from %s", script)
|
||||
nextScripts, err := frameworks.GetPagesRouterScripts(script)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, nextScript := range nextScripts {
|
||||
@@ -75,10 +85,11 @@ func JavascriptScan(url string, timeout time.Duration, threads int, logdir strin
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("Got all scripts: %s, now running scans on them", scripts)
|
||||
jslog.Infof("Got %d scripts, now running scans on them", len(scripts))
|
||||
|
||||
var supabaseResults []supabaseScanResult
|
||||
for _, script := range scripts {
|
||||
log.Debugf("Scanning %s", script)
|
||||
jslog.Infof("Scanning %s", script)
|
||||
resp, err := http.Get(script)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -92,19 +103,22 @@ func JavascriptScan(url string, timeout time.Duration, threads int, logdir strin
|
||||
}
|
||||
content := string(bodyBytes)
|
||||
|
||||
supabaseResults, err := ScanSupabase(content)
|
||||
jslog.Infof("Running supabase scanner on %s", script)
|
||||
scriptSupabaseResults, err := ScanSupabase(content, script)
|
||||
|
||||
if err != nil {
|
||||
log.Debugf("Error while scanning supabase: %s", err)
|
||||
jslog.Errorf("Error while scanning supabase: %s", err)
|
||||
}
|
||||
|
||||
if supabaseResults != nil {
|
||||
marshalled, err := json.Marshal(supabaseResults)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Supabase results: %s", marshalled)
|
||||
if scriptSupabaseResults != nil {
|
||||
supabaseResults = append(supabaseResults, scriptSupabaseResults...)
|
||||
}
|
||||
}
|
||||
|
||||
result := JavascriptScanResult{
|
||||
SupabaseResults: supabaseResults,
|
||||
FoundEnvironmentVars: map[string]string{},
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
@@ -92,7 +93,10 @@ func GetSupabaseJsonResponse(projectId string, path string, apikey string, auth
|
||||
return data.(map[string]interface{}), nil
|
||||
}
|
||||
|
||||
func ScanSupabase(jsContent string) ([]supabaseScanResult, error) {
|
||||
func ScanSupabase(jsContent string, jsUrl string) ([]supabaseScanResult, error) {
|
||||
supabaselog := log.NewWithOptions(os.Stderr, log.Options{
|
||||
Prefix: "🚧 JavaScript > Supabase ⚡️",
|
||||
}).With("url", jsUrl)
|
||||
|
||||
jwtRegex, err := regexp.Compile("[\"|'|`](ey[A-Za-z0-9_-]{2,}(?:\\.[A-Za-z0-9_-]{2,}){2})[\"|'|`]")
|
||||
|
||||
@@ -118,15 +122,15 @@ func ScanSupabase(jsContent string) ([]supabaseScanResult, error) {
|
||||
|
||||
decoded, err := base64.RawStdEncoding.DecodeString(body)
|
||||
if err != nil {
|
||||
log.Debugf("Failed to decode JWT %s: %s", body, err)
|
||||
supabaselog.Debugf("Failed to decode JWT %s: %s", body, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("JWT body: %s", decoded)
|
||||
supabaselog.Debugf("JWT body: %s", decoded)
|
||||
var supabaseJwt *supabaseJwtBody
|
||||
err = json.Unmarshal([]byte(decoded), &supabaseJwt)
|
||||
if err != nil {
|
||||
log.Debugf("Failed to json parse JWT %s: %s", jwt, err)
|
||||
supabaselog.Debugf("Failed to json parse JWT %s: %s", jwt, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -134,22 +138,22 @@ func ScanSupabase(jsContent string) ([]supabaseScanResult, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Found valid supabase project %s with role %s", *supabaseJwt.ProjectId, *supabaseJwt.Role)
|
||||
supabaselog.Infof("Found valid supabase project %s with role %s", *supabaseJwt.ProjectId, *supabaseJwt.Role)
|
||||
client := http.Client{}
|
||||
|
||||
req, err := http.NewRequest("POST", "https://"+*supabaseJwt.ProjectId+".supabase.co/auth/v1/signup", bytes.NewBufferString(`{"email":"automated`+strconv.Itoa(int(time.Now().Unix()))+`@sif.sh","password":"automatedacct"}`))
|
||||
if err != nil {
|
||||
log.Debugf("1 %s", err)
|
||||
supabaselog.Errorf("Error while creating HTTP req for creating user: %s", err)
|
||||
continue
|
||||
}
|
||||
req.Header.Set("apikey", jwt)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Debugf("2 %s", err)
|
||||
|
||||
supabaselog.Errorf("Error while sending request to create user: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("%d", resp.StatusCode)
|
||||
var auth string
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
@@ -165,7 +169,7 @@ func ScanSupabase(jsContent string) ([]supabaseScanResult, error) {
|
||||
}
|
||||
|
||||
auth = data["access_token"].(string)
|
||||
log.Debugf("Created account with JWT %s", auth)
|
||||
supabaselog.Infof("Created account with JWT %s", auth)
|
||||
}
|
||||
|
||||
var collections = []supabaseCollection{}
|
||||
@@ -199,11 +203,13 @@ func ScanSupabase(jsContent string) ([]supabaseScanResult, error) {
|
||||
}
|
||||
|
||||
samples := sampleObj["array"].([]interface{})
|
||||
|
||||
for _, sample := range samples {
|
||||
log.Debugf("%s", sample)
|
||||
marshalled, err := json.Marshal(samples)
|
||||
if err != nil {
|
||||
supabaselog.Errorf("Failed to marshal sample data for %s: %s", k, err)
|
||||
}
|
||||
|
||||
supabaselog.Infof("Got sample (1000 entries) for collection %s: %s", k, string(marshalled))
|
||||
|
||||
limitedSample := samples[0:int(math.Min(float64(len(samples)), 10))]
|
||||
|
||||
collection := supabaseCollection{
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"github.com/projectdiscovery/ratelimit"
|
||||
)
|
||||
|
||||
func Nuclei(url string, timeout time.Duration, threads int, logdir string) {
|
||||
func Nuclei(url string, timeout time.Duration, threads int, logdir string) ([]output.ResultEvent, error) {
|
||||
fmt.Println(styles.Separator.Render("⚛️ Starting " + styles.Status.Render("nuclei template scanning") + "..."))
|
||||
|
||||
sanitizedURL := strings.Split(url, "://")[1]
|
||||
@@ -50,12 +50,14 @@ func Nuclei(url string, timeout time.Duration, threads int, logdir string) {
|
||||
config.DefaultConfig.SetTemplatesDir(pwd)
|
||||
catalog := disk.NewCatalog(pwd)
|
||||
|
||||
results := []output.ResultEvent{}
|
||||
// Custom output
|
||||
outputWriter := testutils.NewMockOutputWriter()
|
||||
outputWriter.WriteCallback = func(event *output.ResultEvent) {
|
||||
if event.Matched != "" {
|
||||
nucleilog.Infof(format.FormatLine(event))
|
||||
|
||||
results = append(results, *event)
|
||||
// TODO: metasploit
|
||||
}
|
||||
}
|
||||
@@ -70,7 +72,7 @@ func Nuclei(url string, timeout time.Duration, threads int, logdir string) {
|
||||
interactOpts := interactsh.DefaultOptions(outputWriter, reportingClient, progressClient)
|
||||
interactClient, err := interactsh.New(interactOpts)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create interact client: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
defer interactClient.Close()
|
||||
|
||||
@@ -92,13 +94,13 @@ func Nuclei(url string, timeout time.Duration, threads int, logdir string) {
|
||||
|
||||
workflowLoader, err := parsers.NewLoader(&executorOpts)
|
||||
if err != nil {
|
||||
nucleilog.Fatalf("Could not create workflow loader: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
executorOpts.WorkflowLoader = workflowLoader
|
||||
|
||||
store, err := loader.New(loader.NewConfig(options, catalog, executorOpts))
|
||||
if err != nil {
|
||||
nucleilog.Fatalf("Could not create loader client: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
store.Load()
|
||||
|
||||
@@ -107,4 +109,6 @@ func Nuclei(url string, timeout time.Duration, threads int, logdir string) {
|
||||
|
||||
_ = engine.Execute(store.Templates(), input)
|
||||
engine.WorkPool().Wait()
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ import (
|
||||
|
||||
const commonPorts = "https://raw.githubusercontent.com/dropalldatabases/sif-runtime/main/ports/top-ports.txt"
|
||||
|
||||
func Ports(scope string, url string, timeout time.Duration, threads int, logdir string) {
|
||||
fmt.Println(styles.Separator.Render("🚪 Starting " + styles.Status.Render("port scanning") + "..."))
|
||||
func Ports(scope string, url string, timeout time.Duration, threads int, logdir string) ([]string, error) {
|
||||
log.Printf(styles.Separator.Render("🚪 Starting " + styles.Status.Render("port scanning") + "..."))
|
||||
|
||||
sanitizedURL := strings.Split(url, "://")[1]
|
||||
if logdir != "" {
|
||||
if err := logger.WriteHeader(sanitizedURL, logdir, scope+" port scanning"); err != nil {
|
||||
log.Errorf("Error creating log file: %v", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func Ports(scope string, url string, timeout time.Duration, threads int, logdir
|
||||
resp, err := http.Get(commonPorts)
|
||||
if err != nil {
|
||||
log.Errorf("Error downloading ports list: %s", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
@@ -89,4 +89,6 @@ func Ports(scope string, url string, timeout time.Duration, threads int, logdir
|
||||
} else {
|
||||
portlog.Error("Found no open ports")
|
||||
}
|
||||
|
||||
return openPorts, nil
|
||||
}
|
||||
|
||||
87
sif.go
87
sif.go
@@ -2,6 +2,7 @@ package sif
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -12,8 +13,7 @@ import (
|
||||
"github.com/dropalldatabases/sif/pkg/config"
|
||||
"github.com/dropalldatabases/sif/pkg/logger"
|
||||
"github.com/dropalldatabases/sif/pkg/scan"
|
||||
"github.com/dropalldatabases/sif/pkg/scan/js"
|
||||
"github.com/dropalldatabases/sif/pkg/utils"
|
||||
jsscan "github.com/dropalldatabases/sif/pkg/scan/js"
|
||||
)
|
||||
|
||||
// App is a client instance. It is first initialised using New and then ran
|
||||
@@ -24,6 +24,16 @@ type App struct {
|
||||
logFiles []string
|
||||
}
|
||||
|
||||
type UrlResult struct {
|
||||
Url string `json:"url"`
|
||||
Results []ModuleResult
|
||||
}
|
||||
|
||||
type ModuleResult struct {
|
||||
Id string `json:"id"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// New creates a new App struct by parsing the configuration options,
|
||||
// figuring out the targets from list or file, etc.
|
||||
//
|
||||
@@ -68,6 +78,10 @@ func (app *App) Run() error {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
|
||||
if app.settings.ApiMode {
|
||||
log.SetLevel(5)
|
||||
}
|
||||
|
||||
if app.settings.LogDir != "" {
|
||||
if err := logger.Init(app.settings.LogDir); err != nil {
|
||||
return err
|
||||
@@ -81,6 +95,8 @@ func (app *App) Run() error {
|
||||
|
||||
log.Infof("📡Starting scan on %s...", url)
|
||||
|
||||
moduleResults := []ModuleResult{}
|
||||
|
||||
if app.settings.LogDir != "" {
|
||||
if err := logger.CreateFile(&app.logFiles, url, app.settings.LogDir); err != nil {
|
||||
return err
|
||||
@@ -92,15 +108,30 @@ func (app *App) Run() error {
|
||||
}
|
||||
|
||||
if app.settings.Dirlist != "none" {
|
||||
scan.Dirlist(app.settings.Dirlist, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
result, err := scan.Dirlist(app.settings.Dirlist, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error while running directory scan: %s", err)
|
||||
} else {
|
||||
moduleResults = append(moduleResults, ModuleResult{"dirlist", result})
|
||||
}
|
||||
}
|
||||
|
||||
if app.settings.Dnslist != "none" {
|
||||
scan.Dnslist(app.settings.Dnslist, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
result, err := scan.Dnslist(app.settings.Dnslist, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error while running dns scan: %s", err)
|
||||
} else {
|
||||
moduleResults = append(moduleResults, ModuleResult{"dnslist", result})
|
||||
}
|
||||
}
|
||||
|
||||
if app.settings.Ports != "none" {
|
||||
scan.Ports(app.settings.Ports, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
result, err := scan.Ports(app.settings.Ports, url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error while running port scan: %s", err)
|
||||
} else {
|
||||
moduleResults = append(moduleResults, ModuleResult{"portscan", result})
|
||||
}
|
||||
}
|
||||
|
||||
if app.settings.Whois {
|
||||
@@ -109,26 +140,52 @@ func (app *App) Run() error {
|
||||
|
||||
// func Git(url string, timeout time.Duration, threads int, logdir string)
|
||||
if app.settings.Git {
|
||||
scan.Git(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
result, err := scan.Git(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error while running Git module: %s", err)
|
||||
} else {
|
||||
moduleResults = append(moduleResults, ModuleResult{"git", result})
|
||||
}
|
||||
}
|
||||
|
||||
if app.settings.Nuclei {
|
||||
scan.Nuclei(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
result, err := scan.Nuclei(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error while running Nuclei module: %s", err)
|
||||
} else {
|
||||
moduleResults = append(moduleResults, ModuleResult{"nuclei", result})
|
||||
}
|
||||
}
|
||||
|
||||
js.JavascriptScan(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if app.settings.JavaScript {
|
||||
result, err := jsscan.JavascriptScan(url, app.settings.Timeout, app.settings.Threads, app.settings.LogDir)
|
||||
if err != nil {
|
||||
log.Errorf("Error while running JS module: %s", err)
|
||||
} else {
|
||||
moduleResults = append(moduleResults, ModuleResult{"js", result})
|
||||
}
|
||||
}
|
||||
|
||||
if app.settings.ApiMode {
|
||||
utils.ReturnApiOutput()
|
||||
}
|
||||
result := UrlResult{
|
||||
Url: url,
|
||||
Results: moduleResults,
|
||||
}
|
||||
|
||||
// TODO: WHOIS
|
||||
marshalled, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal result: %s", err)
|
||||
}
|
||||
fmt.Println(string(marshalled))
|
||||
}
|
||||
}
|
||||
|
||||
if app.settings.LogDir != "" {
|
||||
fmt.Println(styles.Box.Render(fmt.Sprintf("🌿 All scans completed!\n📂 Output saved to files: %s\n", strings.Join(app.logFiles, ", "))))
|
||||
} else {
|
||||
fmt.Println(styles.Box.Render(fmt.Sprintf("🌿 All scans completed!\n")))
|
||||
if !app.settings.ApiMode {
|
||||
if app.settings.LogDir != "" {
|
||||
fmt.Println(styles.Box.Render(fmt.Sprintf("🌿 All scans completed!\n📂 Output saved to files: %s\n", strings.Join(app.logFiles, ", "))))
|
||||
} else {
|
||||
fmt.Println(styles.Box.Render(fmt.Sprintf("🌿 All scans completed!\n")))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user