├── compile.sh ├── xpipe.o ├── xpipe.png ├── xpipe.cna ├── LICENSE.md ├── beacon.h ├── README.md └── xpipe.c /compile.sh: -------------------------------------------------------------------------------- 1 | x86_64-w64-mingw32-gcc xpipe.c -c -o xpipe.o -Os 2 | -------------------------------------------------------------------------------- /xpipe.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/xPipe/HEAD/xpipe.o -------------------------------------------------------------------------------- /xpipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boku7/xPipe/HEAD/xpipe.png -------------------------------------------------------------------------------- /xpipe.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "xpipe", 3 | "List pipes and get their DACL permissions", 4 | "Synopsis: xpipe \\\\.\\pipe\\atsvc" 5 | ); 6 | 7 | alias xpipe { 8 | if(size(@_) == 1) 9 | { 10 | $2 = "L" 11 | } 12 | if(size(@_) >= 3) 13 | { 14 | berror($1, "Incorrect usage!"); 15 | berror($1, beacon_command_detail("xpipe")); 16 | return; 17 | } 18 | local('$handle $data $args'); 19 | $handle = openf(script_resource("xpipe.o")); 20 | $data = readb($handle, -1); 21 | closef($handle); 22 | $args = bof_pack($1, "z",$2); 23 | btask($1, "xpipe (IBM X-Force Red|Bobby Cooke|@0xBoku)"); 24 | beacon_inline_execute($1, $data, "go", $args); 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bobby Cooke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char* original; /* the original buffer [so we can free it] */ 13 | char* buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap* parser, char* buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap* parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap* parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap* parser); 22 | DECLSPEC_IMPORT char* BeaconDataExtract(datap* parser, int* size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char* original; /* the original buffer [so we can free it] */ 27 | char* buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp* format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp* format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp* format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp* format, char* text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp* format, char* fmt, ...); 37 | DECLSPEC_IMPORT char* BeaconFormatToString(formatp* format, int* size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp* format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char* fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char* data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char* buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char* arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION* pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char* src, wchar_t* dst, int max); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xPipe Cobalt Strike BOF (x64) 2 | Cobalt Strike Beacon Object File (BOF) to list active Pipes & return their Owner & Discretionary Access Control List (DACL) permissions. 3 | 4 | ![](/xpipe.png) 5 | 6 | https://github.com/xforcered/xPipe & https://github.com/boku7/xPipe 7 | ## Usage 8 | ### List All Local Active Pipes 9 | To list all the pipes, simply run the `xpipe` command from Cobalt Strikes interactive beacon console after importing the `xpipe.cna` aggressor script. 10 | ``` 11 | beacon> xpipe 12 | [*] xpipe (IBM X-Force Red|Bobby Cooke|@0xBoku) 13 | \\.\pipe\InitShutdown 14 | \\.\pipe\lsass 15 | \\.\pipe\ntsvcs 16 | \\.\pipe\scerpc 17 | \\.\pipe\atsvc 18 | ++ 19 | ``` 20 | 21 | ### Show Pipe Owner & DACL Permissions 22 | To show the Owner & DACL permissions of a pipe, simply supply the pipe name as the first argument to the `xpipe` command. 23 | + If you lack permissions to query the pipe, the BOF will timeout after 5 seconds and return thread control to the operator. 24 | ``` 25 | beacon> xpipe \\.\pipe\lsass 26 | [*] xpipe (IBM X-Force Red|Bobby Cooke|@0xBoku) 27 | Pipe: \\.\pipe\lsass 28 | Owner: Administrators\BUILTIN 29 | Everyone 30 | + SYNCHRONIZE 31 | + READ_CONTROL 32 | + FILE_WRITE_DATA 33 | + FILE_READ_DATA 34 | + FILE_WRITE_ATTRIBUTES 35 | + FILE_READ_ATTRIBUTES 36 | ANONYMOUS LOGON\NT AUTHORITY 37 | + SYNCHRONIZE 38 | ++ 39 | ``` 40 | 41 | ## Compile with x64 MinGW: 42 | ```bash 43 | x86_64-w64-mingw32-gcc xpipe.c -c -o xpipe.o -Os 44 | ``` 45 | + Only tested from macOS 46 | 47 | ## Why I Created This? 48 | Recently I have been exploring C2 channels using SMB/pipes and also dabbling in privilege escalation research. To better understand how windows pipes worked, I decided to create some projects. I personally find that getting my hands dirty with the windows APIs, debugging, and tinkering is the best way I learn. 49 | 50 | ## To Do's 51 | + For pipes which we don't have access to query, the BOF will just timeout after 5 seconds. Create error handler which checks if access was denied and return error code to operator. As of now it will just timeout after 5 seconds and return nothing. 52 | + Code cleanup, make sure there are no leaks and handles are closed, etc. 53 | + Update the `pipelist()` function use the same CS beacon print formatting as the `getPipeACL()` function. Its cleaner and less prone to errors. 54 | 55 | ## Detection & Mitigation 56 | This BOF is for situational awareness. It does not perform any malicious behavior as of December 7th 2021. For detecting pipe enumeration for threat actors in their enumeration phase, it may be possible to detect attempts to query all named pipes which exist within `\\.\pipe\*`. 57 | 58 | ## Credits & References 59 | #### Cobalt Strike BOF Code Projects 60 | + [trustedsec/CS-Situational-Awareness-BOF/src/SA/cacls/](https://github.com/trustedsec/CS-Situational-Awareness-BOF/blob/master/src/SA/cacls/entry.c) 61 | + The code for the `getPipeACL()` function is derived from TrustedSecs awesome work from the CACL BOF project. 62 | + [EspressoCake/HandleKatz_BOF](https://github.com/EspressoCake/HandleKatz_BOF) 63 | + This project taught me how to use Cobalt Strikes beacon output formatting APIs and output text to beacon with `BeaconOutput()`. This is great because it makes the text display in the CS GUI so much cleaner. The code to make this happen is pulled from this project. 64 | #### Malware Dev Skill References 65 | + [Sektor7 Malware Dev Essentials course](https://institute.sektor7.net/red-team-operator-malware-development-essentials) 66 | + [OxDarkVortex Blogs](https://0xdarkvortex.dev/blogs/) 67 | + [Brute Ratel Blogs](https://bruteratel.com/blog/) 68 | #### DACL Permissions Code Projects & References 69 | + [microsoft/Windows-classic-samples/SecPrint.c](https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/security/authorization/secprint/SecPrint.c) 70 | + [fasterthanlime/share.c](https://gist.github.com/fasterthanlime/ea38871666bc7cc486c272650523c9e1) 71 | + [Microsoft Developer Documentation](https://docs.microsoft.com/en-us/windows/win32/api/winbase/) 72 | + StackOverFlow - Sorry I can't find references to add. LMK and I will add them here 73 | #### Pipe Code Projects 74 | + [Mark Russinovich - Sysinternals pipelist & accesscheck](https://docs.microsoft.com/en-us/sysinternals/) 75 | + This BOF pretty much does the same thing as `pipelist.exe`. I used `pipelist` while developing to make sure I was getting the correct listing of named pipes. 76 | + `accesscheck.exe -lv` will query the permissions of the named pipes like this BOF will. 77 | + Decoder's Blog / Project - Windows Named Pipes & Impersonation 78 | + [GitHub PowerShell Project](https://github.com/decoder-it/pipeserverimpersonate) 79 | + [PowerShell Pipe Blog](https://decoder.cloud/2019/03/06/windows-named-pipes-impersonation/) 80 | + [peter-bloomfield/win32-named-pipes-example](https://github.com/peter-bloomfield/win32-named-pipes-example) 81 | #### Cobalt Strike - How to Develop a BOF 82 | ##### Raphael Mudge - Beacon Object Files - Luser Demo 83 | + https://www.youtube.com/watch?v=gfYswA_Ronw 84 | ##### Cobalt Strike - Beacon Object Files 85 | + https://www.cobaltstrike.com/help-beacon-object-files 86 | -------------------------------------------------------------------------------- /xpipe.c: -------------------------------------------------------------------------------- 1 | // IBM X-Force Red|Bobby Cooke|@0xBoku | https://github.com/xforcered/xPipe & https://github.com/boku7/xPipe 2 | // Allot of code is pulled or derived from github.com/trustedsec/CS-Situational-Awareness-BOF & github.com/EspressoCake/HandleKatz_BOF 3 | #include 4 | #include "beacon.h" 5 | 6 | #define FileDirectoryInformation 1 7 | #define STATUS_NO_MORE_FILES 0x80000006L 8 | #define STATUS_BUFFER_OVERFLOW 0x80000005L 9 | #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L 10 | #define SE_FILE_OBJECT 1 11 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 12 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle( HANDLE hObject); 13 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap(); 14 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); 15 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$HeapFree(HANDLE, DWORD, PVOID); 16 | DECLSPEC_IMPORT void* __cdecl MSVCRT$memcpy(LPVOID, LPVOID, size_t); 17 | DECLSPEC_IMPORT void __cdecl MSVCRT$memset(void*, int, size_t); 18 | WINBASEAPI FARPROC WINAPI KERNEL32$GetProcAddress (HMODULE hModule, LPCSTR lpProcName); 19 | WINBASEAPI HMODULE WINAPI KERNEL32$LoadLibraryA(LPCSTR lpLibFileName); 20 | WINBASEAPI LPWSTR WINAPI KERNEL32$lstrcatW( LPWSTR lpString1, LPCWSTR lpString2); 21 | WINBASEAPI HANDLE WINAPI KERNEL32$CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 22 | WINBASEAPI DWORD WINAPI KERNEL32$GetLastError (VOID); 23 | WINBASEAPI VOID WINAPI KERNEL32$SetLastError (DWORD dwErrCode); 24 | WINBASEAPI VOID WINAPI KERNEL32$Sleep (DWORD dwMilliseconds); 25 | WINBASEAPI WINBOOL WINAPI KERNEL32$CloseHandle (HANDLE hObject); 26 | WINADVAPI DWORD WINAPI ADVAPI32$GetSecurityInfo(HANDLE handle, int ObjectType, SECURITY_INFORMATION SecurityInfo, PSID *ppsidOwner, PSID *ppsidGroup, PACL *ppDacl, PACL *ppSacl, PSECURITY_DESCRIPTOR *ppSecurityDescriptor); 27 | WINADVAPI WINBOOL WINAPI ADVAPI32$LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); 28 | WINADVAPI WINBOOL WINAPI ADVAPI32$GetFileSecurityW (LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded); 29 | WINADVAPI WINBOOL WINAPI ADVAPI32$GetAce (PACL pAcl, DWORD dwAceIndex, LPVOID *pAce); 30 | WINADVAPI WINBOOL WINAPI ADVAPI32$GetSecurityDescriptorDacl (PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, LPBOOL lpbDaclDefaulted); 31 | WINBASEAPI size_t __cdecl MSVCRT$strlen(const char *_Str); 32 | #define intAlloc(size) KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, size) 33 | #define intFree(addr) KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, addr) 34 | 35 | typedef struct { LONG Status; ULONG Information; } IO_STATUS_BLOCK; 36 | typedef struct _FILE_DIRECTORY_INFORMATION { 37 | ULONG NextEntryOffset; 38 | ULONG FileIndex; 39 | LARGE_INTEGER CreationTime; 40 | LARGE_INTEGER LastAccessTime; 41 | LARGE_INTEGER LastWriteTime; 42 | LARGE_INTEGER ChangeTime; 43 | LARGE_INTEGER EndOfFile; 44 | LARGE_INTEGER AllocationSize; 45 | ULONG FileAttributes; 46 | ULONG FileNameLength; 47 | WCHAR FileName[1]; 48 | } FILE_DIRECTORY_INFORMATION, * PFILE_DIRECTORY_INFORMATION; 49 | typedef LONG (NTAPI * NtQueryDirectoryFile_t)(HANDLE, HANDLE, PVOID, PVOID, IO_STATUS_BLOCK*, PVOID, ULONG, UINT, BOOL, LPVOID, BOOL); 50 | 51 | void getPipeACL(wchar_t * pipeName){ 52 | formatp stringFormatObject; // Cobalt Strike beacon format object we will pass strings too 53 | BeaconFormatAlloc(&stringFormatObject, 64 * 1024); // allocate memory for our string blob 54 | DWORD dwRtnCode = 0; 55 | PSID pOwnerSid, pGroupSid = NULL; // used to return the owner of the pipe 56 | BOOL bRtnBool = TRUE; 57 | LPWSTR AcctName = NULL; 58 | LPWSTR DomainName = NULL; 59 | DWORD dwAcctName = 1, dwDomainName = 1; 60 | SID_NAME_USE eUse = SidTypeUnknown; 61 | PSECURITY_DESCRIPTOR pSD = NULL; 62 | PACL file_dacl = NULL; 63 | PSECURITY_DESCRIPTOR SecurityDescriptor; 64 | DWORD SDSize = 0; 65 | SecurityDescriptor = (PSECURITY_DESCRIPTOR)intAlloc(SDSize); // allocate memory for the security descriptor we will get for the pipe 66 | PACL Dacl; 67 | BOOL DaclPresent; 68 | BOOL DaclDefaulted; 69 | BOOL Error = FALSE, Ret = FALSE; 70 | 71 | // Get handle to named pipe 72 | HANDLE hPipe = NULL; 73 | BeaconFormatPrintf(&stringFormatObject,"Pipe: %ls\n",pipeName); 74 | hPipe = KERNEL32$CreateFileW( 75 | pipeName, 76 | GENERIC_READ, 77 | FILE_SHARE_READ, 78 | NULL, 79 | OPEN_EXISTING, 80 | FILE_ATTRIBUTE_NORMAL, 81 | NULL); 82 | 83 | // Get the owner SID of the file. 84 | ADVAPI32$GetSecurityInfo( 85 | hPipe, 86 | SE_FILE_OBJECT, 87 | OWNER_SECURITY_INFORMATION, 88 | &pOwnerSid, 89 | NULL, 90 | NULL, 91 | NULL, 92 | &pSD); 93 | 94 | // First call to LookupAccountSid to get the buffer sizes. 95 | ADVAPI32$LookupAccountSidW( 96 | NULL, // local computer 97 | pOwnerSid, 98 | AcctName, 99 | (LPDWORD)&dwAcctName, 100 | DomainName, 101 | (LPDWORD)&dwDomainName, 102 | &eUse); 103 | 104 | // Reallocate memory for the buffers. 105 | AcctName = (LPWSTR)intAlloc((dwAcctName+2) * 2); 106 | DomainName = (LPWSTR)intAlloc((dwDomainName+2) * 2); 107 | 108 | // Second call to LookupAccountSid to get the account name. 109 | ADVAPI32$LookupAccountSidW( 110 | NULL, // name of local or remote computer 111 | pOwnerSid, // security identifier 112 | AcctName, // account name buffer 113 | (LPDWORD)&dwAcctName, // size of account name buffer 114 | DomainName, // domain name 115 | (LPDWORD)&dwDomainName, // size of domain name buffer 116 | &eUse // SID type 117 | ); 118 | BeaconFormatPrintf(&stringFormatObject,"Owner: %ls\\%ls\n", AcctName, DomainName); 119 | KERNEL32$CloseHandle(hPipe); 120 | intFree(AcctName); 121 | intFree(DomainName); 122 | // find out how much memory we need 123 | BOOL success = FALSE; 124 | DWORD timeout = 0; // 5 second timeout 125 | // Wait for handle to open up if it is busy from the last GetFileSecurityW call above 126 | //BeaconPrintf(CALLBACK_OUTPUT,"timeout before 1: %d",timeout); 127 | while (SDSize == 0 && timeout < 20) { 128 | //BeaconPrintf(CALLBACK_OUTPUT,"SDSize: %d | timeout: %d",SDSize,timeout); 129 | success = ADVAPI32$GetFileSecurityW(pipeName, DACL_SECURITY_INFORMATION, NULL, 0, &SDSize); 130 | KERNEL32$Sleep(100); 131 | timeout++; 132 | } 133 | //BeaconPrintf(CALLBACK_OUTPUT,"timeout after 1: %d",timeout); 134 | if (!success && KERNEL32$GetLastError() != ERROR_INSUFFICIENT_BUFFER) 135 | { 136 | return; 137 | } 138 | SecurityDescriptor = (PSECURITY_DESCRIPTOR)intAlloc(SDSize); 139 | if (SecurityDescriptor != NULL) 140 | { 141 | //if (ADVAPI32$GetFileSecurityW(pipeName, DACL_SECURITY_INFORMATION, SecurityDescriptor, SDSize, &SDSize)) 142 | success = FALSE; 143 | timeout = 0; // 5 second timeout 144 | // Wait for handle to open up if it is busy from the last GetFileSecurityW call above 145 | //BeaconPrintf(CALLBACK_OUTPUT,"timeout before 2: %d",timeout); 146 | while (success != TRUE && timeout < 50) { 147 | success = ADVAPI32$GetFileSecurityW(pipeName, DACL_SECURITY_INFORMATION, SecurityDescriptor, SDSize, &SDSize); 148 | KERNEL32$Sleep(100); 149 | timeout++; 150 | } 151 | //BeaconPrintf(CALLBACK_OUTPUT,"timeout after 2: %d",timeout); 152 | if (success) 153 | { 154 | if (ADVAPI32$GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted)) 155 | { 156 | if (DaclPresent) 157 | { 158 | PACCESS_ALLOWED_ACE Ace; 159 | DWORD AceIndex = 0; 160 | // dump the ACL 161 | while (ADVAPI32$GetAce(Dacl, AceIndex, (PVOID*)&Ace)) 162 | { 163 | SID_NAME_USE Use; 164 | DWORD NameSize = 0; 165 | DWORD DomainSize = 0; 166 | LPWSTR Name = NULL; 167 | LPWSTR Domain = NULL; 168 | DWORD IndentAccess = 0; 169 | 170 | DWORD AccessMask = Ace->Mask; 171 | PSID Sid = (PSID)&Ace->SidStart; 172 | if (!ADVAPI32$LookupAccountSidW(NULL, 173 | Sid, 174 | Name, 175 | &NameSize, 176 | Domain, 177 | &DomainSize, 178 | &Use)) 179 | { 180 | if (KERNEL32$GetLastError() != ERROR_INSUFFICIENT_BUFFER) 181 | { 182 | Error = TRUE; 183 | break; 184 | } 185 | Name = (LPWSTR)intAlloc((NameSize + DomainSize) * 2); 186 | if (Name == NULL) 187 | { 188 | KERNEL32$SetLastError(ERROR_NOT_ENOUGH_MEMORY); 189 | Error = TRUE; 190 | break; 191 | } 192 | Domain = Name + NameSize; 193 | Name[0] = L'\0'; 194 | if (DomainSize != 0) 195 | Domain[0] = L'\0'; 196 | if (ADVAPI32$LookupAccountSidW(NULL, 197 | Sid, 198 | Name, 199 | &NameSize, 200 | Domain, 201 | &DomainSize, 202 | &Use)) 203 | { 204 | if (Domain[0] == 0x00){ 205 | BeaconFormatPrintf(&stringFormatObject,"%ls\n",Name); 206 | } 207 | else { 208 | BeaconFormatPrintf(&stringFormatObject,"%ls\\%ls\n",Name,Domain); 209 | } 210 | } 211 | intFree(Name); 212 | Name = NULL; 213 | Domain = NULL; 214 | } 215 | // The access mask of the ACE will have a bunch of bits set. For each bit that is set, it maps to a permission 216 | // FILE_ALL_ACCESS #define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) 217 | if (Ace->Mask == 0x1f01ff) 218 | { 219 | BeaconFormatPrintf(&stringFormatObject," + FILE_ALL_ACCESS\n"); 220 | } 221 | else { 222 | // SYNCHRONIZE #define SYNCHRONIZE (0x00100000L) 223 | if (Ace->Mask & 0x100000) 224 | { 225 | BeaconFormatPrintf(&stringFormatObject," + SYNCHRONIZE\n"); 226 | } 227 | // READ_CONTROL = 0x00020000L // for example if the 17th bit is set in the ACE mask, then the user has READ_CONTROL rights on this pipe 228 | if (Ace->Mask & 0x20000) 229 | { 230 | BeaconFormatPrintf(&stringFormatObject," + READ_CONTROL\n"); 231 | } 232 | // FILE_WRITE_DATA ( 0x0002 ) // file & pipe // winnt.h // AKA FILE_ADD_FILE 233 | if (Ace->Mask & 0x2) 234 | { 235 | BeaconFormatPrintf(&stringFormatObject," + FILE_WRITE_DATA\n"); 236 | } 237 | // FILE_READ_DATA ( 0x0001 ) bit1 set // file & pipe // AKA FILE_LIST_DIRECTORY 238 | if (Ace->Mask & 0x1) 239 | { 240 | BeaconFormatPrintf(&stringFormatObject," + FILE_READ_DATA\n"); 241 | } 242 | // FILE_CREATE_PIPE_INSTANCE(0x0004) bit3 set // named pipe // aka FILE_ADD_SUBDIRECTORY 243 | if (Ace->Mask & 0x4) 244 | { 245 | BeaconFormatPrintf(&stringFormatObject," + FILE_CREATE_PIPE_INSTANCE\n"); 246 | } 247 | // FILE_WRITE_ATTRIBUTES ( 0x0100 ) bit9 set // all 248 | if (Ace->Mask & 0x100) 249 | { 250 | BeaconFormatPrintf(&stringFormatObject," + FILE_WRITE_ATTRIBUTES\n"); 251 | } 252 | // FILE_READ_ATTRIBUTES ( 0x0080 ) bit8 set // all 253 | if (Ace->Mask & 0x80) 254 | { 255 | BeaconFormatPrintf(&stringFormatObject," + FILE_READ_ATTRIBUTES\n"); 256 | } 257 | } 258 | AceIndex++; 259 | } 260 | } 261 | } 262 | } 263 | intFree(SecurityDescriptor); 264 | SecurityDescriptor = NULL; 265 | } 266 | int sizeOfObject = 0; 267 | char* outputString = NULL; 268 | outputString = BeaconFormatToString(&stringFormatObject, &sizeOfObject); 269 | BeaconOutput(CALLBACK_OUTPUT, outputString, sizeOfObject); 270 | BeaconFormatFree(&stringFormatObject); 271 | } 272 | 273 | void pipelist(){ 274 | LONG ntStatus; 275 | IO_STATUS_BLOCK IoStatusBlock; 276 | HANDLE hPipe; 277 | BOOL RestartScan = TRUE; 278 | PFILE_DIRECTORY_INFORMATION dir_info, pipe_info; 279 | NtQueryDirectoryFile_t NtQueryDirectoryFile = (NtQueryDirectoryFile_t)KERNEL32$GetProcAddress(KERNEL32$LoadLibraryA("ntdll.dll"),"NtQueryDirectoryFile"); 280 | hPipe = KERNEL32$CreateFileA("\\\\.\\Pipe\\", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); 281 | if (hPipe == INVALID_HANDLE_VALUE){ return;} 282 | unsigned __int64 qwSize = 0x1000; 283 | LPVOID buffer = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), 0, qwSize); 284 | MSVCRT$memset(buffer, 0x00, qwSize); 285 | dir_info = (PFILE_DIRECTORY_INFORMATION)buffer; 286 | size_t output_size = 0x100000; // Allocate a big amount of memory in the heap write the pipe names too 287 | LPVOID output = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), 0, output_size); 288 | MSVCRT$memset(output, 0x00, output_size); 289 | char* outptr = (char*)output; // This keeps track of our position as we write the pipe names to the big buffer we allocated in the heap 290 | unsigned __int64 overflowChk = 0; // check that we are not writing into unallocated memory to prevent beacon from crashing. 291 | BOOL flag = 0; 292 | while (1){ // This loop enumerates the directories that pipes are in. The second loop prints the pipes in the directory. On next 1st loop, we enumerate the next dir holding pipes 293 | ntStatus = NtQueryDirectoryFile(hPipe, NULL, NULL, NULL, &IoStatusBlock, dir_info, qwSize, FileDirectoryInformation, FALSE, NULL, RestartScan); 294 | if (ntStatus != NO_ERROR) { 295 | // If we need more memory we increase the size and reallocate 296 | if (ntStatus == STATUS_BUFFER_OVERFLOW || ntStatus == STATUS_INFO_LENGTH_MISMATCH) { 297 | KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, buffer); 298 | qwSize *= 2; 299 | buffer = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), 0, qwSize); 300 | } 301 | // If there are no more directories holding pipes to enumerate then we exit the 1st loop and print pipes 302 | else if (ntStatus == STATUS_NO_MORE_FILES) { break; } 303 | else { return; } 304 | } 305 | pipe_info = dir_info; 306 | while (1){ // This loop prints all pipes located in the current directory we are enumerating 307 | outptr += 18; 308 | outptr += pipe_info->FileNameLength; 309 | overflowChk = (unsigned __int64)outptr - (unsigned __int64)output; // make sure we don't crash beacon 310 | if (overflowChk > output_size) { break; } 311 | KERNEL32$lstrcatW((wchar_t *)output, L"\\\\.\\pipe\\"); 312 | KERNEL32$lstrcatW((wchar_t *)output, pipe_info->FileName); 313 | outptr[0] = 0x0A; // After the pipe name we put a \n so pipes will print as a list 314 | outptr[1] = 0x00; // These are to make sure we dont get bad characters as we concatinate all the pipes together 315 | outptr[2] = 0x00; 316 | outptr[3] = 0x00; 317 | outptr += 2; // move to the next character after the \n we wrote. (2 because a single unicode character in windows is 2 bytes) 318 | if (pipe_info->NextEntryOffset == 0){ break; } 319 | pipe_info = (PFILE_DIRECTORY_INFORMATION)((char*)pipe_info + pipe_info->NextEntryOffset); 320 | } 321 | if (overflowChk > output_size) { flag = 1; break; } 322 | RestartScan = FALSE; // This double while loop is: Loop1 = Directory, Loop 2 = Pipes in Directory 323 | } 324 | // Print all the pipes in one go 325 | BeaconPrintf(CALLBACK_OUTPUT,"%ls", (wchar_t*)output); 326 | // Error message - If this happens you got quite allot of pipes. This is mainly here in the event that does happen so beacon doesn't crash 327 | // If you get this, then increase the size of the `output_size` variable and recompile 328 | if (flag == 1){ BeaconPrintf(CALLBACK_ERROR,"\n[!] Buffer to small. Truncating pipelist and exiting..\n"); } 329 | // Cleanup - free heaps & close handle 330 | MSVCRT$memset(output, 0x00, output_size); // overwrite the heaps with 0x00's so there is no leftover strings after heap is free 331 | MSVCRT$memset(buffer, 0x00, qwSize); 332 | KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, output); 333 | KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, buffer); 334 | KERNEL32$CloseHandle(hPipe); 335 | } 336 | 337 | void go(char * args, int len) { 338 | datap parser; 339 | char * pipeName = NULL; 340 | wchar_t * wPipeName = NULL; 341 | size_t pipeNameLen = 0; 342 | BeaconDataParse(&parser, args, len); 343 | pipeName = BeaconDataExtract(&parser, NULL); 344 | //BeaconPrintf(CALLBACK_OUTPUT,"pipeName: %s", pipeName); 345 | if (pipeName[0] == 'L'){ 346 | pipelist(); 347 | return; 348 | }else{ 349 | pipeNameLen = MSVCRT$strlen(pipeName); 350 | pipeNameLen = pipeNameLen*2+4; 351 | wPipeName = (wchar_t *)intAlloc(pipeNameLen); 352 | toWideChar(pipeName,wPipeName,pipeNameLen); // Convert the ASCII pipe name from beacon to a Unicode pipe name 353 | getPipeACL(wPipeName); 354 | } 355 | } 356 | --------------------------------------------------------------------------------