Skip to content

Commit afd5789

Browse files
authored
Merge pull request #2166 from BishopFox/linux/shellcode
Linux/shellcode
2 parents 0bef549 + 87b1efa commit afd5789

28 files changed

Lines changed: 2937 additions & 116 deletions

client/command/generate/commands.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,14 @@ func coreImplantFlags(name string, cmd *cobra.Command) {
343343
f.StringP("limit-fileexists", "F", "", "limit execution to hosts with this file in the filesystem")
344344
f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale")
345345

346-
f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows and darwin/arm64)")
346+
f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows, darwin/arm64, linux/amd64, linux/arm64)")
347347

348348
// Shellcode generation options:
349349
// - Windows: Donut
350350
// - macOS: beignet
351+
// - Linux: malasada
351352
f.Uint32("shellcode-entropy", 1, "Shellcode entropy (Donut: 1=none, 2=random names, 3=random+encrypt) (windows shellcode only)")
352-
f.Bool("shellcode-compress", false, "Enable shellcode compression (aPLib) (windows and macOS shellcode)")
353+
f.Bool("shellcode-compress", false, "Enable shellcode compression (aPLib) (windows, macOS, and Linux shellcode)")
353354
f.Uint32("shellcode-exitopt", 1, "Shellcode exit option (Donut: 1=exit thread, 2=exit process, 3=block) (windows shellcode only)")
354355
f.Uint32("shellcode-bypass", 3, "Shellcode bypass mode (Donut: 1=none, 2=abort, 3=continue) (windows shellcode only)")
355356
f.Uint32("shellcode-headers", 1, "Shellcode headers handling (Donut: 1=overwrite, 2=keep) (windows shellcode only)")

