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  }