Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions GetWebDAVStatus_BOF/GetWebDAVStatus.cna
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# GetWebDAVStatus.cna
# CNA author @nickvourd

beacon_command_register(
"GetWebDAVStatus",
"Determine if the WebClient Service (WebDAV) is running on remote systems",
"Synopsis: GetWebDAVStatus <target1> [target2] [target3] ...\n\n" .
"Usage: GetWebDAVStatus <target> [additional targets...]\n\n" .
"Description:\n" .
" Checks if the WebClient service (WebDAV) is running on one or more\n" .
" remote systems by attempting to connect to the DAV RPC SERVICE pipe.\n\n" .
"Arguments:\n" .
" target IP address or hostname of the remote system(s)\n" .
" Multiple targets can be specified separated by spaces\n\n" .
"Examples:\n" .
" GetWebDAVStatus 192.168.1.100\n" .
" GetWebDAVStatus dc01.domain.local\n" .
" GetWebDAVStatus dc01 ws01 srv01\n" .
" GetWebDAVStatus 192.168.1.10 192.168.1.20 192.168.1.30",
"bof"
);

alias GetWebDAVStatus {
local('$bid $handle $data $arg_data $i $target $numTargets');

$bid = $1;

# Check if we have at least one target
if (size(@_) < 2) {
berror($bid, "Specify at least one ip or hostname");
berror($bid, "Usage: GetWebDAVStatus <target1> [target2] [target3] ...");
return;
}

# Read in the right BOF file
$handle = openf(script_resource("GetWebDAVStatus." . barch($bid) . ".o"));
$data = readb($handle, -1);
closef($handle);

if (strlen($data) == 0) {
berror($bid, "Could not load BOF file: GetWebDAVStatus." . barch($bid) . ".o");
return;
}

# Calculate number of targets
$numTargets = size(@_) - 1;

# Pack: first the count (i), then each target as wide string (Z)
$arg_data = bof_pack($bid, "i", $numTargets);

for ($i = 1; $i < size(@_); $i++) {
$target = @_[$i];
if ($target ne "") {
$arg_data = $arg_data . bof_pack($bid, "Z", $target);
}
}

btask($bid, "GetWebDAVStatus BOF by @G0ldenGunSec && @nickvourd");
btask($bid, "Checking WebDAV status on $numTargets host(s)...");

beacon_inline_execute($bid, $data, "go", $arg_data);
}
Binary file added GetWebDAVStatus_BOF/GetWebDAVStatus.x64.o
Binary file not shown.
Binary file added GetWebDAVStatus_BOF/GetWebDAVStatus.x86.o
Binary file not shown.
Binary file removed GetWebDAVStatus_BOF/GetWebDAVStatus_x64.o
Binary file not shown.
2 changes: 2 additions & 0 deletions GetWebDAVStatus_BOF/GetWebDavStatus-Checksum.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GetWebDAVStatus.x64.o B8ED7B5C95EC7511D4CE307550BA0305
GetWebDAVStatus.x86.o 49C859A3FF0D7E18E01576075A934899
117 changes: 117 additions & 0 deletions GetWebDAVStatus_BOF/Source/GetWebDAVStatus.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include <windows.h>
#include "beacon.h"

WINBASEAPI BOOL WINAPI KERNEL32$WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut);
WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap(void);
WINBASEAPI LPVOID WINAPI KERNEL32$HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
WINBASEAPI BOOL WINAPI KERNEL32$HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);