client/command/generate/generate.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ var (
8080
"darwin/arm64": true,
8181
"linux/386": true,
8282
"linux/amd64": true,
83+
"linux/arm64": true,
8384
"windows/386": true,
8485
"windows/amd64": true,
8586
}
@@ -394,12 +395,25 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
394395
return "", nil
395396
}
396397
if configFormat == clientpb.OutputFormat_SHELLCODE {
397-
if targetOS != "windows" && targetOS != "darwin" {
398-
con.PrintErrorf("Shellcode format is currently only supported on Windows and macOS\n")
399-
return "", nil
400-
}
401-
if targetOS == "darwin" && targetArch != "arm64" {
402-
con.PrintErrorf("macOS shellcode format is only supported on darwin/arm64\n")
398+
switch targetOS {
399+
case "windows":
400+
// Server-side implementation supports amd64 and 386 only.
401+
if targetArch != "amd64" && targetArch != "386" {
402+
con.PrintErrorf("Windows shellcode format is only supported on windows/amd64 and windows/386\n")
403+
return "", nil
404+
}
405+
case "darwin":
406+
if targetArch != "arm64" {
407+
con.PrintErrorf("macOS shellcode format is only supported on darwin/arm64\n")
408+
return "", nil
409+
}
410+
case "linux":
411+
if targetArch != "amd64" && targetArch != "arm64" {
412+
con.PrintErrorf("Linux shellcode format is only supported on linux/amd64 and linux/arm64\n")
413+
return "", nil
414+
}
415+
default:
416+
con.PrintErrorf("Shellcode format is currently only supported on Windows, macOS, and Linux\n")
403417
return "", nil
404418
}
405419
}
@@ -585,14 +599,22 @@ func parseShellcodeFlags(cmd *cobra.Command, targetOS string, configFormat clien
585599
cmd.Flags().Changed("donut-unicode") ||
586600
cmd.Flags().Changed("donut-oep")
587601

588-
// macOS shellcode currently only supports compression.
602+
// macOS and Linux shellcode currently only support compression.
589603
if targetOS != "windows" {
590-
if targetOS == "darwin" {
591-
if windowsOnlyChanged {
604+
if targetOS != "darwin" && targetOS != "linux" {
605+
// parseCompileFlags normally blocks this, but keep a safe fallback.
606+
if anyChanged {
607+
con.PrintWarnf("Shellcode options are only supported on Windows, macOS, and Linux shellcode, ignoring.\n")
608+
}
609+
return nil, nil
610+
}
611+
612+
if windowsOnlyChanged {
613+
if targetOS == "darwin" {
592614
con.PrintWarnf("Windows-only shellcode options are ignored on macOS shellcode.\n")
615+
} else {
616+
con.PrintWarnf("Windows-only shellcode options are ignored on Linux shellcode.\n")
593617
}
594-
} else if anyChanged {
595-
con.PrintWarnf("Shellcode options are only supported on Windows and macOS shellcode, ignoring.\n")
596618
}
597619

598620
shellcodeCompress := uint32(1)

client/command/help/long-help.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ You can also stack the C2 configuration with multiple protocols:
190190
191191
[[.Bold]][[.Underline]]++ Formats ++[[.Normal]]
192192
Supported output formats include Windows PE, Windows DLL, Windows shellcode, macOS Mach-O, macOS shellcode (arm64),
193-
and Linux ELF. The output format is controlled with the --os and --format flags.
193+
Linux ELF, and Linux shellcode (amd64/arm64). The output format is controlled with the --os and --format flags.
194194
195195
To output a 64bit Windows PE file (defaults to WinPE/64bit), either of the following command would be used:
196196
generate --mtls foo.example.com
@@ -209,7 +209,7 @@ To output a Linux ELF executable file, the following command would be used:
209209
[[.Bold]][[.Underline]]++ Shellcode Options ++[[.Normal]]
210210
When generating shellcode (--format shellcode), you can tune the shellcode generator:
211211
--shellcode-encoder <name|none> # Apply a shellcode encoder (see: shellcode-encoders)
212-
--shellcode-compress # Enable aPLib compression (windows and macOS)
212+
--shellcode-compress # Enable aPLib compression (windows, macOS, and Linux)
213213
--shellcode-entropy 1|2|3 # (windows only) Entropy: 1=none (default), 2=random names, 3=random+encrypt
214214
--shellcode-exitopt 1|2|3 # (windows only) Exit behavior: 1=exit thread (default), 2=exit process, 3=block
215215
--shellcode-bypass 1|2|3 # (windows only) Bypass: 1=none, 2=abort on failure, 3=continue (default)
@@ -218,6 +218,8 @@ When generating shellcode (--format shellcode), you can tune the shellcode gener
218218
--shellcode-unicode # (windows only) Unmanaged DLL: pass Unicode command line
219219
--shellcode-oep <uint32> # (windows only) Override original entry point (0=default)
220220
221+
Note: macOS and Linux shellcode currently only support --shellcode-compress; other options are Windows-only.
222+
221223
222224
[[.Bold]][[.Underline]]++ DNS Canaries ++[[.Normal]]
223225
DNS canaries are unique per-binary domains that are deliberately NOT obfuscated during the compilation process.

client/forms/generate_profiles_new.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func GenerateProfilesNewForm() (*GenerateProfilesNewFormResult, error) {
6060
case "linux":
6161
return []huh.Option[string]{
6262
huh.NewOption("amd64", "amd64"),
63+
huh.NewOption("arm64", "arm64"),
6364
huh.NewOption("386", "386"),
6465
}
6566
default:
@@ -83,6 +84,8 @@ func GenerateProfilesNewForm() (*GenerateProfilesNewFormResult, error) {
8384
huh.NewOption("Service", "service"),
8485
huh.NewOption("Shellcode", "shellcode"),
8586
)
87+
} else if result.OS == "darwin" || result.OS == "linux" {
88+
options = append(options, huh.NewOption("Shellcode", "shellcode"))
8689
}
8790
return options
8891
}, &result.OS).

client/forms/generate_profiles_new_beacon.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ func GenerateProfilesNewBeaconForm() (*GenerateProfilesNewBeaconFormResult, erro
6565
case "linux":
6666
return []huh.Option[string]{
6767
huh.NewOption("amd64", "amd64"),
68+
huh.NewOption("arm64", "arm64"),
6869
huh.NewOption("386", "386"),
6970
}
7071
default:
@@ -88,6 +89,8 @@ func GenerateProfilesNewBeaconForm() (*GenerateProfilesNewBeaconFormResult, erro
8889
huh.NewOption("Service", "service"),
8990
huh.NewOption("Shellcode", "shellcode"),
9091
)
92+
} else if result.OS == "darwin" || result.OS == "linux" {
93+
options = append(options, huh.NewOption("Shellcode", "shellcode"))
9194
}
9295
return options
9396
}, &result.OS).

client/forms/generate_targets.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func commonArchOptions(goos string) []huh.Option[string] {
4444
case "linux":
4545
return []huh.Option[string]{
4646
huh.NewOption("amd64", "amd64"),
47+
huh.NewOption("arm64", "arm64"),
4748
huh.NewOption("386", "386"),
4849
}
4950
default:
@@ -66,6 +67,8 @@ func commonFormatOptions(goos string) []huh.Option[string] {
6667
)
6768
} else if goos == "darwin" {
6869
options = append(options, huh.NewOption("Shellcode", "shellcode"))
70+
} else if goos == "linux" {
71+
options = append(options, huh.NewOption("Shellcode", "shellcode"))
6972
}
7073
return options
7174
}

