github.com/iDigitalFlame/xmt@v0.5.4/c2/z_no_implant.go (about) 1 //go:build !implant 2 // +build !implant 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package c2 21 22 import ( 23 "io" 24 "time" 25 26 "github.com/PurpleSec/escape" 27 "github.com/iDigitalFlame/xmt/com" 28 "github.com/iDigitalFlame/xmt/data" 29 "github.com/iDigitalFlame/xmt/device" 30 "github.com/iDigitalFlame/xmt/device/local/tags" 31 "github.com/iDigitalFlame/xmt/util" 32 ) 33 34 const maxEvents = 2048 35 36 type stringer interface { 37 String() string 38 } 39 40 func (*Server) close() {} 41 func (s *Server) count() int { 42 return len(s.events) 43 } 44 func formatBool(b bool) string { 45 if b { 46 return "true" 47 } 48 return "false" 49 } 50 func (s *Session) name() string { 51 return s.ID.String() 52 } 53 func (s status) String() string { 54 switch s { 55 case StatusError: 56 return "error" 57 case StatusWaiting: 58 return "waiting" 59 case StatusAccepted: 60 return "accepted" 61 case StatusCanceled: 62 return "canceled" 63 case StatusReceiving: 64 return "receiving" 65 case StatusCompleted: 66 return "completed" 67 } 68 return "invalid" 69 } 70 71 // String returns the details of this Session as a string. 72 func (s *Session) String() string { 73 switch { 74 case s.IsClient() && s.sleep == 0: 75 return "[" + s.ID.String() + "] -> " + s.host.String() + " " + s.Last.Format(time.RFC1123) 76 case s.IsClient() && (s.jitter == 0 || s.jitter > 100): 77 return "[" + s.ID.String() + "] " + s.sleep.String() + " -> " + s.host.String() 78 case s.IsClient(): 79 return "[" + s.ID.String() + "] " + s.sleep.String() + "/" + util.Uitoa(uint64(s.jitter)) + "% -> " + s.host.String() 80 case !s.IsClient() && (s.jitter == 0 || s.jitter > 100): 81 return "[" + s.ID.String() + "] " + s.sleep.String() + " -> " + s.host.String() + " " + s.Last.Format(time.RFC1123) 82 } 83 return "[" + s.ID.String() + "] " + s.sleep.String() + "/" + util.Uitoa(uint64(s.jitter)) + "% -> " + s.host.String() + " " + s.Last.Format(time.RFC1123) 84 } 85 86 // JSON returns the data of this Job as a JSON blob. 87 func (j *Job) JSON(w io.Writer) error { 88 if j == nil { 89 _, err := w.Write([]byte(`{}`)) 90 return err 91 } 92 if _, err := w.Write([]byte(`{"id":` + util.Uitoa(uint64(j.ID)) + `,` + 93 `"type":` + util.Uitoa(uint64(j.Type)) + `,` + 94 `"error":` + escape.JSON(j.Error) + `,` + 95 `"status":"` + j.Status.String() + `",` + 96 `"start":"` + j.Start.Format(time.RFC3339) + `"`, 97 )); err != nil { 98 return err 99 } 100 if j.s != nil && !j.s.ID.Empty() { 101 if _, err := w.Write([]byte(`,"host":"` + j.s.ID.String() + `"`)); err != nil { 102 return err 103 } 104 } 105 if !j.Complete.IsZero() { 106 if _, err := w.Write([]byte(`,"complete":"` + j.Complete.Format(time.RFC3339) + `"`)); err != nil { 107 return err 108 } 109 } 110 if j.Result != nil { 111 if _, err := w.Write([]byte(`,"result":` + util.Uitoa(uint64(j.Result.Size())))); err != nil { 112 return err 113 } 114 } 115 _, err := w.Write([]byte{'}'}) 116 return err 117 } 118 119 // JSON returns the data of this Server as a JSON blob. 120 func (s *Server) JSON(w io.Writer) error { 121 if _, err := w.Write([]byte(`{"listeners":{`)); err != nil { 122 return err 123 } 124 i := 0 125 for k, v := range s.active { 126 if i > 0 { 127 if _, err := w.Write([]byte{','}); err != nil { 128 return err 129 } 130 } 131 if _, err := w.Write([]byte(escape.JSON(k) + `:`)); err != nil { 132 return err 133 } 134 if err := v.JSON(w); err != nil { 135 return err 136 } 137 i++ 138 } 139 i = 0 140 if _, err := w.Write([]byte(`},"sessions":[`)); err != nil { 141 return err 142 } 143 s.lock.RLock() 144 for _, v := range s.sessions { 145 if i > 0 { 146 if _, err := w.Write([]byte{','}); err != nil { 147 s.lock.RUnlock() 148 return err 149 } 150 } 151 if err := v.JSON(w); err != nil { 152 s.lock.RUnlock() 153 return err 154 } 155 i++ 156 } 157 s.lock.RUnlock() 158 _, err := w.Write([]byte(`]}`)) 159 return err 160 } 161 func (l *Listener) oneshot(n *com.Packet) { 162 if l.s == nil || l.s.Oneshot == nil { 163 n.Clear() 164 return 165 } 166 l.m.queue(event{p: n, pf: l.s.Oneshot}) 167 } 168 169 // JSON returns the data of this Session as a JSON blob. 170 func (s *Session) JSON(w io.Writer) error { 171 if _, err := w.Write([]byte(`{` + 172 `"id":"` + s.ID.String() + `",` + 173 `"hash":"` + util.Uitoa(uint64(s.ID.Hash())) + `",` + 174 `"channel":` + formatBool(s.InChannel()) + `,` + 175 `"device":{` + 176 `"id":"` + s.ID.Full() + `",` + 177 `"user":` + escape.JSON(s.Device.User) + `,` + 178 `"hostname":` + escape.JSON(s.Device.Hostname) + `,` + 179 `"version":` + escape.JSON(s.Device.Version) + `,` + 180 `"arch":"` + s.Device.Arch().String() + `",` + 181 `"os":` + escape.JSON(s.Device.OS().String()) + `,` + 182 `"elevated":` + formatBool(s.Device.IsElevated()) + `,` + 183 `"capabilities":"` + tags.ParseCapabilities(s.Device.OS() == device.Windows, s.Device.Capabilities) + `",` + 184 `"domain":` + formatBool(s.Device.IsDomainJoined()) + `,` + 185 `"pid":` + util.Uitoa(uint64(s.Device.PID)) + `,` + 186 `"ppid":` + util.Uitoa(uint64(s.Device.PPID)) + `,` + 187 `"network":[`, 188 )); err != nil { 189 return err 190 } 191 for i := range s.Device.Network { 192 if i > 0 { 193 if _, err := w.Write([]byte{','}); err != nil { 194 return err 195 } 196 } 197 if _, err := w.Write([]byte( 198 `{"name":` + escape.JSON(s.Device.Network[i].Name) + `,` + 199 `"mac":"` + s.Device.Network[i].Mac.String() + `","ip":[`, 200 )); err != nil { 201 return err 202 } 203 for x := range s.Device.Network[i].Address { 204 if x > 0 { 205 if _, err := w.Write([]byte{','}); err != nil { 206 return err 207 } 208 } 209 if _, err := w.Write([]byte(`"` + s.Device.Network[i].Address[x].String() + `"`)); err != nil { 210 return err 211 } 212 } 213 if _, err := w.Write([]byte("]}")); err != nil { 214 return err 215 } 216 } 217 _, err := w.Write([]byte( 218 `]},"created":"` + s.Created.Format(time.RFC3339) + `",` + 219 `"last":"` + s.Last.Format(time.RFC3339) + `",` + 220 `"via":` + escape.JSON(s.host.String()) + `,` + 221 `"sleep":` + util.Uitoa(uint64(s.sleep)) + `,` + 222 `"jitter":` + util.Uitoa(uint64(s.jitter)) + `,`, 223 )) 224 if err != nil { 225 return err 226 } 227 if s.kill.IsZero() { 228 _, err = w.Write([]byte(`"kill_date":"",`)) 229 } else { 230 _, err = w.Write([]byte(`"kill_date":"` + s.kill.Format(time.RFC3339) + `",`)) 231 } 232 if err != nil { 233 return err 234 } 235 if s.work != nil { 236 _, err = w.Write([]byte( 237 `"work_hours":{"start_hour":` + util.Uitoa(uint64(s.work.StartHour)) + `,` + 238 `"start_min":` + util.Uitoa(uint64(s.work.StartMin)) + `,` + 239 `"end_hour":` + util.Uitoa(uint64(s.work.EndHour)) + `,` + 240 `"end_min":` + util.Uitoa(uint64(s.work.EndMin)) + `,` + 241 `"days":"` + s.work.String() + `"}`, 242 )) 243 } else { 244 _, err = w.Write([]byte(`"work_hours":{}`)) 245 } 246 if err != nil { 247 return err 248 } 249 if s.parent != nil { 250 if _, err = w.Write([]byte(`,"connector_name":` + escape.JSON(s.parent.name))); err != nil { 251 return err 252 } 253 } 254 if t, ok := s.parent.listener.(stringer); ok { 255 if _, err = w.Write([]byte(`,"connector":` + escape.JSON(t.String()))); err != nil { 256 return err 257 } 258 } 259 if !s.IsClient() && len(s.proxies) > 0 { 260 if _, err = w.Write([]byte(`,"proxy":[`)); err != nil { 261 return err 262 } 263 for i := range s.proxies { 264 if i > 0 { 265 if _, err = w.Write([]byte{','}); err != nil { 266 return err 267 } 268 } 269 _, err = w.Write([]byte( 270 `{"name":` + escape.JSON(s.proxies[i].n) + `,"address": ` + escape.JSON(s.proxies[i].b) + `}`, 271 )) 272 if err != nil { 273 return err 274 } 275 } 276 if _, err = w.Write([]byte{']'}); err != nil { 277 return err 278 } 279 } 280 _, err = w.Write([]byte{'}'}) 281 return err 282 } 283 284 // JSON returns the data of this Listener as a JSON blob. 285 func (l *Listener) JSON(w io.Writer) error { 286 if _, err := w.Write([]byte(`{"name":` + escape.JSON(l.name) + `,"address":` + escape.JSON(l.Address()))); err != nil { 287 return err 288 } 289 var n uint64 290 if len(l.s.sessions) > 0 { 291 l.s.lock.RLock() 292 for _, s := range l.s.sessions { 293 if s.parent == l { 294 n++ 295 } 296 } 297 l.s.lock.RUnlock() 298 } 299 if _, err := w.Write([]byte(`,"count":` + util.Uitoa(uint64(n)))); err != nil { 300 return err 301 } 302 if t, ok := l.listener.(stringer); ok { 303 if _, err := w.Write([]byte(`,"type":` + escape.JSON(t.String()))); err != nil { 304 return err 305 } 306 } 307 _, err := w.Write([]byte(`}`)) 308 return err 309 } 310 311 // MarshalJSON fulfils the JSON Marshaler interface. 312 func (j *Job) MarshalJSON() ([]byte, error) { 313 b := buffers.Get().(*data.Chunk) 314 j.JSON(b) 315 d := b.Payload() 316 returnBuffer(b) 317 return d, nil 318 } 319 320 // MarshalJSON fulfils the JSON Marshaler interface. 321 func (s *Server) MarshalJSON() ([]byte, error) { 322 b := buffers.Get().(*data.Chunk) 323 s.JSON(b) 324 d := b.Payload() 325 returnBuffer(b) 326 return d, nil 327 } 328 329 // MarshalJSON fulfils the JSON Marshaler interface. 330 func (s *Session) MarshalJSON() ([]byte, error) { 331 b := buffers.Get().(*data.Chunk) 332 s.JSON(b) 333 d := b.Payload() 334 returnBuffer(b) 335 return d, nil 336 } 337 338 // MarshalJSON fulfils the JSON Marshaler interface. 339 func (l *Listener) MarshalJSON() ([]byte, error) { 340 b := buffers.Get().(*data.Chunk) 341 l.JSON(b) 342 d := b.Payload() 343 returnBuffer(b) 344 return d, nil 345 }