void go(char* args, int length)
{
datap parser;
wchar_t* host = NULL;
wchar_t* fullPipeName = NULL;
BOOL pipeStatus = 0;
HANDLE hHeap = NULL;
int totalHosts = 0;
int enabledCount = 0;
int disabledCount = 0;
int hostLen = 0;
int i = 0;
int numHosts = 0;

BeaconDataParse(&parser, args, length);
hHeap = KERNEL32$GetProcessHeap();

// First argument is the number of hosts
numHosts = BeaconDataInt(&parser);

if (numHosts <= 0)
{
BeaconPrintf(CALLBACK_ERROR, "[!] No targets specified");
return;
}

BeaconPrintf(CALLBACK_OUTPUT, "=== GetWebDAVStatus Check ===\n");

for (totalHosts = 0; totalHosts < numHosts; totalHosts++)
{
host = (wchar_t*)BeaconDataExtract(&parser, NULL);

if (host == NULL || host[0] == L'\0')
{
break;
}

// Calculate length manually
hostLen = 0;
while (host[hostLen] != L'\0')
{
hostLen++;
}

// Allocate buffer for full pipe name
// \\host\pipe\DAV RPC SERVICE = 2 + hostLen + 21 + 1
fullPipeName = (wchar_t*)KERNEL32$HeapAlloc(hHeap, HEAP_ZERO_MEMORY, (2 + hostLen + 21 + 1) * sizeof(wchar_t));

if (fullPipeName == NULL)
{
BeaconPrintf(CALLBACK_ERROR, "[!] Memory allocation failed for %S", host);
continue;
}

// Build pipe name manually
// Copy "\\\\"
fullPipeName[0] = L'\\';
fullPipeName[1] = L'\\';

// Copy host
for (i = 0; i < hostLen; i++)
{
fullPipeName[2 + i] = host[i];
}

// Copy "\\pipe\\DAV RPC SERVICE"
fullPipeName[2 + hostLen] = L'\\';
fullPipeName[3 + hostLen] = L'p';
fullPipeName[4 + hostLen] = L'i';
fullPipeName[5 + hostLen] = L'p';
fullPipeName[6 + hostLen] = L'e';
fullPipeName[7 + hostLen] = L'\\';
fullPipeName[8 + hostLen] = L'D';
fullPipeName[9 + hostLen] = L'A';
fullPipeName[10 + hostLen] = L'V';
fullPipeName[11 + hostLen] = L' ';
fullPipeName[12 + hostLen] = L'R';
fullPipeName[13 + hostLen] = L'P';
fullPipeName[14 + hostLen] = L'C';
fullPipeName[15 + hostLen] = L' ';
fullPipeName[16 + hostLen] = L'S';
fullPipeName[17 + hostLen] = L'E';
fullPipeName[18 + hostLen] = L'R';
fullPipeName[19 + hostLen] = L'V';
fullPipeName[20 + hostLen] = L'I';
fullPipeName[21 + hostLen] = L'C';
fullPipeName[22 + hostLen] = L'E';
fullPipeName[23 + hostLen] = L'\0';

pipeStatus = KERNEL32$WaitNamedPipeW(fullPipeName, 3000);

if (pipeStatus == 0)
{
BeaconPrintf(CALLBACK_OUTPUT, "[-] %S - WebClient NOT running or unreachable", host);
disabledCount++;
}
else
{
BeaconPrintf(CALLBACK_OUTPUT, "[+] %S - WebClient ENABLED", host);
enabledCount++;
}

KERNEL32$HeapFree(hHeap, 0, fullPipeName);
fullPipeName = NULL;
}

BeaconPrintf(CALLBACK_OUTPUT, "\n[*] Summary: %d hosts checked, %d enabled, %d disabled/unreachable",
totalHosts, enabledCount, disabledCount);
}
19 changes: 19 additions & 0 deletions GetWebDAVStatus_BOF/Source/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
SRC = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRC))
CC_x86 := i686-w64-mingw32-gcc
CC_x64 := x86_64-w64-mingw32-gcc
STRIP_x86 := i686-w64-mingw32-strip
STRIP_x64 := x86_64-w64-mingw32-strip
CFLAGS := -masm=intel

all: $(OBJS)

%.o: %.c
$(CC_x64) $(CFLAGS) -o ../$*.x64.o -c $<
$(STRIP_x64) --strip-unneeded ../$*.x64.o

$(CC_x86) $(CFLAGS) -o ../$*.x86.o -DWOW64 -fno-leading-underscore -c $<
$(STRIP_x86) --strip-unneeded ../$*.x86.o

clean:
rm ../*.o
File renamed without changes.
38 changes: 0 additions & 38 deletions GetWebDAVStatus_BOF/src/Source.c

This file was deleted.

14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@
Small project to determine if the Web Client service (WebDAV) is running on a remote system by checking for the presence of the DAV RPC SERVICE named pipe. Does not require admin privileges on the remote system, but does require some form of valid credentials (no anonymous access). Both a BOF and C# version of the project are included, the C# version is multi-threaded so would be better suited for scanning a large number of systems.

## Usage
Both the BOF and C# versions take a comma-seperated list of systems to scan. The C# version also has an optional arg of "--tc" that allows the operator to control the max amount of threads to be used (default: 5).
The C# versions take a comma-seperated list of systems to scan. The C# version also has an optional arg of "--tc" that allows the operator to control the max amount of threads to be used (default: 5). The BOF vesrion take only one argument.

BOF: `inline-execute C:\scripts\GetWebDAVStatus_x64.o server01,server02`
BOF: `GetWebDAVStatus server01 dc01 ws01 192.168.1.55 ca.domain.local`

C#: `execute-assembly C:\assemblies\GetWebDAVStatus.exe server01,server02 --tc 1`

## Building
The C# project should be a pretty standard build, x64 + Release is the recommended build configuration. BOF can be built with the following command from the Developer Command Prompt for VS:
The C# project should be a pretty standard build, x64 + Release is the recommended build configuration. BOF can be built with the following command from the Makefile:

`cl.exe /c /GS- Source.c /Fo./GetWebDAVStatus_x64.o`
`make`

Prerequisites for compiling the BOF:
- i686-w64-mingw32-gcc
- x86_64-w64-mingw32-gcc

## Credits
[@tifkin_](https://twitter.com/tifkin_) originally posted about this method of remotely identifying WebDAV [here](https://twitter.com/tifkin_/status/1419806476353298442).

Special thanks to [@nickvourd](https://twitter.com/nickvourd) for his contributions.

Originally heard about the above tweet on [@flangvik](https://twitter.com/Flangvik)'s [twitch stream](https://www.twitch.tv/flangvik). Would definitely recommend checking out.