302 lines
5.8 KiB
Go
302 lines
5.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-admin-team/go-admin-core/sdk/api"
|
|
"github.com/gorilla/websocket"
|
|
"github.com/ziutek/telnet"
|
|
"golang.org/x/crypto/ssh"
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
)
|
|
|
|
type TgWs struct {
|
|
api.Api
|
|
}
|
|
|
|
var upGrader = websocket.Upgrader{
|
|
ReadBufferSize: 1024,
|
|
WriteBufferSize: 1024 * 1024 * 10,
|
|
CheckOrigin: func(r *http.Request) bool {
|
|
return true
|
|
},
|
|
}
|
|
|
|
type ShellInfoStruct struct {
|
|
Proto string `json:"proto"`
|
|
IpAddr string `json:"ipaddr"`
|
|
Port string `json:"port"`
|
|
}
|
|
|
|
type wsWrapper struct {
|
|
*websocket.Conn
|
|
}
|
|
|
|
func main() {
|
|
telnetHandle(rw io.ReadWriter, ip, port string, errhandle func(string)) {
|
|
|
|
}
|
|
|
|
func init() {
|
|
routerCheckRole = append(routerCheckRole, registerTgWsRouter)
|
|
}
|
|
|
|
// 需认证的路由代码
|
|
func registerTgWsRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
|
api := apis.TgWs{}
|
|
r := v1.Group("")
|
|
{
|
|
// 协议、IP、端口
|
|
r.GET("/tgws/:proto/:ipaddr/:port", api.TgWsWeb)
|
|
}
|
|
}
|
|
|
|
func (e TgWs) TgWsWeb(c *gin.Context) {
|
|
// 初始化返回信息
|
|
err := e.MakeContext(c).Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, fmt.Sprintf(" %s ", err.Error()))
|
|
return
|
|
}
|
|
|
|
// 升级为websocket
|
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, "websocket client connect error")
|
|
return
|
|
}
|
|
defer wsConn.Close()
|
|
|
|
proto := c.Param("proto")
|
|
ipaddr := c.Param("ipaddr")
|
|
port := c.Param("port")
|
|
shellinfo := ShellInfoStruct{
|
|
Proto: proto,
|
|
IpAddr: ipaddr,
|
|
Port: port,
|
|
}
|
|
quitChan := make(chan bool, 1)
|
|
go websocketHandle(wsConn, shellinfo, quitChan)
|
|
<-quitChan
|
|
}
|
|
|
|
func websocketHandle(con *websocket.Conn, shellinfo ShellInfoStruct, exitCh chan bool) {
|
|
defer setQuit(exitCh)
|
|
rw := io.ReadWriter(&wsWrapper{con})
|
|
webprintln := func(data string) {
|
|
rw.Write([]byte(data + "\r\n"))
|
|
}
|
|
con.SetCloseHandler(func(code int, text string) error {
|
|
con.Close()
|
|
return nil
|
|
})
|
|
switch shellinfo.Proto {
|
|
case "ssh":
|
|
sshHandle(rw, shellinfo.IpAddr, shellinfo.Port, "XXX", "XXX", webprintln)
|
|
case "telnet":
|
|
telnetHandle(rw, shellinfo.IpAddr, shellinfo.Port, webprintln)
|
|
case "bind_shell":
|
|
bindShellHandler(rw, shellinfo.IpAddr, shellinfo.Port, webprintln)
|
|
default:
|
|
webprintln("Not Support Protocol '" + shellinfo.Proto + "'")
|
|
}
|
|
return
|
|
}
|
|
|
|
func (wsw *wsWrapper) Write(p []byte) (n int, err error) {
|
|
writer, err := wsw.Conn.NextWriter(websocket.TextMessage)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer writer.Close()
|
|
return writer.Write(p)
|
|
}
|
|
|
|
func (wsw *wsWrapper) Read(p []byte) (n int, err error) {
|
|
for {
|
|
msgType, reader, err := wsw.Conn.NextReader()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if msgType != websocket.TextMessage {
|
|
continue
|
|
}
|
|
return reader.Read(p)
|
|
}
|
|
}
|
|
|
|
// SSH连接
|
|
func sshHandle(rw io.ReadWriter, ip, port, user, passwd string, errhandle func(string)) {
|
|
sshConfig := &ssh.ClientConfig{
|
|
User: user,
|
|
Auth: []ssh.AuthMethod{ssh.Password(passwd)},
|
|
Timeout: 6 * time.Second,
|
|
}
|
|
sshConfig.HostKeyCallback = ssh.InsecureIgnoreHostKey()
|
|
if port == "" {
|
|
ip = ip + ":22"
|
|
} else {
|
|
ip = ip + ":" + port
|
|
}
|
|
client, err := ssh.Dial("tcp", ip, sshConfig)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
return
|
|
}
|
|
defer client.Close()
|
|
session, err := client.NewSession()
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
return
|
|
}
|
|
defer session.Close()
|
|
fd := int(os.Stdin.Fd())
|
|
session.Stdout = rw
|
|
session.Stderr = rw
|
|
session.Stdin = rw
|
|
modes := ssh.TerminalModes{
|
|
ssh.ECHO: 1,
|
|
ssh.TTY_OP_ISPEED: 14400,
|
|
ssh.TTY_OP_OSPEED: 14400,
|
|
}
|
|
termWidth, termHeight, err := terminal.GetSize(fd)
|
|
err = session.RequestPty("xterm", termHeight, termWidth, modes)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
}
|
|
err = session.Shell()
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
}
|
|
err = session.Wait()
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
// telnet连接
|
|
func telnetHandle(rw io.ReadWriter, ip, port string, errhandle func(string)) {
|
|
if port == "" {
|
|
ip = ip + ":23"
|
|
} else {
|
|
ip = ip + ":" + port
|
|
}
|
|
con, err := telnet.Dial("tcp", ip)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
return
|
|
}
|
|
defer con.Close()
|
|
buf := make([]byte, 16*1024)
|
|
|
|
// 从远端读取返回结果并回显页面
|
|
go func() {
|
|
for {
|
|
n, err := con.Read(buf)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
_, err = rw.Write(buf[:n])
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
for {
|
|
// 从页面读取命令
|
|
n, err := rw.Read(buf)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
if buf[0] == 13 { // 处理换行
|
|
data := []byte{telnet.CR, telnet.LF}
|
|
_, err = con.Write(data)
|
|
} else {
|
|
_, err = con.Write(buf[:n])
|
|
}
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// 正向shell
|
|
func bindShellHandler(rw io.ReadWriter, ip, port string, errhandle func(string)) {
|
|
server := ip + ":" + port
|
|
//获取命令行参数 socket地址
|
|
addr, err := net.ResolveTCPAddr("tcp4", server)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
return
|
|
}
|
|
//建立tcp连接
|
|
con, err := net.DialTCP("tcp4", nil, addr)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
return
|
|
}
|
|
rw.Write([]byte("reverse shell connected " + "\r\n"))
|
|
defer con.Close()
|
|
buf := make([]byte, 16*1024)
|
|
|
|
go func() {
|
|
for {
|
|
n, err := con.Read(buf)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
_, err = rw.Write(buf[:n])
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
for {
|
|
n, err := rw.Read(buf)
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
_, err = rw.Write(buf[:n])
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
|
|
if buf[0] == 13 {
|
|
data := []byte{telnet.LF}
|
|
_, err = con.Write(data)
|
|
rw.Write([]byte("\r\n"))
|
|
} else {
|
|
_, err = con.Write(buf[:n])
|
|
}
|
|
if err != nil {
|
|
errhandle(err.Error())
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func setQuit(ch chan bool) {
|
|
ch <- true
|
|
}
|