mirror of
https://github.com/j3ssie/osmedeus.git
synced 2026-09-27 20:14:54 +02:00
185 lines
7.0 KiB
Go
185 lines
7.0 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/j3ssie/osmedeus/core"
|
|
"github.com/j3ssie/osmedeus/distribute"
|
|
"github.com/j3ssie/osmedeus/libs"
|
|
"github.com/j3ssie/osmedeus/utils"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/text/cases"
|
|
"golang.org/x/text/language"
|
|
)
|
|
|
|
func init() {
|
|
var cloudCmd = &cobra.Command{
|
|
Use: "cloud",
|
|
Short: "Perform a scan using the distributed cloud mode",
|
|
Long: core.Banner(),
|
|
RunE: runCloud,
|
|
}
|
|
|
|
// core options
|
|
cloudCmd.Flags().StringVarP(&options.Cloud.Module, "module", "m", "", "module name for running")
|
|
cloudCmd.Flags().StringVarP(&options.Cloud.Flow, "flow", "f", "general", "Flow name for running (default: general)")
|
|
cloudCmd.Flags().StringVarP(&options.Cloud.Workspace, "workspace", "w", "", "Name of workspace (default is same as target)")
|
|
cloudCmd.Flags().StringSliceVarP(&options.Cloud.Params, "params", "p", []string{}, "Custom params -p='foo=bar' (Multiple -p flags are accepted)")
|
|
|
|
// chunk inputs
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.EnablePrivateIP, "privateIP", false, "Enable Private IP")
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.TargetAsFile, "as-file", false, "Run target as file (use -T targets.txt file instead of -t targets.txt at cloud instance)")
|
|
cloudCmd.Flags().StringVar(&options.Cloud.LocalSyncFolder, "rfolder", "", "Remote Folder to sync back to local")
|
|
|
|
// commands on cloud
|
|
cloudCmd.Flags().IntVar(&options.Cloud.Threads, "cloud-threads", 1, "Concurrency level on remote cloud")
|
|
cloudCmd.Flags().StringVar(&options.Cloud.Extra, "extra", "", "append raw command after the command builder")
|
|
cloudCmd.Flags().StringVar(&options.Cloud.RawCommand, "cmd", "", "specific raw command and override everything (eg: --cmd 'curl {{Target}}')")
|
|
cloudCmd.Flags().StringVar(&options.Cloud.ClearTime, "clear", "10m", "time to wait before next clear check")
|
|
cloudCmd.Flags().StringVar(&options.Cloud.TempTarget, "tempTargets", "/tmp/osm-tmp-inputs/", "Temp Folder to store targets file")
|
|
|
|
// mics option
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.EnableSyncWorkflow, "sync-workflow", false, "Enable Sync Workflow folder to remote machine first before starting the scan")
|
|
cloudCmd.Flags().BoolVarP(&options.Cloud.CopyWorkspaceToGit, "gws", "G", false, "Enable Copy Workspace to Git (run -f sync after done)")
|
|
cloudCmd.Flags().BoolVarP(&options.Cloud.DisableLocalSync, "no-lsync", "z", false, "Disable sync back data to local machine")
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.BackgroundRun, "bg", false, "Send command to instance without checking if process is done or not")
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.EnableTerraform, "tf", false, "Use terraform to create cloud instance")
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.NoDelete, "no-del", false, "Don't delete instance after done (you can run 'osmedeus provider health' to clean up later)")
|
|
cloudCmd.Flags().BoolVar(&options.Cloud.IgnoreProcess, "no-ps", false, "Disable checking process on remote machine")
|
|
cloudCmd.Flags().IntVar(&options.Cloud.Retry, "retry", 10, "Number of retry when command is error")
|
|
cloudCmd.SetHelpFunc(CloudHelp)
|
|
RootCmd.AddCommand(cloudCmd)
|
|
cloudCmd.PreRun = func(cmd *cobra.Command, args []string) {
|
|
if options.FullHelp {
|
|
cmd.Help()
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
}
|
|
|
|
func runCloud(cmd *cobra.Command, _ []string) error {
|
|
utils.GoodF("Launching %v Engine %v developed by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR))
|
|
utils.InforF("Storing the log file to: %v", color.CyanString(options.LogFile))
|
|
|
|
// parse some arguments
|
|
threads, _ := cmd.Flags().GetInt("thread")
|
|
if threads > 1 || options.Cloud.Threads <= 1 {
|
|
options.Cloud.Threads = threads
|
|
}
|
|
|
|
// get pre run commands
|
|
getPreRun(&options)
|
|
|
|
// change targets list if chunk mode enable
|
|
if options.Cloud.EnableChunk {
|
|
utils.InforF("Running cloud scan in chunk mode")
|
|
for _, target := range options.Scan.Inputs {
|
|
chunkTargets := HandleChunksInputs(target)
|
|
if len(chunkTargets) == 0 {
|
|
continue
|
|
}
|
|
|
|
distribute.InitCloud(options, chunkTargets)
|
|
// remove chunk inputs
|
|
utils.DebugF("Remove chunk inputs file")
|
|
for _, ctarget := range chunkTargets {
|
|
os.RemoveAll(ctarget)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// @NOTE: pro-tips
|
|
if options.Concurrency > 1 && len(options.Scan.Inputs) == 1 {
|
|
if !utils.FileExists(options.Scan.Inputs[0]) {
|
|
utils.WarnF("You're using %v in cloud scan but your input %v is just a single domain", color.HiMagentaString(`'-c %v'`, options.Concurrency), color.HiMagentaString(`'-t %v'`, options.Scan.Inputs[0]))
|
|
utils.WarnF("Consider running: osmedeus cloud -c 5 -T list-of-targets.txt")
|
|
}
|
|
}
|
|
|
|
distribute.InitCloud(options, options.Scan.Inputs)
|
|
return nil
|
|
}
|
|
|
|
// HandleChunksInputs split the inputs to multiple file first
|
|
func HandleChunksInputs(target string) []string {
|
|
var chunkTargets []string
|
|
utils.MakeDir(options.Cloud.ChunkInputs)
|
|
|
|
if !utils.FileExists(target) {
|
|
utils.ErrorF("error to split input file: %v", target)
|
|
return chunkTargets
|
|
}
|
|
|
|
if options.Cloud.NumberOfParts == 0 {
|
|
options.Cloud.NumberOfParts = options.Concurrency
|
|
}
|
|
|
|
utils.DebugF("Splitting %v to %v part", target, options.Cloud.NumberOfParts)
|
|
rawChunks, err := utils.SplitLineChunks(target, options.Cloud.NumberOfParts)
|
|
if err != nil || len(rawChunks) == 0 {
|
|
utils.ErrorF("error to split input file: %v", target)
|
|
return chunkTargets
|
|
}
|
|
fp, err := os.Open(target)
|
|
if err != nil {
|
|
utils.ErrorF("error to open input file: %v", target)
|
|
return chunkTargets
|
|
}
|
|
for index, offset := range rawChunks {
|
|
targetName := fmt.Sprintf("%s-chunk-%v", utils.CleanPath(target), index)
|
|
targetName = path.Join(options.Cloud.ChunkInputs, targetName)
|
|
|
|
sectionReader := io.NewSectionReader(fp, offset.Start, offset.Stop-offset.Start)
|
|
targetFile, err := os.OpenFile(targetName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
utils.ErrorF("error when create chunk file: %v", target)
|
|
continue
|
|
}
|
|
|
|
_, err = io.Copy(targetFile, sectionReader)
|
|
if err != nil {
|
|
utils.ErrorF("error to read chunk file: %s", err)
|
|
continue
|
|
}
|
|
targetFile.Close()
|
|
chunkTargets = append(chunkTargets, targetName)
|
|
}
|
|
|
|
return chunkTargets
|
|
}
|
|
|
|
func getPreRun(options *libs.Options) {
|
|
if options.Cloud.Module != "" {
|
|
module := core.DirectSelectModule(*options, options.Cloud.Module)
|
|
if module == "" {
|
|
utils.ErrorF("Error to select module: %s", options.Cloud.Module)
|
|
return
|
|
}
|
|
parsedModule, err := core.ParseModules(module)
|
|
if err == nil {
|
|
options.Cloud.RemotePreRun = parsedModule.RemotePreRun
|
|
options.Cloud.LocalPostRun = parsedModule.LocalPostRun
|
|
options.Cloud.LocalPreRun = parsedModule.LocalPreRun
|
|
options.Cloud.LocalSteps = parsedModule.LocalSteps
|
|
}
|
|
return
|
|
}
|
|
|
|
if options.Cloud.Flow != "" {
|
|
flows := core.SelectFlow(options.Cloud.Flow, *options)
|
|
for _, flow := range flows {
|
|
parseFlow, err := core.ParseFlow(flow)
|
|
if err == nil {
|
|
options.Cloud.RemotePreRun = parseFlow.RemotePreRun
|
|
options.Cloud.LocalPostRun = parseFlow.LocalPostRun
|
|
options.Cloud.LocalPreRun = parseFlow.LocalPreRun
|
|
}
|
|
}
|
|
}
|
|
}
|