diff --git a/core/parse.go b/core/parse.go index 2d708fc..67eaf06 100644 --- a/core/parse.go +++ b/core/parse.go @@ -148,6 +148,12 @@ func ParseInputFormat(raw string, options libs.Options) map[string]string { // ParseInput parse input for routine func ParseInput(raw string, options libs.Options) map[string]string { ROptions := ParseTarget(raw) + if utils.IsFile(raw) { + ROptions["TargetIsFile"] = "true" + } else { + ROptions["TargetIsFile"] = "false" + } + if options.EnableFormatInput { // avoid the loophole options.EnableFormatInput = false @@ -199,7 +205,6 @@ func ParseInput(raw string, options libs.Options) map[string]string { ROptions["Workspace"] = utils.CleanPath(options.Scan.CustomWorkspace) } ROptions["Output"] = path.Join(ROptions["Workspaces"], ROptions["Workspace"]) - ROptions["ExecutionLog"] = path.Join(ROptions["Output"], "execution.log") ROptions["LogFile"] = options.LogFile diff --git a/libs/version.go b/libs/version.go index 57b02bb..e7d571d 100644 --- a/libs/version.go +++ b/libs/version.go @@ -4,7 +4,7 @@ import "fmt" const ( // VERSION of this project - VERSION = "v4.7.0" + VERSION = "v4.7.1" // DESC description of the tool DESC = "A Workflow Engine for Offensive Security" // BINARY name of osmedeus diff --git a/server/API-SPEC.md b/server/API-SPEC.md new file mode 100644 index 0000000..a3ce040 --- /dev/null +++ b/server/API-SPEC.md @@ -0,0 +1,457 @@ +# Osmedeus API Specification + +> Generated by LLM + +- [Osmedeus API Specification](#osmedeus-api-specification) + - [Overview](#overview) + - [Base URL](#base-url) + - [Authentication](#authentication) + - [1. JWT Token Authentication (Default)](#1-jwt-token-authentication-default) + - [2. Basic Authentication (Optional)](#2-basic-authentication-optional) + - [3. No Authentication (Development Mode)](#3-no-authentication-development-mode) + - [API Endpoints](#api-endpoints) + - [Authentication](#authentication-1) + - [Login](#login) + - [System Health](#system-health) + - [Health Check](#health-check) + - [Ping](#ping) + - [Workspaces](#workspaces) + - [List All Workspaces](#list-all-workspaces) + - [Get Workspace Details](#get-workspace-details) + - [Delete Workspace](#delete-workspace) + - [Scans](#scans) + - [List All Scans](#list-all-scans) + - [Start New Scan](#start-new-scan) + - [Processes](#processes) + - [List Running Processes](#list-running-processes) + - [Workflows](#workflows) + - [List Available Workflows](#list-available-workflows) + - [File Operations](#file-operations) + - [Upload Data](#upload-data) + - [Static Content](#static-content) + - [Workspace Files](#workspace-files) + - [Storage Files](#storage-files) + - [Utility](#utility) + - [Raw Directory Information](#raw-directory-information) + - [Helper Message](#helper-message) + - [Example Scanning request](#example-scanning-request) + - [Basic Scanning](#basic-scanning) + - [Scanning with URL workflow](#scanning-with-url-workflow) + + +## Overview +Osmedeus is a workflow engine for offensive security testing. This API provides endpoints to manage workspaces, execute scans, and monitor processes. + +## Base URL +- **Local**: `http://localhost:8000` +- **With SSL**: `https://localhost:8443` + +## Authentication +The API supports two authentication methods: + +### 1. JWT Token Authentication (Default) +- **Login Endpoint**: `POST /api/login` +- **Token Header**: `Authorization: Osmedeus ` +- **Token Expiry**: 30 days + +### 2. Basic Authentication (Optional) +- **Username**: `osmedeus` +- **Password**: Configured master password +- **Header**: `Authorization: Basic ` + +### 3. No Authentication (Development Mode) +- Enabled with `-A` flag + +## API Endpoints + +### Authentication + +#### Login +Authenticate user and obtain JWT token. + +**Endpoint**: `POST /api/login` + +**Request Body**: +```json +{ + "username": "admin", + "password": "your_password" +} +``` + +**Response**: +```json +{ + "status": "success", + "message": "Successfully login", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Status Codes**: +- `200`: Success +- `401`: Unauthorized +- `500`: Internal Server Error + +### System Health + +#### Health Check +Check server health status and version. + +**Endpoint**: `GET /api/osmp/health` + +**Response**: +```json +{ + "status": 200, + "data": { + "version": "v4.5.0" + }, + "message": "server is up" +} +``` + +#### Ping +Simple connectivity check. + +**Endpoint**: `GET /ping` + +**Response**: +```json +{ + "status": 200, + "message": "pong" +} +``` + +### Workspaces + +#### List All Workspaces +Get all available workspaces. + +**Endpoint**: `GET /api/osmp/workspaces` + +**Response**: +```json +{ + "status": 200, + "data": [...], + "type": "workspaces", + "total": 42, + "message": "List all of Workspaces" +} +``` + +#### Get Workspace Details +Get detailed information about a specific workspace including reports. + +**Endpoint**: `GET /api/osmp/workspace/{wsname}` + +**Path Parameters**: +- `wsname` (string): Workspace name + +**Response**: +```json +{ + "status": 200, + "data": { + "workspace": {...}, + "reports": { + "subdomain": ["/static/workspaces/target/subdomain.txt"], + "portscan": ["/static/workspaces/target/portscan.html"] + } + }, + "type": "workspace", + "message": "Workspace Detail" +} +``` + +#### Delete Workspace +Delete a workspace and all its associated files. + +**Endpoint**: `DELETE /api/osmp/delete/{wsname}` + +**Path Parameters**: +- `wsname` (string): Workspace name + +**Response**: +```json +{ + "status": 200, + "type": "delete", + "message": "Workspace Deleted" +} +``` + +**Status Codes**: +- `200`: Success +- `400`: Workspace doesn't exist + +### Scans + +#### List All Scans +Get all running and completed scan processes. + +**Endpoint**: `GET /api/osmp/scans` + +**Response**: +```json +{ + "status": 200, + "data": [...], + "type": "scans", + "total": 15, + "message": "List all the scan process" +} +``` + +#### Start New Scan +Execute a new scan with specified configuration. + +**Endpoint**: `POST /api/osmp/execute` + +**Request Body**: +```json +{ + "target": "example.com", + "workflow": "general", + "workspace": "my-project", + "threads": 10, + "timeout": "1h", + "debug": false +} +``` + +**Advanced Request Examples**: + +**Single Target**: +```json +{ + "target": "example.com", + "workflow": "general" +} +``` + +**Multiple Targets**: +```json +{ + "targets": ["1.2.3.4/24", "5.6.7.8/24"], + "as_file": true, + "workflow": "cidr" +} +``` + +**With Custom Parameters**: +```json +{ + "target": "example.com", + "workflow": "general", + "params": ["-deep", "-aggressive"], + "distributed": true, + "concurrency": 5 +} +``` + +**Response**: +```json +{ + "status": 200, + "data": { + "command": "osmedeus scan -f general -t example.com -w my-project", + "input": "example.com", + "workspace": "my-project" + }, + "type": "new-scan", + "message": "New Scan Imported" +} +``` + +**Request Schema**: +- `target` (string): Target to scan +- `targets` (array): List of targets to scan (optional) +- `workflow` (string): Workflow name to execute (default: "general") +- `workspace` (string): Workspace name (optional) +- `module` (string): Plugin name to run (optional) +- `threads` (integer): Number of concurrent threads (optional) +- `timeout` (string): Scan timeout (e.g., "1h", "30m") (optional) +- `concurrency` (integer): Concurrency level (optional) +- `distributed` (boolean): Enable distributed scanning (optional) +- `params` (array): Additional parameters (optional) +- `debug` (boolean): Enable debug mode (optional) +- `test` (boolean): Test mode without actual execution (optional) + +### Processes + +#### List Running Processes +Get all currently running Osmedeus processes. + +**Endpoint**: `GET /api/osmp/ps` + +**Response**: +```json +{ + "status": 200, + "data": [...], + "type": "processes", + "total": 5, + "message": "List all osm process" +} +``` + +### Workflows + +#### List Available Workflows +Get all available workflow configurations and their modules. + +**Endpoint**: `GET /api/osmp/flows` + +**Response**: +```json +{ + "status": 200, + "data": [ + { + "name": "general", + "desc": "General reconnaissance workflow", + "modules": "subdomain,portscan,vulnscan" + } + ], + "total": 12, + "type": "flows", + "message": "Workflows Listing" +} +``` + +### File Operations + +#### Upload Data +Upload target data or configuration files. + +**Endpoint**: `POST /api/osmp/upload` + +**Request Body**: +```json +{ + "data": "example.com\nsub.example.com", + "filename": "targets.txt" +} +``` + +**Response**: +```json +{ + "status": 200, + "data": { + "filepath": "/tmp/osmedeus-input/targets.txt" + }, + "type": "upload", + "message": "New Data Uploaded" +} +``` + +### Static Content + +#### Workspace Files +Access workspace files and reports. + +**Endpoint**: `GET /{static_prefix}/workspaces/{path...}` + +**Example**: `GET /static/workspaces/target/subdomain.txt` + +#### Storage Files +Access storage files and configurations. + +**Endpoint**: `GET /{static_prefix}/storages/{path...}` + +**Example**: `GET /static/storages/cloud-configs/aws.json` + +### Utility + +#### Raw Directory Information +Get raw directory structure for workspaces, storages, and logs. + +**Endpoint**: `GET /api/osmp/raw` + +**Response**: +```json +{ + "status": 200, + "data": { + "storages": "/static/storages/", + "workspaces": "/static/workspaces/", + "logs": "/static/logs/" + }, + "type": "raw", + "message": "Raw directory" +} +``` + +#### Helper Message +Get help information and documentation links. + +**Endpoint**: `GET /api/osmp/help` + +**Response**: +```json +{ + "status": 200, + "data": { + "version": "v4.5.0", + "doc": "https://docs.osmedeus.org", + "message": "[*] Visit this page for complete Usage: https://docs.osmedeus.org" + }, + "type": "helper", + "message": "Helper message" +} +``` + +## Example Scanning request + +### Basic Scanning + +``` +POST /api/osmp/execute HTTP/1.1 +Host: 127.0.0.1:8000 +User-Agent: curl/8.7.1 +Accept: */* +Connection: keep-alive +Authorization: +Content-Type: application/json +Content-Length: 334 + +{ + "target":"sample.io", + "flow":"general" +} + +``` + +### Scanning with URL workflow + +``` +POST /api/osmp/execute HTTP/1.1 +Host: 127.0.0.1:8000 +User-Agent: curl/8.7.1 +Accept: */* +Connection: keep-alive +Authorization: +Content-Type: application/json +Content-Length: 334 + +{ + "targets": [ + "origin-lite-www.example.com", + "partner.example.com", + "partners.example.com", + "polri.example.com", + "retailenabler.example.com", + "seller-id.example.com", + "shop-id.example.com", + "sobat.example.com" + ], + "as_file": true, + "debug": true, + "workspace": "custom-workspace", + "workflow": "url" +} +``` \ No newline at end of file diff --git a/server/builder.go b/server/builder.go index 9c1e0b8..6f35eda 100644 --- a/server/builder.go +++ b/server/builder.go @@ -130,12 +130,19 @@ func CommandBuilder(taskData *TaskData) string { return taskData.Command } - // mean general scan + // mean general scan with -f if taskData.ModuleName == "" { command = fmt.Sprintf("%v %v -t %v %v%v%v%v", binary, workflow, taskData.Target, concurrency, timeout, workspace, params) + + // this means loop through targets file one by one if taskData.TargetsFile != "" { command = fmt.Sprintf("%v %v -T %v %v%v%v%v", binary, workflow, taskData.TargetsFile, concurrency, timeout, workspace, params) } + + if taskData.TargetAsFile { + command = fmt.Sprintf("%v %v -t %v %v%v%v%v", binary, workflow, taskData.TargetsFile, concurrency, timeout, workspace, params) + } + command = strings.TrimSpace(command) if taskData.Debug { command = command + " --debug" @@ -144,10 +151,16 @@ func CommandBuilder(taskData *TaskData) string { } command = fmt.Sprintf("%v %v -t %v %v %v%v%v%v", binary, plugin, taskData.Target, scanID, concurrency, timeout, workspace, params) + + // this means loop through targets file one by one if taskData.TargetsFile != "" { command = fmt.Sprintf("%v %v -t %v %v %v%v%v%v", binary, plugin, taskData.TargetsFile, scanID, concurrency, timeout, workspace, params) } + if taskData.TargetAsFile { + command = fmt.Sprintf("%v %v -t %v %v%v%v%v", binary, workflow, taskData.TargetsFile, concurrency, timeout, workspace, params) + } + command = strings.TrimSpace(command) if taskData.Debug { command = command + " --debug" diff --git a/server/scan.go b/server/scan.go index 3263dc0..23d2252 100644 --- a/server/scan.go +++ b/server/scan.go @@ -16,19 +16,21 @@ type TaskData struct { TargetsList []string `json:"targets" description:"List of targets to scan (optional)"` WorkFlow string `json:"workflow" example:"general" description:"Workflow name to execute"` - ModuleName string `json:"module" example:"subdomain" description:"Plugin name to run (optional)"` - Workspace string `json:"workspace" example:"my-project" description:"Workspace name (optional)"` - TargetsFile string `json:"targets_file" example:"/path/to/targets.txt" description:"File containing targets (optional)"` - Threads int `json:"threads" example:"10" description:"Number of concurrent threads (optional)"` - Chunk bool `json:"chunk" example:"false" description:"Enable chunk mode (optional)"` - TargetAsFile bool `json:"as_file" example:"false" description:"Treat target as file (optional)"` - Params []string `json:"params" example:"[\"-deep\", \"-aggressive\"]" description:"Additional parameters (optional)"` - Timeout string `json:"timeout" example:"1h" description:"Scan timeout (optional)"` - Concurrency int `json:"concurrency" example:"5" description:"Concurrency level (optional)"` - Distributed bool `json:"distributed" example:"false" description:"Enable distributed scanning (optional)"` - WildCard bool `json:"wildcard" example:"false" description:"Enable wildcard mode (optional)"` - Debug bool `json:"debug" example:"false" description:"Enable debug mode (optional)"` - Test bool `json:"test" example:"false" description:"Test mode without actual execution (optional)"` + TargetAsFile bool `json:"as_file" example:"false" description:"Treat target as file (optional)"` + TargetsFile string `json:"targets_file" example:"/path/to/targets.txt" description:"File containing targets (optional)"` + UploadTargetFile bool `json:"upload_targets_file" example:"false" description:"Upload target data (optional)"` + Params []string `json:"params" example:"[\"-deep\", \"-aggressive\"]" description:"Additional parameters (optional)"` + + ModuleName string `json:"module" example:"subdomain" description:"Plugin name to run (optional)"` + Workspace string `json:"workspace" example:"my-project" description:"Workspace name (optional)"` + Threads int `json:"threads" example:"10" description:"Number of concurrent threads (optional)"` + Chunk bool `json:"chunk" example:"false" description:"Enable chunk mode (optional)"` + Timeout string `json:"timeout" example:"1h" description:"Scan timeout (optional)"` + Concurrency int `json:"concurrency" example:"5" description:"Concurrency level (optional)"` + Distributed bool `json:"distributed" example:"false" description:"Enable distributed scanning (optional)"` + WildCard bool `json:"wildcard" example:"false" description:"Enable wildcard mode (optional)"` + Debug bool `json:"debug" example:"false" description:"Enable debug mode (optional)"` + Test bool `json:"test" example:"false" description:"Test mode without actual execution (optional)"` } // @Summary Start a new scan @@ -87,8 +89,9 @@ func NewScan(c *fiber.Ctx) error { return c.JSON(ResponseHTTP{ Status: 200, Data: fiber.Map{ - "command": taskData.Command, - "input": taskData.Target, + "command": taskData.Command, + "input": taskData.Target, + "workspace": taskData.Workspace, // this would be the folder name }, Type: "new-scan", Message: "New Scan Imported",