mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-26 05:01:53 +08:00
- 添加ErrNLAAuthSuccess标志用于NLA验证成功信号 - tpkt层支持nlaAuthOnly模式,验证成功后不建立完整会话 - x224层正确传播NLA验证结果 - rdpCrack改用NlaAuth进行凭据验证
705 lines
18 KiB
Go
705 lines
18 KiB
Go
package login
|
||
|
||
import (
|
||
"bufio"
|
||
"bytes"
|
||
"errors"
|
||
"fmt"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/core"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/glog"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/protocol/nla"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/protocol/pdu"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/protocol/sec"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/protocol/t125"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/protocol/tpkt"
|
||
"github.com/shadow1ng/fscan/mylib/grdp/protocol/x224"
|
||
"golang.org/x/net/context"
|
||
"golang.org/x/net/proxy"
|
||
"image"
|
||
"image/color"
|
||
"image/draw"
|
||
"image/jpeg"
|
||
"log"
|
||
"math/rand"
|
||
"net"
|
||
"net/url"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
var (
|
||
Socks5Proxy string = ""
|
||
LogLever glog.LEVEL = glog.NONE
|
||
OutputDir string
|
||
)
|
||
|
||
func init() {
|
||
}
|
||
|
||
func RdpConn(host, domain, user, password string, timeout int64, rdpProtocol uint32) (bool, error) {
|
||
g := NewClient(host, LogLever)
|
||
status, err, reconnectProtocol := g.ScreenShot(domain, user, password, timeout, rdpProtocol)
|
||
if status == true {
|
||
return true, err
|
||
} else {
|
||
if reconnectProtocol != rdpProtocol {
|
||
glog.Info("reconnect with protocol:", reconnectProtocol)
|
||
return RdpConn(host, domain, user, password, timeout, reconnectProtocol)
|
||
} else {
|
||
return status, err
|
||
}
|
||
}
|
||
}
|
||
|
||
func RdpCrack(host, domain, user, password string, timeout int64, rdpProtocol uint32) (bool, error) {
|
||
g := NewClient(host, LogLever)
|
||
status, err, reconnectProtocol := g.Crack(domain, user, password, timeout, rdpProtocol)
|
||
if status == true {
|
||
return true, err
|
||
} else {
|
||
if reconnectProtocol != rdpProtocol {
|
||
glog.Info("reconnect with protocol:", reconnectProtocol)
|
||
return RdpCrack(host, domain, user, password, timeout, reconnectProtocol)
|
||
} else {
|
||
return status, err
|
||
}
|
||
}
|
||
}
|
||
|
||
// NlaAuth 仅进行NLA认证验证,不建立RDP会话,不会挤掉已登录用户
|
||
// 返回: (认证成功, 错误信息)
|
||
func NlaAuth(host, domain, user, password string, timeout int64) (bool, error) {
|
||
g := NewClient(host, LogLever)
|
||
return g.NlaAuthOnly(domain, user, password, timeout)
|
||
}
|
||
|
||
type Client struct {
|
||
Host string // ip:port
|
||
tpkt *tpkt.TPKT
|
||
x224 *x224.X224
|
||
mcs *t125.MCSClient
|
||
sec *sec.Client
|
||
pdu *pdu.Client
|
||
}
|
||
|
||
func NewClient(host string, logLevel glog.LEVEL) *Client {
|
||
glog.SetLevel(logLevel)
|
||
logger := log.New(os.Stdout, "", 0)
|
||
glog.SetLogger(logger)
|
||
return &Client{
|
||
Host: host,
|
||
}
|
||
}
|
||
|
||
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
||
local_ip := "0.0.0.0"
|
||
net_ip := net.ParseIP(local_ip)
|
||
if net_ip == nil {
|
||
net_ip = net.ParseIP("0.0.0.0")
|
||
}
|
||
local_addr := &net.TCPAddr{
|
||
IP: net_ip, // 替换为你想要使用的本地IP地址
|
||
}
|
||
d := &net.Dialer{Timeout: timeout, LocalAddr: local_addr}
|
||
return WrapperTCP(network, address, d)
|
||
}
|
||
|
||
func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error) {
|
||
//get conn
|
||
var conn net.Conn
|
||
if Socks5Proxy == "" {
|
||
var err error
|
||
conn, err = forward.Dial(network, address)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
} else {
|
||
dailer, err := Socks5Dailer(forward)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
conn, err = dailer.Dial(network, address)
|
||
if err != nil {
|
||
// fmt.Println(err)
|
||
return nil, err
|
||
}
|
||
|
||
}
|
||
|
||
timeout := forward.Timeout
|
||
if err := conn.SetWriteDeadline(time.Now().Add(timeout * 6)); err != nil {
|
||
return nil, err
|
||
}
|
||
if err := conn.SetReadDeadline(time.Now().Add(timeout * 6)); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return conn, nil
|
||
|
||
}
|
||
|
||
func Socks5Dailer(forward *net.Dialer) (proxy.Dialer, error) {
|
||
u, err := url.Parse(Socks5Proxy)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if strings.ToLower(u.Scheme) != "socks5" {
|
||
return nil, errors.New("Only support socks5")
|
||
}
|
||
address := u.Host
|
||
var auth proxy.Auth
|
||
var dailer proxy.Dialer
|
||
if u.User.String() != "" {
|
||
auth = proxy.Auth{}
|
||
auth.User = u.User.Username()
|
||
password, _ := u.User.Password()
|
||
auth.Password = password
|
||
dailer, err = proxy.SOCKS5("tcp", address, &auth, forward)
|
||
} else {
|
||
dailer, err = proxy.SOCKS5("tcp", address, nil, forward)
|
||
}
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return dailer, nil
|
||
}
|
||
|
||
type Bitmap struct {
|
||
DestLeft int `json:"destLeft"`
|
||
DestTop int `json:"destTop"`
|
||
DestRight int `json:"destRight"`
|
||
DestBottom int `json:"destBottom"`
|
||
Width int `json:"width"`
|
||
Height int `json:"height"`
|
||
BitsPerPixel int `json:"bitsPerPixel"`
|
||
IsCompress bool `json:"isCompress"`
|
||
Data []byte `json:"data"`
|
||
}
|
||
|
||
func Bpp(BitsPerPixel uint16) (pixel int) {
|
||
switch BitsPerPixel {
|
||
case 15:
|
||
pixel = 1
|
||
|
||
case 16:
|
||
pixel = 2
|
||
|
||
case 24:
|
||
pixel = 3
|
||
|
||
case 32:
|
||
pixel = 4
|
||
|
||
default:
|
||
glog.Error("-------------------------------------Bpp func. invalid bitmap data format")
|
||
}
|
||
return
|
||
}
|
||
|
||
func BitmapDecompress(bitmap *pdu.BitmapData) []byte {
|
||
return core.Decompress(bitmap.BitmapDataStream, int(bitmap.Width), int(bitmap.Height), Bpp(bitmap.BitsPerPixel))
|
||
}
|
||
|
||
func ToRGBA(pixel int, i int, data []byte) (r, g, b, a uint8) {
|
||
a = 255
|
||
switch pixel {
|
||
case 1:
|
||
rgb555 := core.Uint16BE(data[i], data[i+1])
|
||
r, g, b = core.RGB555ToRGB(rgb555)
|
||
case 2:
|
||
rgb565 := core.Uint16BE(data[i], data[i+1])
|
||
r, g, b = core.RGB565ToRGB(rgb565)
|
||
case 3, 4:
|
||
fallthrough
|
||
default:
|
||
r, g, b = data[i+2], data[i+1], data[i]
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// NlaAuthOnly 仅进行NLA认证验证凭据,不建立RDP会话
|
||
// 这样不会挤掉已登录的用户
|
||
func (g *Client) NlaAuthOnly(domain, user, pwd string, timeout int64) (bool, error) {
|
||
conn, err := WrapperTcpWithTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
|
||
if err != nil {
|
||
return false, fmt.Errorf("[dial err] %v", err)
|
||
}
|
||
defer conn.Close()
|
||
|
||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||
g.x224 = x224.New(g.tpkt)
|
||
|
||
// 设置NLA仅验证模式
|
||
g.tpkt.SetNLAAuthOnly(true)
|
||
|
||
// 使用 PROTOCOL_HYBRID (NLA) 协议
|
||
g.x224.SetRequestedProtocol(x224.PROTOCOL_HYBRID)
|
||
|
||
// 用于接收结果的通道
|
||
resultChan := make(chan error, 1)
|
||
|
||
// 监听错误事件(包括 ErrNLAAuthSuccess)
|
||
g.x224.On("error", func(err error) {
|
||
resultChan <- err
|
||
})
|
||
|
||
// 监听连接事件(不应该发生在 auth-only 模式)
|
||
g.x224.On("connect", func(protocol uint32) {
|
||
resultChan <- fmt.Errorf("unexpected connect in auth-only mode")
|
||
})
|
||
|
||
// 发起连接
|
||
err = g.x224.Connect()
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
|
||
// 等待结果或超时
|
||
select {
|
||
case err := <-resultChan:
|
||
if err == tpkt.ErrNLAAuthSuccess {
|
||
return true, nil
|
||
}
|
||
return false, err
|
||
case <-time.After(time.Duration(timeout*3) * time.Second):
|
||
return false, fmt.Errorf("NLA auth timeout")
|
||
}
|
||
}
|
||
|
||
func (g *Client) ProbeOSInfo(host, domain, user, pwd string, timeout int64, rdpProtocol uint32) (info map[string]any) {
|
||
start := time.Now()
|
||
exitFlag := make(chan bool)
|
||
info = make(map[string]any)
|
||
|
||
targetSlice := strings.Split(g.Host, ":")
|
||
ip := targetSlice[0]
|
||
conn, err := WrapperTcpWithTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
|
||
if err != nil {
|
||
return
|
||
}
|
||
defer conn.Close()
|
||
glog.Info(conn.LocalAddr().String())
|
||
|
||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||
g.x224 = x224.New(g.tpkt)
|
||
g.mcs = t125.NewMCSClient(g.x224)
|
||
g.sec = sec.NewClient(g.mcs)
|
||
g.pdu = pdu.NewClient(g.sec)
|
||
|
||
g.sec.SetUser(user)
|
||
g.sec.SetPwd(pwd)
|
||
g.sec.SetDomain(domain)
|
||
|
||
g.tpkt.SetFastPathListener(g.sec)
|
||
g.sec.SetFastPathListener(g.pdu)
|
||
g.pdu.SetFastPathSender(g.tpkt)
|
||
g.sec.SetChannelSender(g.mcs)
|
||
|
||
g.tpkt.On("os_info", func(infoMap map[string]any) {
|
||
glog.Debug("[+] callback, get os info ........................")
|
||
for k, v := range infoMap {
|
||
glog.Debugf("%s: %s\n", k, v)
|
||
}
|
||
info = infoMap
|
||
g.pdu.Emit("done")
|
||
})
|
||
|
||
g.x224.SetRequestedProtocol(rdpProtocol) //x224.PROTOCOL_SSL , x224.PROTOCOL_RDP , x224.PROTOCOL_HYBRID , x224.PROTOCOL_HYBRID_EX
|
||
g.x224.On("reconnect", func(protocol uint32) {
|
||
info["reconn"] = protocol
|
||
g.pdu.Emit("close")
|
||
exitFlag <- true
|
||
})
|
||
|
||
err = g.x224.Connect()
|
||
if err != nil {
|
||
info["err"] = err.Error()
|
||
return
|
||
}
|
||
glog.Info("wait connect ok")
|
||
|
||
g.pdu.On("error", func(e error) {
|
||
err = e
|
||
glog.Error("error", e)
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("close", func() {
|
||
err = errors.New("close")
|
||
glog.Info("on close")
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("success", func() {
|
||
glog.Debugf("===============login success %s===============", ip)
|
||
err = nil
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("ready", func() {
|
||
err = nil
|
||
glog.Debug("on ready")
|
||
})
|
||
g.pdu.On("bitmap", func(rectangles []pdu.BitmapData) {
|
||
})
|
||
g.pdu.On("done", func() {
|
||
glog.Debug("done信号触发")
|
||
exitFlag <- true
|
||
})
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout*3)*time.Second)
|
||
defer cancel()
|
||
|
||
loop:
|
||
for {
|
||
select {
|
||
case <-time.After(time.Second * time.Duration(timeout)): //
|
||
break loop
|
||
case <-exitFlag:
|
||
break loop
|
||
case <-ctx.Done():
|
||
glog.Debug("总超时已达到,退出")
|
||
break loop
|
||
}
|
||
}
|
||
glog.Debug("循环结束,总时间过去了:", time.Since(start))
|
||
return info
|
||
}
|
||
|
||
func (g *Client) ScreenShot(domain, user, pwd string, timeout int64, rdpProtocol uint32) (status bool, err error, reconnProtocol uint32) {
|
||
//glog.SetLevel(glog.ERROR)
|
||
reconnProtocol = rdpProtocol
|
||
pic_length := 1280 //1280
|
||
pic_width := 800 //800
|
||
needReconnect := false
|
||
isScreenOK := false
|
||
refresh := make(chan bool)
|
||
exitFlag := make(chan bool)
|
||
start := time.Now()
|
||
now := start
|
||
screenImage := image.NewRGBA(image.Rect(0, 0, pic_length, pic_width))
|
||
|
||
targetSlice := strings.Split(g.Host, ":")
|
||
ip := targetSlice[0]
|
||
port := targetSlice[1]
|
||
status = false
|
||
conn, err := WrapperTcpWithTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
|
||
if err != nil {
|
||
return status, fmt.Errorf("[dial err] %v", err), reconnProtocol
|
||
}
|
||
defer conn.Close()
|
||
glog.Info(conn.LocalAddr().String())
|
||
|
||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||
g.x224 = x224.New(g.tpkt)
|
||
g.mcs = t125.NewMCSClient(g.x224)
|
||
g.sec = sec.NewClient(g.mcs)
|
||
g.pdu = pdu.NewClient(g.sec)
|
||
|
||
g.sec.SetUser(user)
|
||
g.sec.SetPwd(pwd)
|
||
g.sec.SetDomain(domain)
|
||
//g.sec.SetClientAutoReconnect()
|
||
|
||
g.tpkt.SetFastPathListener(g.sec)
|
||
g.sec.SetFastPathListener(g.pdu)
|
||
g.pdu.SetFastPathSender(g.tpkt)
|
||
g.sec.SetChannelSender(g.mcs)
|
||
|
||
g.tpkt.On("os_info", func(info map[string]any) {
|
||
glog.Debug("[+] callback, get os info ........................")
|
||
for k, v := range info {
|
||
glog.Debugf("%s: %s\n", k, v)
|
||
}
|
||
})
|
||
|
||
g.x224.SetRequestedProtocol(rdpProtocol) //x224.PROTOCOL_SSL , x224.PROTOCOL_RDP , x224.PROTOCOL_HYBRID , x224.PROTOCOL_HYBRID_EX
|
||
g.x224.On("reconnect", func(protocol uint32) {
|
||
needReconnect = true
|
||
reconnProtocol = protocol
|
||
glog.Info("need reconnect with protocol:", protocol)
|
||
g.pdu.Emit("close")
|
||
exitFlag <- true
|
||
})
|
||
g.x224.On("more_timeout", func() {
|
||
timeout += 18 //如果是PROTOCOL_RDP协议,可以适当延长超时时间
|
||
})
|
||
|
||
err = g.x224.Connect()
|
||
if err != nil {
|
||
return status, fmt.Errorf("[x224 connect err] %v", err), reconnProtocol
|
||
}
|
||
glog.Info("wait connect ok")
|
||
|
||
g.pdu.On("error", func(e error) {
|
||
err = e
|
||
glog.Error("error", e)
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("close", func() {
|
||
err = errors.New("close")
|
||
glog.Info("on close")
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("success", func() {
|
||
glog.Debugf("===============login success %s===============", ip)
|
||
status = true
|
||
err = nil
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("ready", func() {
|
||
err = nil
|
||
glog.Debug("on ready")
|
||
//g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("bitmap", func(rectangles []pdu.BitmapData) {
|
||
now = time.Now()
|
||
// 发送一个鼠标事件,作用是与服务器保持联系不要断开
|
||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||
randomNumber := rand.Intn(1000) + 10 // 10到1000之间的随机数
|
||
mouseX := 60 + randomNumber
|
||
mouseY := 10 + randomNumber
|
||
pevent := &pdu.PointerEvent{}
|
||
pevent.PointerFlags |= pdu.PTRFLAGS_MOVE
|
||
pevent.XPos = uint16(mouseX)
|
||
pevent.YPos = uint16(mouseY)
|
||
g.pdu.SendInputEvents(pdu.INPUT_EVENT_MOUSE, []pdu.InputEventsInterface{pevent})
|
||
|
||
glog.Debug("on update bitmap:", len(rectangles))
|
||
bs := make([]Bitmap, 0)
|
||
for _, v := range rectangles {
|
||
IsCompress := v.IsCompress()
|
||
data := v.BitmapDataStream
|
||
if IsCompress {
|
||
data = BitmapDecompress(&v)
|
||
IsCompress = false
|
||
}
|
||
b := Bitmap{int(v.DestLeft), int(v.DestTop), int(v.DestRight), int(v.DestBottom),
|
||
int(v.Width), int(v.Height), Bpp(v.BitsPerPixel), IsCompress, data}
|
||
bs = append(bs, b)
|
||
}
|
||
var (
|
||
pixel int
|
||
i int
|
||
r, g, b, a uint8
|
||
)
|
||
|
||
for _, bm := range bs {
|
||
i = 0
|
||
pixel = bm.BitsPerPixel
|
||
m := image.NewRGBA(image.Rect(0, 0, bm.Width, bm.Height))
|
||
for y := 0; y < bm.Height; y++ {
|
||
for x := 0; x < bm.Width; x++ {
|
||
r, g, b, a = ToRGBA(pixel, i, bm.Data)
|
||
c := color.RGBA{R: r, G: g, B: b, A: a}
|
||
i += pixel
|
||
m.Set(x, y, c)
|
||
}
|
||
}
|
||
draw.Draw(screenImage, screenImage.Bounds().Add(image.Pt(bm.DestLeft, bm.DestTop)), m, m.Bounds().Min, draw.Src)
|
||
}
|
||
// Encode to jpeg.
|
||
//var imageBuf bytes.Buffer
|
||
//err = jpeg.Encode(&imageBuf, screenImage, nil)
|
||
//
|
||
//if err != nil {
|
||
// glog.Info("trans bitmap to jpeg err:", err)
|
||
//}
|
||
|
||
// Write to file.
|
||
//fo, err := os.Create(fmt.Sprintf("img/%s-%d.jpg", ip, index))
|
||
//if err != nil {
|
||
// panic(err)
|
||
//}
|
||
//index += 1
|
||
//fw := bufio.NewWriter(fo)
|
||
//fw.Write(imageBuf.Bytes())
|
||
|
||
isScreenOK = true
|
||
refresh <- true
|
||
|
||
})
|
||
g.pdu.On("done", func() {
|
||
glog.Debug("done信号触发")
|
||
exitFlag <- true
|
||
})
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout*6)*time.Second)
|
||
defer cancel()
|
||
|
||
loop:
|
||
for {
|
||
select {
|
||
case <-time.After(time.Second * time.Duration(timeout*3)): //
|
||
glog.Debug("本次获取bitmap超时了, 距离上次获取到图像过去了:", time.Since(now))
|
||
break loop
|
||
case <-refresh:
|
||
continue loop
|
||
case <-exitFlag:
|
||
break loop
|
||
case <-ctx.Done():
|
||
glog.Debug("总超时已达到,退出")
|
||
break loop
|
||
}
|
||
}
|
||
glog.Debug("循环结束,总时间过去了:", time.Since(start))
|
||
|
||
// 认证结果由 success 事件回调设置,不在此处覆盖
|
||
|
||
if needReconnect {
|
||
return status, err, reconnProtocol
|
||
} else if isScreenOK {
|
||
glog.Info("get screen ok")
|
||
// Encode to jpeg.
|
||
var imageBuf bytes.Buffer
|
||
encodeErr := jpeg.Encode(&imageBuf, screenImage, nil)
|
||
if encodeErr != nil {
|
||
glog.Error("Failed to encode screenshot:", encodeErr)
|
||
return status, err, reconnProtocol
|
||
}
|
||
|
||
// Write to file.
|
||
saveDate := time.Now().Format("2006_01_02_15_04_05")
|
||
fo, writeErr := os.Create(fmt.Sprintf("%s/%s_%s_%s.jpg", OutputDir, ip, port, saveDate))
|
||
if writeErr != nil {
|
||
glog.Error("Can not create rdp screenshot file:", writeErr)
|
||
} else {
|
||
defer fo.Close()
|
||
fw := bufio.NewWriter(fo)
|
||
_, writeErr := fw.Write(imageBuf.Bytes())
|
||
if writeErr != nil {
|
||
glog.Error("Can not write rdp screenshot file:", writeErr)
|
||
} else {
|
||
fw.Flush()
|
||
}
|
||
}
|
||
}
|
||
return status, err, reconnProtocol
|
||
|
||
}
|
||
|
||
func (g *Client) Crack(domain, user, pwd string, timeout int64, rdpProtocol uint32) (status bool, err error, reconnProtocol uint32) {
|
||
//glog.SetLevel(glog.ERROR)
|
||
reconnProtocol = rdpProtocol
|
||
refresh := make(chan bool)
|
||
exitFlag := make(chan bool)
|
||
start := time.Now()
|
||
now := start
|
||
|
||
targetSlice := strings.Split(g.Host, ":")
|
||
ip := targetSlice[0]
|
||
status = false
|
||
conn, err := WrapperTcpWithTimeout("tcp", g.Host, time.Duration(timeout)*time.Second)
|
||
if err != nil {
|
||
return status, fmt.Errorf("[dial err] %v", err), reconnProtocol
|
||
}
|
||
defer conn.Close()
|
||
glog.Info(conn.LocalAddr().String())
|
||
|
||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||
g.x224 = x224.New(g.tpkt)
|
||
g.mcs = t125.NewMCSClient(g.x224)
|
||
g.sec = sec.NewClient(g.mcs)
|
||
g.pdu = pdu.NewClient(g.sec)
|
||
|
||
g.sec.SetUser(user)
|
||
g.sec.SetPwd(pwd)
|
||
g.sec.SetDomain(domain)
|
||
//g.sec.SetClientAutoReconnect()
|
||
|
||
g.tpkt.SetFastPathListener(g.sec)
|
||
g.sec.SetFastPathListener(g.pdu)
|
||
g.pdu.SetFastPathSender(g.tpkt)
|
||
g.sec.SetChannelSender(g.mcs)
|
||
|
||
g.tpkt.On("os_info", func(info map[string]any) {
|
||
glog.Debug("[+] callback, get os info ........................")
|
||
for k, v := range info {
|
||
glog.Debugf("%s: %s\n", k, v)
|
||
}
|
||
})
|
||
|
||
g.x224.SetRequestedProtocol(rdpProtocol) //x224.PROTOCOL_SSL , x224.PROTOCOL_RDP , x224.PROTOCOL_HYBRID , x224.PROTOCOL_HYBRID_EX
|
||
g.x224.On("reconnect", func(protocol uint32) {
|
||
reconnProtocol = protocol
|
||
glog.Info("need reconnect with protocol:", protocol)
|
||
g.pdu.Emit("close")
|
||
exitFlag <- true
|
||
})
|
||
g.x224.On("more_timeout", func() {
|
||
timeout += 18 //如果是PROTOCOL_RDP协议,可以适当延长超时时间
|
||
})
|
||
|
||
err = g.x224.Connect()
|
||
if err != nil {
|
||
return status, fmt.Errorf("[x224 connect err] %v", err), reconnProtocol
|
||
}
|
||
glog.Info("wait connect ok")
|
||
|
||
g.pdu.On("error", func(e error) {
|
||
err = e
|
||
glog.Error("error", e)
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("close", func() {
|
||
err = errors.New("close")
|
||
glog.Info("on close")
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("success", func() {
|
||
glog.Debugf("===============login success %s===============", ip)
|
||
status = true
|
||
err = nil
|
||
g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("ready", func() {
|
||
err = nil
|
||
glog.Debug("on ready")
|
||
//g.pdu.Emit("done")
|
||
})
|
||
g.pdu.On("bitmap", func(rectangles []pdu.BitmapData) {
|
||
now = time.Now()
|
||
// 发送一个鼠标事件,作用是与服务器保持联系不要断开
|
||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||
randomNumber := rand.Intn(1000) + 10 // 10到1000之间的随机数
|
||
mouseX := 60 + randomNumber
|
||
mouseY := 10 + randomNumber
|
||
pevent := &pdu.PointerEvent{}
|
||
pevent.PointerFlags |= pdu.PTRFLAGS_MOVE
|
||
pevent.XPos = uint16(mouseX)
|
||
pevent.YPos = uint16(mouseY)
|
||
g.pdu.SendInputEvents(pdu.INPUT_EVENT_MOUSE, []pdu.InputEventsInterface{pevent})
|
||
|
||
glog.Debug("on update bitmap:", len(rectangles))
|
||
refresh <- true
|
||
|
||
})
|
||
g.pdu.On("done", func() {
|
||
glog.Debug("done信号触发")
|
||
exitFlag <- true
|
||
})
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout*6)*time.Second)
|
||
defer cancel()
|
||
|
||
loop:
|
||
for {
|
||
select {
|
||
case <-time.After(time.Second * time.Duration(timeout*3)): //
|
||
glog.Debug("本次获取bitmap超时了, 距离上次获取到图像过去了:", time.Since(now))
|
||
break loop
|
||
case <-refresh:
|
||
continue loop
|
||
case <-exitFlag:
|
||
break loop
|
||
case <-ctx.Done():
|
||
glog.Debug("总超时已达到,退出")
|
||
break loop
|
||
}
|
||
}
|
||
glog.Debug("循环结束,总时间过去了:", time.Since(start))
|
||
|
||
// 认证结果由 success 事件回调设置,不在此处覆盖
|
||
return status, err, reconnProtocol
|
||
}
|