client/packages/output.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
package packages
22

3+
/*
4+
Sliver Implant Framework
5+
Copyright (C) 2024 Bishop Fox
6+
7+
This program is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
321
import (
422
"encoding/json"
523
"fmt"
@@ -10,23 +28,6 @@ import (
1028
"github.com/jedib0t/go-pretty/v6/table"
1129
)
1230

13-
/*
14-
Sliver Implant Framework
15-
Copyright (C) 2024 Bishop Fox
16-
17-
This program is free software: you can redistribute it and/or modify
18-
it under the terms of the GNU General Public License as published by
19-
the Free Software Foundation, either version 3 of the License, or
20-
(at your option) any later version.
21-
22-
This program is distributed in the hope that it will be useful,
23-
but WITHOUT ANY WARRANTY; without even the implied warranty of
24-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25-
GNU General Public License for more details.
26-
27-
You should have received a copy of the GNU General Public License
28-
along with this program. If not, see <https://www.gnu.org/licenses/>.
29-
*/
3031
const (
3132
KeyValueSchemaName = "key-value"
3233
GroupedKeyValueSchemaName = "grouped-key-value"

docs/sliver-docs/pages/docs/md/Cross-compiling Implants.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
**NOTE:** Any platform can cross-compile a standalone executable to any other platform out of the box; you only need cross-compilers when using `--format shared`.
1+
**NOTE:** Any platform can cross-compile a standalone executable to any other platform out of the box; you primarily need cross-compilers when using CGO-based formats like `--format shared`, and for `--format shellcode` on macOS/Linux.
22

33
Sliver can tell you which platforms it can likely target based on the server's platform and available cross-compilers by running the `generate info` command in the console.
44

@@ -37,7 +37,7 @@ Sliver automatically looks in the default paths for these cross-compilers; once
3737

3838
## From MacOS to Linux/Windows
3939

40-
Sliver embeds a Zig cross-compiler out of the box, so Windows DLLs and Linux shared objects do not require mingw-w64 or musl-cross.
40+
Sliver embeds a Zig cross-compiler out of the box, so Windows DLLs and Linux shared objects/shellcode do not require mingw-w64 or musl-cross.
4141

4242
However, we're not aware of any good options to target 32-bit Linux from MacOS. Sliver automatically looks in the default paths for these cross-compilers; once installed simply use the `generate` command with the desired `--os` and `--arch`, check `~/.sliver/logs/sliver.log` for build errors. You can override any cross-compiler location via the appropriate [environment variables](/docs?name=Environment+Variables).
4343

docs/sliver-docs/pages/docs/md/External Builders.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ sliver > builders
4747
=============================== ========== =========== ============== ==========================
4848
molochs-MacBook-Pro-111.local moloch sliver darwin/arm64 EXECUTABLE:linux/386
4949
EXECUTABLE:linux/amd64
50+
EXECUTABLE:linux/arm64
5051
EXECUTABLE:windows/386
5152
EXECUTABLE:windows/amd64
5253
EXECUTABLE:darwin/amd64
@@ -56,10 +57,14 @@ sliver > builders
5657
SHARED_LIB:darwin/amd64
5758
SHARED_LIB:darwin/arm64
5859
SHARED_LIB:linux/amd64
60+
SHARED_LIB:linux/arm64
5961
SERVICE:windows/386
6062
SERVICE:windows/amd64
6163
SHELLCODE:windows/386
6264
SHELLCODE:windows/amd64
65+
SHELLCODE:darwin/arm64
66+
SHELLCODE:linux/amd64
67+
SHELLCODE:linux/arm64
6368
```
6469

6570
Use the `--external-builder` flag to offload a `generate` or `generate beacon` command onto an external builder:

docs/sliver-docs/pages/docs/md/Stagers.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
**⚠️ Important:** You must have MinGW installed on your Sliver server to get some staged (e.g., Windows DLLs) payloads to work.
1+
**⚠️ Important:** Some staged payloads require a working cross-compiler toolchain on the Sliver server (especially shared libraries and non-native targets). Sliver bundles a Zig toolchain for many Windows/Linux targets, but macOS shared library/shellcode builds require osxcross.
22

33
## Overview
44

@@ -33,23 +33,35 @@ Name Platform Command & Control Debug Format
3333
win-shellcode windows/amd64 [1] mtls://192.168.122.1:8888 false SHELLCODE enabled
3434
```
3535

36-
You can tune shellcode options for shellcode profiles (Windows: Donut):
36+
Shellcode generation varies by platform:
3737

38-
- `--shellcode-entropy`: 1=none, 2=random names, 3=random+encrypt
39-
- `--shellcode-compress`: enable/disable aPLib compression (boolean)
40-
- `--shellcode-exitopt`: 1=exit thread, 2=exit process, 3=block
41-
- `--shellcode-bypass`: 1=none, 2=abort on failure, 3=continue
42-
- `--shellcode-headers`: 1=overwrite, 2=keep
43-
- `--shellcode-thread`: run unmanaged EXE entrypoint as a new thread (boolean)
44-
- `--shellcode-unicode`: pass Unicode command line to unmanaged DLL entrypoints (boolean)
45-
- `--shellcode-oep`: override original entry point (uint32, 0=default)
38+
- Windows shellcode uses Donut and supports all shellcode tuning flags below.
39+
- macOS (darwin/arm64) and Linux (amd64/arm64) shellcode currently only support `--shellcode-compress`; other `--shellcode-*` options are Windows-only.
40+
41+
Shellcode options:
42+
43+
- `--shellcode-encoder`: apply an optional shellcode encoder (see: `shellcode-encoders`)
44+
- `--shellcode-compress`: enable/disable aPLib compression (boolean) (Windows, macOS, Linux)
45+
- `--shellcode-entropy`: 1=none, 2=random names, 3=random+encrypt (Windows only)
46+
- `--shellcode-exitopt`: 1=exit thread, 2=exit process, 3=block (Windows only)
47+
- `--shellcode-bypass`: 1=none, 2=abort on failure, 3=continue (Windows only)
48+
- `--shellcode-headers`: 1=overwrite, 2=keep (Windows only)
49+
- `--shellcode-thread`: run unmanaged EXE entrypoint as a new thread (boolean) (Windows only)
50+
- `--shellcode-unicode`: pass Unicode command line to unmanaged DLL entrypoints (boolean) (Windows only)
51+
- `--shellcode-oep`: override original entry point (uint32, 0=default) (Windows only)
4652

4753
Example:
4854

4955
```
5056
sliver > profiles new --mtls 192.168.122.1 --format shellcode --shellcode-entropy 2 --shellcode-compress --shellcode-exitopt 3 win-shellcode
5157
```
5258

59+
Linux example (compression only):
60+
61+
```
62+
sliver > profiles new --os linux --arch amd64 --mtls 192.168.122.1 --format shellcode --shellcode-compress linux-shellcode
63+
```
64+
5365
We can now create a staging listener and link it to the profile:
5466

5567
```

0 commit comments

Comments
 (0)