github.com/iDigitalFlame/xmt@v0.5.4/c2/session_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 "sync" 24 "time" 25 26 "github.com/iDigitalFlame/xmt/c2/cfg" 27 "github.com/iDigitalFlame/xmt/c2/cout" 28 "github.com/iDigitalFlame/xmt/c2/task" 29 "github.com/iDigitalFlame/xmt/com" 30 "github.com/iDigitalFlame/xmt/data" 31 "github.com/iDigitalFlame/xmt/device" 32 "github.com/iDigitalFlame/xmt/util" 33 "github.com/iDigitalFlame/xmt/util/xerr" 34 ) 35 36 // ErrNoTask is returned from some functions that return Jobs. This will 37 // be returned when the Job object will be nil due to the fact the function 38 // was called on the client-side instead of the server-side. 39 // 40 // This is more of an informational message than an error, as this does NOT 41 // indicate that the function failed, but that the Job object should NOT be 42 // used as it is nil. (In case the Job object is not checked.) 43 var ErrNoTask = xerr.Sub("no Job created for client Session", 0x58) 44 45 // Session is a struct that represents a connection between the client and the 46 // Listener. 47 // 48 // This struct does some automatic handling and acts as the communication 49 // channel between the client and server. 50 type Session struct { 51 connection 52 kill time.Time 53 54 Last time.Time 55 Created time.Time 56 swap cfg.Profile 57 58 Receive func(*Session, *com.Packet) 59 jobs map[uint16]*Job 60 parent *Listener 61 send, recv, chn chan *com.Packet 62 frags map[uint16]*cluster 63 ch chan struct{} 64 65 Shutdown func(*Session) 66 keysNext *data.KeyPair 67 proxy *proxyBase 68 tick *sleeper 69 peek *com.Packet 70 wake chan struct{} 71 work *cfg.WorkHours 72 host container 73 proxies []proxyData 74 75 Device device.Machine 76 sleep time.Duration 77 lock sync.RWMutex 78 state state 79 keys data.KeyPair 80 81 ID device.ID 82 jitter, errors uint8 83 } 84 85 // Jobs returns all current Jobs for this Session. 86 // 87 // This returns nil if there are no Jobs or this Session does not have the 88 // ability to schedule them. 89 func (s *Session) Jobs() []*Job { 90 if s.jobs == nil || len(s.jobs) == 0 { 91 return nil 92 } 93 s.lock.RLock() 94 r := make([]*Job, 0, len(s.jobs)) 95 for _, j := range s.jobs { 96 r = append(r, j) 97 } 98 s.lock.RUnlock() 99 return r 100 } 101 102 // IsClient returns true when this Session is not associated to a Listener on 103 // this end, which signifies that this session is Client initiated, or we are 104 // on a client device. 105 func (s *Session) IsClient() bool { 106 return s.parent == nil && s.s == nil 107 } 108 func (s *Session) accept(i uint16) { 109 if i < 2 || s.parent == nil || s.jobs == nil || len(s.jobs) == 0 { 110 return 111 } 112 s.lock.RLock() 113 j, ok := s.jobs[i] 114 if s.lock.RUnlock(); !ok { 115 return 116 } 117 if j.Status = StatusAccepted; j.Update != nil { 118 s.m.queue(event{j: j, jf: j.Update}) 119 } 120 if cout.Enabled { 121 s.log.Trace("[%s] Set JobID %d to accepted.", s.ID, i) 122 } 123 } 124 func (s *Session) newJobID() uint16 { 125 var ( 126 ok bool 127 i, c uint16 128 ) 129 s.lock.RLock() 130 for ; c < 512; c++ { 131 i = uint16(util.FastRand()) 132 if _, ok = s.jobs[i]; !ok && i > 1 { 133 s.lock.RUnlock() 134 return i 135 } 136 } 137 s.lock.RUnlock() 138 return 0 139 } 140 141 // Job returns a Job with the associated ID, if it exists. It returns nil 142 // otherwise. 143 func (s *Session) Job(i uint16) *Job { 144 if i < 2 || s.jobs == nil || len(s.jobs) == 0 { 145 return nil 146 } 147 s.lock.RLock() 148 j := s.jobs[i] 149 s.lock.RUnlock() 150 return j 151 } 152 153 // Listener will return the Listener that created the Session. This will return 154 // nil if the session is not on the server side. 155 func (s *Session) Listener() *Listener { 156 return s.parent 157 } 158 func (s *Session) hasJob(j uint16) bool { 159 // There's no need to lock here. 160 _, ok := s.jobs[j] 161 return ok 162 } 163 func (s *Session) handle(p *com.Packet) bool { 164 if p == nil || p.Device.Empty() || p.ID != RvResult || p.Job < 2 { 165 return false 166 } 167 if s.jobs == nil || len(s.jobs) == 0 { 168 if cout.Enabled { 169 s.log.Warning("[%s/ShC] Received an un-tracked Job %d!", s.ID, p.Job) 170 } 171 return false 172 } 173 if s.state.Moving() { 174 if cout.Enabled { 175 s.log.Error("[%s/ShC] Dropping Job %d as Session is being Migrated!", s.ID, p.Job) 176 } 177 return true 178 } 179 s.lock.RLock() 180 j, ok := s.jobs[p.Job] 181 if s.lock.RUnlock(); !ok { 182 if cout.Enabled { 183 s.log.Warning("[%s/ShC] Received an un-tracked Job %d!", s.ID, p.Job) 184 } 185 return false 186 } 187 if cout.Enabled { 188 s.log.Debug("[%s/ShC] Received response for Job %d.", s.ID, j.ID) 189 } 190 if j.Result, j.Complete, j.Status = p, time.Now(), StatusCompleted; p.Flags&com.FlagError != 0 { 191 j.Status = StatusError 192 if err := p.ReadString(&j.Error); err != nil { 193 j.Error = err.Error() 194 } 195 } else if j.Result != nil { 196 s.handleInfoResult(j.ID, j.Type, j.Result) 197 } 198 s.lock.Lock() 199 delete(s.jobs, j.ID) 200 if s.lock.Unlock(); j.done != nil { 201 close(j.done) 202 j.done = nil 203 } 204 if j.Update != nil { 205 s.m.queue(event{j: j, jf: j.Update}) 206 } 207 return true 208 } 209 func (s *Session) frag(i, id, max, cur uint16) { 210 if i < 2 || s.parent == nil || s.jobs == nil || len(s.jobs) == 0 { 211 return 212 } 213 s.lock.RLock() 214 j, ok := s.jobs[i] 215 if s.lock.RUnlock(); !ok { 216 return 217 } 218 if j.Frags == 0 { 219 j.Status = StatusReceiving 220 } 221 if j.Frags, j.Current = max, cur; j.Update != nil { 222 s.m.queue(event{j: j, jf: j.Update}) 223 } 224 if cout.Enabled { 225 s.log.Trace("[%s/Frag] Tracking Job %d Frag Group 0x%X, Current %d of %d.", s.ID, i, id, cur+1, max) 226 } 227 } 228 229 // SetJitter sets Jitter percentage of the Session's wake interval. This is a 0 230 // to 100 percentage (inclusive) that will determine any +/- time is added to 231 // the waiting period. This assists in evading IDS/NDS devices/systems. 232 // 233 // A value of 0 will disable Jitter and any value over 100 will set the value to 234 // 100, which represents using Jitter 100% of the time. 235 // 236 // If this is a Server-side Session, the new value will be sent to the Client in 237 // a MvTime Packet. 238 func (s *Session) SetJitter(j int) (*Job, error) { 239 return s.SetDuration(0, j) 240 } 241 242 // Task is a function that will attach a JobID to the specified Packet (if 243 // empty) and wil return a Job promise that can be used to internally keep track 244 // of a response Packet with a matching Job ID. 245 // 246 // Errors will be returned if Task is attempted on an invalid Packet, this 247 // Session is a client-side Session, Job ID is already used or the scheduler is 248 // full. 249 func (s *Session) Task(n *com.Packet) (*Job, error) { 250 if n == nil { 251 return nil, xerr.Sub("empty or nil Job", 0x59) 252 } 253 if s.parent == nil || s.jobs == nil { 254 return nil, xerr.Sub("cannot be a client session", 0x4E) 255 } 256 if s.isMoving() { 257 return nil, xerr.Sub("migration in progress", 0x4F) 258 } 259 if n.Job == 0 { 260 if n.Job = s.newJobID(); n.Job == 0 { 261 return nil, xerr.Sub("cannot assign a Job ID", 0x5A) 262 } 263 } 264 if n.Device.Empty() { 265 n.Device = s.Device.ID 266 } 267 s.lock.RLock() 268 _, ok := s.jobs[n.Job] 269 if s.lock.RUnlock(); ok { 270 if xerr.ExtendedInfo { 271 return nil, xerr.Sub("job "+util.Uitoa(uint64(n.Job))+" already registered", 0x5B) 272 } 273 return nil, xerr.Sub("job already registered", 0x5B) 274 } 275 if err := s.write(false, n); err != nil { 276 return nil, err 277 } 278 j := &Job{ID: n.Job, Type: n.ID, Start: time.Now(), s: s, done: make(chan struct{})} 279 s.lock.Lock() 280 s.jobs[n.Job] = j 281 if s.lock.Unlock(); cout.Enabled { 282 s.log.Info("[%s/ShC] Added JobID %d to Track!", s.ID, n.Job) 283 } 284 return j, nil 285 } 286 func (s *Session) setProfile(b []byte) (*Job, error) { 287 if s.parent == nil { 288 return nil, ErrNoTask 289 } 290 n := &com.Packet{ID: task.MvProfile, Device: s.Device.ID} 291 n.WriteBytes(b) 292 return s.Task(n) 293 } 294 295 // Tasklet is a function similar to Task and will attach a JobID to the specified 296 // Packet created by the supplied Tasklet and wil return a Job promise that can be 297 // used to internally keep track of a response Packet with a matching Job ID. 298 // 299 // If the Tasklet has an issue generating the payload, it will return an error 300 // before scheduling. 301 // 302 // Errors will be returned if Task is attempted on an invalid Packet, this Session 303 // is a client-side Session, Job ID is already or the scheduler is full. 304 func (s *Session) Tasklet(t task.Tasklet) (*Job, error) { 305 if t == nil { 306 return nil, xerr.Sub("empty or nil Tasklet", 0x5C) 307 } 308 n, err := t.Packet() 309 if err != nil { 310 return nil, err 311 } 312 return s.Task(n) 313 } 314 315 // SetKillDate sets the KillDate for this Session. This is a setting that controls 316 // the date when this Session will shutdown automatically. 317 // 318 // Use the WorkHours functions to create one or do it manually. If a nil value 319 // is passed (or an empty WorkHours) this will clear the current WorkHours setting. 320 // 321 // Changing the WorkHours when there perviously was a non-nil setting will wake 322 // the Session if it's sleeping. 323 // 324 // If this is a Server-side Session, the new value will be sent to the Client in 325 // a MvTime Packet. 326 func (s *Session) SetKillDate(t time.Time) (*Job, error) { 327 if s.kill = t; s.parent == nil { 328 return nil, ErrNoTask 329 } 330 n := &com.Packet{ID: task.MvTime, Device: s.Device.ID} 331 if n.WriteUint8(timeKillDate); s.kill.IsZero() { 332 n.WriteInt64(0) 333 } else { 334 n.WriteInt64(t.Unix()) 335 } 336 return s.Task(n) 337 } 338 339 // SetSleep sets the wake interval period for this Session. This is the time value 340 // between connections to the C2 Server. 341 // 342 // If this is a Server-side Session, the new value will be sent to the Client in 343 // a MvTime Packet. This setting does not affect Jitter. 344 func (s *Session) SetSleep(t time.Duration) (*Job, error) { 345 return s.SetDuration(t, -1) 346 } 347 348 // SetProfileBytes will set the Profile used by this Session. This function will 349 // unmarshal and set the server-side before setting and will then pass it to be 350 // set by the client Session (if this isn't one already). 351 // 352 // If this is a server-side Session, this will trigger the sending of a MvProfile 353 // Packet to update the client-side instance, which will update on it's next 354 // wakeup cycle. 355 // 356 // This function will fail if no ProfileParser is set. 357 // 358 // If this is a client-side session the error 'ErrNoTask' will be returned AFTER 359 // setting the Profile and indicates that no Packet will be sent and that the 360 // Job object result is nil. 361 func (s *Session) SetProfileBytes(b []byte) (*Job, error) { 362 p, err := parseProfile(b) 363 if err != nil { 364 return nil, xerr.Wrap("parse Profile", err) 365 } 366 s.p = p 367 return s.setProfile(b) 368 } 369 370 // SetProfile will set the Profile used by this Session. This function will 371 // ensure that the profile is marshalable before setting and will then pass it 372 // to be set by the client Session (if this isn't one already). 373 // 374 // If this is a server-side Session, this will trigger the sending of a MvProfile 375 // Packet to update the client-side instance, which will update on it's next 376 // wakeup cycle. 377 // 378 // If this is a client-side session the error 'ErrNoTask' will be returned AFTER 379 // setting the Profile and indicates that no Packet will be sent and that the 380 // Job object result is nil. 381 func (s *Session) SetProfile(p cfg.Profile) (*Job, error) { 382 if p == nil { 383 return nil, ErrInvalidProfile 384 } 385 m, ok := p.(marshaler) 386 if !ok { 387 return nil, xerr.Sub("cannot marshal Profile", 0x50) 388 } 389 b, err := m.MarshalBinary() 390 if err != nil { 391 return nil, xerr.Wrap("cannot marshal Profile", err) 392 } 393 s.p = p 394 return s.setProfile(b) 395 } 396 397 // SetWorkHours sets the WorkingHours for this Session. This is a setting that 398 // controls WHEN the Session will talk to the C2 Server. 399 // 400 // Use the WorkHours functions to create one or do it manually. If a nil value 401 // is passed (or an empty WorkHours) this will clear the current WorkHours setting. 402 // 403 // Changing the WorkHours when there perviously was a non-nil setting will wake 404 // the Session if it's sleeping. 405 // 406 // If this is a Server-side Session, the new value will be sent to the Client in 407 // a MvTime Packet. 408 func (s *Session) SetWorkHours(w *cfg.WorkHours) (*Job, error) { 409 if w == nil || w.Empty() { 410 if s.work != nil { 411 s.Wake() 412 } 413 if s.work = nil; s.parent == nil { 414 return nil, ErrNoTask 415 } 416 n := &com.Packet{ID: task.MvTime, Device: s.Device.ID} 417 n.WriteUint8(timeWorkHours) 418 n.WriteUint32(0) 419 n.WriteUint8(0) 420 return s.Task(n) 421 } 422 if err := w.Verify(); err != nil { 423 return nil, err 424 } 425 if s.work != nil { 426 s.Wake() 427 } 428 if s.work = w; s.parent == nil { 429 return nil, ErrNoTask 430 } 431 n := &com.Packet{ID: task.MvTime, Device: s.Device.ID} 432 n.WriteUint8(timeWorkHours) 433 w.MarshalStream(n) 434 return s.Task(n) 435 } 436 437 // SetDuration sets the wake interval period and Jitter for this Session. This is 438 // the time value between connections to the C2 Server. 439 // 440 // Jitter is a 0 to 100 percentage (inclusive) that will determine any +/- time 441 // is added to the waiting period. This assists in evading IDS/NDS devices/systems. 442 // 443 // A value of 0 will disable Jitter and any value over 100 will set the value to 444 // 100, which represents using Jitter 100% of the time. 445 // 446 // If this is a Server-side Session, the new value will be sent to the Client in 447 // a MvTime Packet. 448 func (s *Session) SetDuration(t time.Duration, j int) (*Job, error) { 449 switch { 450 case j == -1: 451 case j < 0: 452 s.jitter = 0 453 case j > 100: 454 s.jitter = 100 455 default: 456 s.jitter = uint8(j) 457 } 458 if t > 0 { 459 s.sleep = t 460 } 461 if s.parent == nil { 462 return nil, ErrNoTask 463 } 464 n := &com.Packet{ID: task.MvTime, Device: s.Device.ID} 465 n.WriteUint16(uint16(s.jitter)) // timeSleepJitter (0) is implied here 466 n.WriteUint64(uint64(s.sleep)) 467 return s.Task(n) 468 } 469 func (s *Session) handleInfoResult(i uint16, t uint8, n *com.Packet) { 470 switch t { 471 case task.MvProxy: 472 var err error 473 if s.proxies, err = s.readDeviceInfo(infoProxy, n); err != nil { 474 if cout.Enabled { 475 s.log.Error("[%s/Cr0] Error reading MvProxy Job %d result: %s!", s.ID, i, err.Error()) 476 } 477 } 478 if cout.Enabled { 479 s.log.Debug("[%s/Cr0] Client indicated that it updated it's Proxy details, updating local Proxy information.", s.ID) 480 } 481 case task.MvMigrate: 482 if _, err := s.readDeviceInfo(infoSyncMigrate, n); err != nil { 483 if cout.Enabled { 484 s.log.Error("[%s/Cr0] Error reading MvMigrate Job %d result: %s!", s.ID, i, err.Error()) 485 } 486 } 487 if cout.Enabled { 488 s.log.Debug("[%s/Cr0] Client indicated that it migrated, updating local Session information.", s.ID) 489 } 490 case task.MvRefresh: 491 var err error 492 if s.proxies, err = s.readDeviceInfo(infoRefresh, n); err != nil { 493 if cout.Enabled { 494 s.log.Error("[%s/Cr0] Error reading MvRefresh Job %d result: %s!", s.ID, i, err.Error()) 495 } 496 } 497 if cout.Enabled { 498 s.log.Debug("[%s/Cr0] Client indicated that it refreshed it's details, updating local Session information.", s.ID) 499 } 500 case task.MvTime, task.MvProfile: 501 if _, err := s.readDeviceInfo(infoSync, n); err != nil { 502 if cout.Enabled { 503 s.log.Error("[%s/Cr0] Error reading MvTime/MvProfile Job %d result: %s!", s.ID, i, err.Error()) 504 } 505 } 506 if cout.Enabled { 507 s.log.Debug("[%s/Cr0] Client indicated that it changed profile/time, updating local Session information.", s.ID) 508 } 509 default: 510 return 511 } 512 n.Seek(0, 0) 513 }