Removed old files and cleaned up git files

This commit is contained in:
Ne0nd0g
2021-04-18 10:51:53 -04:00
parent aef1da0036
commit a1143c68c2
4 changed files with 1 additions and 369 deletions
+1 -4
View File
@@ -1,5 +1,2 @@
*.go linguist-language=Go
*.json linguist-language=Javascript
vendor/* linguist-vendored
docs/* linguist-documentation
data/bin/powershell/Invoke-Merlin.ps1 linguist-detectable=false
docs/* linguist-documentation
-5
View File
@@ -1,10 +1,5 @@
.DS_STORE
data/agents
data/temp
data/db
data/log
data/bin/darwin
data/bin/dll/merlin.dll
data/bin/linux
data/bin/windows
.idea/
Binary file not shown.
-360
View File
@@ -1,360 +0,0 @@
// Merlin is a post-exploitation command and control framework.
// This file is part of Merlin.
// Copyright (C) 2021 Russel Van Tuyl
// Merlin is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
// Merlin is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Merlin. If not, see <http://www.gnu.org/licenses/>.
package testserver
import (
// Standard
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/gob"
"fmt"
"io/ioutil"
"log"
"math/big"
"net"
"net/http"
"strings"
"testing"
"time"
// 3rd Party
"github.com/cretz/gopaque/gopaque"
"github.com/satori/go.uuid"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
// Merlin
"github.com/Ne0nd0g/merlin/pkg/agents"
"github.com/Ne0nd0g/merlin/pkg/core"
"github.com/Ne0nd0g/merlin/pkg/handlers"
"github.com/Ne0nd0g/merlin/pkg/messages"
"github.com/Ne0nd0g/merlin/pkg/opaque"
"github.com/Ne0nd0g/merlin/pkg/server/jobs"
)
func (ts *TestServer) handler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet && r.RequestURI == "/isup" {
w.WriteHeader(200)
return
}
// Uses Merlin HTTP Handler
if r.RequestURI == "/merlin" {
ts.ctx.AgentHTTP(w, r)
}
// Make sure the message has a JWT
token := r.Header.Get("Authorization")
if token == "" {
fmt.Println("the request did not contain an Authorization header")
w.WriteHeader(404)
return
}
//Read the request message until EOF
requestBytes, errRequestBytes := ioutil.ReadAll(r.Body)
if errRequestBytes != nil {
fmt.Printf("there was an error reading the request message:\r\n%s\r\n", errRequestBytes.Error())
w.WriteHeader(500)
return
}
// Decode gob to JWE string
var jweString string
errDecode := gob.NewDecoder(bytes.NewReader(requestBytes)).Decode(&jweString)
if errDecode != nil {
fmt.Printf("there was an error decoding the message from gob to JWE string:\r\n%s\r\n", errDecode.Error())
w.WriteHeader(500)
return
}
// Validate JWT and get claims
var agentID uuid.UUID
var errValidate error
agentID, errValidate = validateJWT(strings.Split(token, " ")[1], []byte("xZF7fvaGD6p2yeLyf9i7O9gBBHk05B0u"))
if errValidate != nil {
// Validate JWT using interface PSK; Used by unauthenticated agents
hashedKey := sha256.Sum256([]byte("test"))
key := hashedKey[:]
agentID, errValidate = validateJWT(strings.Split(token, " ")[1], key)
if errValidate != nil {
fmt.Printf("there was an error validating the JWT:\n%s\n", errValidate)
w.WriteHeader(404)
return
}
}
key, errKey := agents.GetEncryptionKey(agentID)
if errKey != nil {
fmt.Printf("there was an error getting the Agent's decryption key:\n%s\n", errKey)
// Use the default key when the agent isn't registered
k := sha256.Sum256([]byte("test"))
key = k[:]
}
// Decrypt JWE
j, errDecryptPSK := decryptJWE(jweString, key)
if errDecryptPSK != nil {
fmt.Printf("there was an error decrypting the JWE on the server:\r\n%s\r\n", errDecryptPSK.Error())
w.WriteHeader(500)
return
}
//fmt.Println(fmt.Sprintf("Request: %+v\nBody:%+v", r, j)) //uncomment here if you want to print out exactly what the test server receives
var returnMessage messages.Base
var err error
// User Agent based actions
switch r.UserAgent() {
case "invalidMessageBaseType":
returnMessage.Type = 200
}
// Message type based action
switch j.Type {
case messages.JOBS:
returnMessage, err = jobs.Handler(j)
case messages.OPAQUE:
if j.Payload.(opaque.Opaque).Type == opaque.AuthComplete {
returnMessage, err = handlers.OPAQUEHandler(j.ID, j.Payload.(opaque.Opaque))
} else {
returnMessage, err = handlers.OPAQUEUnAuthHandler(j.ID, j.Payload.(opaque.Opaque), gopaque.CryptoDefault.NewKey(nil))
}
case 201:
w.Header().Set("Content-Type", "application/octet-stream")
errBadPayload := gob.NewEncoder(w).Encode([]byte("Hack the planet!"))
if errBadPayload != nil {
fmt.Println(errBadPayload.Error())
}
default:
}
if err != nil {
log.Fatal(err)
}
returnMessage.ID = agentID
// Encode messages.Base into a gob
returnMessageBytes := new(bytes.Buffer)
errReturnMessageBytes := gob.NewEncoder(returnMessageBytes).Encode(returnMessage)
if errReturnMessageBytes != nil {
fmt.Printf("there was an error encoding the return message into a gob:\r\n%s\r\n", errReturnMessageBytes.Error())
w.WriteHeader(500)
return
}
// Get JWE
jwe, errJWE := core.GetJWESymetric(returnMessageBytes.Bytes(), key[:])
if errJWE != nil {
fmt.Printf("there was an error encrypting the message into a JWE:\r\n%s\r\n", errJWE.Error())
w.WriteHeader(500)
return
}
// Encode JWE to GOB and send it to the agent
w.Header().Set("Content-Type", "application/octet-stream")
errEncode := gob.NewEncoder(w).Encode(jwe)
if errEncode != nil {
fmt.Printf("there was an error encoding the JWE into a gob:\r\n%s\r\n", errEncode.Error())
w.WriteHeader(500)
return
}
}
//TestServer is a webserver instance that facilitates functional testing of code that requires the ability to send web requests
type TestServer struct {
tes *testing.T
ctx handlers.HTTPContext
}
//since tls/pki is such a pain this generate them every time
func generateTLSConfig() *tls.Config {
//https://golang.org/src/crypto/tls/generate_cert.go taken from here mostly
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
log.Fatalf("failed to generate serial number: %s", err)
}
tpl := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: "127.0.0.1",
Organization: []string{"Joey is the best hacker in Hackers"},
},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)},
DNSNames: []string{"127.0.0.1", "localhost"},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Minute * 20),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
crtBytes, e := x509.CreateCertificate(rand.Reader, &tpl, &tpl, priv.Public(), priv)
if e != nil {
panic(e)
}
crt := tls.Certificate{
Certificate: [][]byte{crtBytes},
PrivateKey: priv,
}
/* #nosec G402 */
// G402: TLS InsecureSkipVerify set true. (Confidence: HIGH, Severity: HIGH) Allowed for testing
// G402 (CWE-295): TLS MinVersion too low. (Confidence: HIGH, Severity: HIGH)
// TLS version is not configured to facilitate dynamic JA3 configurations
return &tls.Config{
Certificates: []tls.Certificate{crt},
NextProtos: []string{"h2", "hq"},
}
}
//Start starts the test HTTP server on the input port
func (TestServer) Start(port string, finishedTest, setup chan struct{}, t *testing.T) {
s := http.NewServeMux()
ts := TestServer{
tes: t,
}
s.HandleFunc("/", ts.handler)
srv := http.Server{}
srv.TLSConfig = generateTLSConfig()
srv.Handler = s
srv.Addr = "127.0.0.1:" + port
ctx := handlers.HTTPContext{
PSK: "test",
JWTKey: []byte(core.RandStringBytesMaskImprSrc(32)),
OpaqueKey: gopaque.CryptoDefault.NewKey(nil),
}
ts.ctx = ctx
go func() {
ln, e := net.Listen("tcp", srv.Addr)
defer func() {
err := ln.Close()
if err != nil {
log.Fatal(err)
}
}()
if e != nil {
panic(e)
}
tlsListener := tls.NewListener(ln, srv.TLSConfig)
e = srv.Serve(tlsListener)
if e != nil { //should be set by the tls config
panic(e)
}
}()
for {
time.Sleep(time.Second * 1)
/* #nosec G402 */
// G402: TLS InsecureSkipVerify set true. (Confidence: HIGH, Severity: HIGH) Allowed for testing
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
resp, err := client.Get("https://localhost:" + port + "/isup")
if err != nil {
continue
}
errC := resp.Body.Close()
if errC != nil {
log.Fatalf("There was an error closing the body:\r\n%s", errC)
}
if resp.StatusCode != http.StatusOK {
continue
}
// Reached this point: server is up and running!
break
}
close(setup)
<-finishedTest //this is an ultra gross hack :(
}
// decryptJWE takes provided JWE string and decrypts it using the per-agent key
func decryptJWE(jweString string, key []byte) (messages.Base, error) {
var m messages.Base
// Parse JWE string back into JSONWebEncryption
jwe, errObject := jose.ParseEncrypted(jweString)
if errObject != nil {
return m, fmt.Errorf("there was an error parseing the JWE string into a JSONWebEncryption object:\r\n%s", errObject)
}
// Decrypt the JWE
jweMessage, errDecrypt := jwe.Decrypt(key)
if errDecrypt != nil {
return m, fmt.Errorf("there was an error decrypting the JWE:\r\n%s", errDecrypt.Error())
}
// Decode the JWE payload into a messages.Base struct
errDecode := gob.NewDecoder(bytes.NewReader(jweMessage)).Decode(&m)
if errDecode != nil {
return m, fmt.Errorf("there was an error decoding JWE payload message sent by an agent:\r\n%s", errDecode.Error())
}
return m, nil
}
// validateJWT validates the provided JSON Web Token
func validateJWT(agentJWT string, key []byte) (uuid.UUID, error) {
var agentID uuid.UUID
claims := jwt.Claims{}
// Parse to make sure it is a valid JWT
nestedToken, err := jwt.ParseSignedAndEncrypted(agentJWT)
if err != nil {
return agentID, fmt.Errorf("there was an error parsing the JWT:\r\n%s", err.Error())
}
// Decrypt JWT
token, errToken := nestedToken.Decrypt(key)
if errToken != nil {
return agentID, fmt.Errorf("there was an error decrypting the JWT:\r\n%s", errToken.Error())
}
// Deserialize the claims and validate the signature
errClaims := token.Claims(key, &claims)
if errClaims != nil {
return agentID, fmt.Errorf("there was an deserializing the JWT claims:\r\n%s", errClaims.Error())
}
// Validate claims
errValidate := claims.Validate(jwt.Expected{
Time: time.Now(),
})
if errValidate != nil {
return agentID, errValidate
}
agentID = uuid.FromStringOrNil(claims.ID)
return agentID, nil
}