Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 248 additions & 4 deletions pkg/apf/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ func Process(data []byte, session *Session) bytes.Buffer {
var dataToSend interface{}

switch data[0] {
case APF_KEEPALIVE_REQUEST:
log.Debug("received APF_KEEPALIVE_REQUEST")

dataToSend = ProcessKeepAliveRequest(data, session)
case APF_KEEPALIVE_REPLY:
log.Debug("received APF_KEEPALIVE_REPLY")

// dataToSend = ProcessKeepAliveReply(data, session)
case APF_KEEPALIVE_OPTIONS_REPLY:
log.Debug("received APF_KEEPALIVE_OPTIONS_REQUEST")

// dataToSend = ProcessKeepAliveOptionsReply(data, session)
case APF_GLOBAL_REQUEST: // 80
log.Debug("received APF_GLOBAL_REQUEST")

Expand Down Expand Up @@ -73,6 +85,9 @@ func Process(data []byte, session *Session) bytes.Buffer {
dataToSend = ProcessProtocolVersion(data)
}
case APF_USERAUTH_REQUEST: // 50
log.Debug("received APF_USERAUTH_REQUEST")

dataToSend = ProcessUserAuthRequest(data, session)
default:
}

Expand All @@ -83,9 +98,235 @@ func Process(data []byte, session *Session) bytes.Buffer {
}
}

// fmt.Printf("bin_buf: %x\n", bin_buf.Bytes())

return bin_buf
}

func ProcessKeepAliveRequest(data []byte, session *Session) any {
if len(data) < 5 {
log.Warn("APF_KEEPALIVE_REQUEST message too short")

return APF_KEEPALIVE_REPLY_MESSAGE{}
}

cookie := binary.BigEndian.Uint32(data[1:5])
log.Debugf("received APF_KEEPALIVE_REQUEST with cookie: %d", cookie)

reply := APF_KEEPALIVE_REPLY_MESSAGE{
MessageType: APF_KEEPALIVE_REPLY,
Cookie: cookie,
}

return reply
}

func ProcessKeepAliveReply(data []byte, session *Session) {
if len(data) < 5 {
log.Warn("APF_KEEPALIVE_REPLY message too short")

return
}

cookie := binary.BigEndian.Uint32(data[1:5])
log.Debugf("received APF_KEEPALIVE_REPLY with cookie: %d", cookie) // TODO: Update session state if necessary
}

func ProcessKeepAliveOptionsReply(data []byte, session *Session) {
if len(data) < 9 {
log.Warn("APF_KEEPALIVE_OPTIONS_REPLY message too short")

return
}

keepaliveInterval := binary.BigEndian.Uint32(data[1:5])
timeout := binary.BigEndian.Uint32(data[5:9])
log.Debugf("KEEPALIVE_OPTIONS_REPLY, Keepalive Interval=%d Timeout=%d", keepaliveInterval, timeout) // TODO: // Update session state or configurations as needed
}

func ProcessUserAuthRequest(data []byte, session *Session) interface{} {
log.Debug("received APF_USERAUTH_REQUEST")

dataBuffer := bytes.NewReader(data)

var messageType byte

err := binary.Read(dataBuffer, binary.BigEndian, &messageType)
if err != nil {
log.Error(err)

return nil
}

// Read username length
var usernameLen uint32

err = binary.Read(dataBuffer, binary.BigEndian, &usernameLen)
if err != nil {
log.Error(err)

return nil
}

if usernameLen > 2048 || uint32(dataBuffer.Len()) < usernameLen {
log.Error("Invalid username length")

return nil
}

usernameBytes := make([]byte, usernameLen)

n, err := dataBuffer.Read(usernameBytes)
if err != nil || n != int(usernameLen) {
log.Error("Failed to read username")

return nil
}

username := string(usernameBytes)

// Read serviceName length
var serviceNameLen uint32

err = binary.Read(dataBuffer, binary.BigEndian, &serviceNameLen)
if err != nil {
log.Error(err)

return nil
}

if serviceNameLen > 2048 || uint32(dataBuffer.Len()) < serviceNameLen {
log.Error("Invalid serviceName length")

return nil
}

serviceNameBytes := make([]byte, serviceNameLen)

n, err = dataBuffer.Read(serviceNameBytes)
if err != nil || n != int(serviceNameLen) {
log.Error("Failed to read serviceName")

return nil
}

serviceName := string(serviceNameBytes)

// Read methodName length
var methodNameLen uint32

err = binary.Read(dataBuffer, binary.BigEndian, &methodNameLen)
if err != nil {
log.Error(err)

return nil
}

if methodNameLen > 2048 || uint32(dataBuffer.Len()) < methodNameLen {
log.Error("Invalid methodName length")

return nil
}

methodNameBytes := make([]byte, methodNameLen)

n, err = dataBuffer.Read(methodNameBytes)
if err != nil || n != int(methodNameLen) {
log.Error("Failed to read methodName")

return nil
}

methodName := string(methodNameBytes)

if methodName == "password" {
if dataBuffer.Len() < 1 {
log.Error("Not enough data for password FALSE byte")

return nil
}
// Read boolean FALSE
var passwordFalse byte

err = binary.Read(dataBuffer, binary.BigEndian, &passwordFalse)
if err != nil {
log.Error(err)

return nil
}

if passwordFalse != 0 {
log.Error("passwordFalse is not zero")

return nil
}

// Read password length
var passwordLen uint32

err = binary.Read(dataBuffer, binary.BigEndian, &passwordLen)
if err != nil {
log.Error(err)

return nil
}

if passwordLen > 2048 || uint32(dataBuffer.Len()) < passwordLen {
log.Error("Invalid password length")

return nil
}

passwordBytes := make([]byte, passwordLen)

n, err = dataBuffer.Read(passwordBytes)
if err != nil || n != int(passwordLen) {
log.Error("Failed to read password")

return nil
}

_ = string(passwordBytes)
} else {
// Unsupported method
log.Warn("Unsupported authentication method: ", methodName)
// Return failure
// failureMessage := &APF_USERAUTH_FAILURE_MESSAGE{
// MessageType: APF_USERAUTH_FAILURE,
// AuthenticationsThatCanContinueLength: uint32(len("password")),
// AuthenticationsThatCanContinue: []byte("password"),
// PartialSuccess: 0,
// }
// return failureMessage
return nil
}

log.Debugf("usernameLen=%d serviceNameLen=%d methodNameLen=%d", usernameLen, serviceNameLen, methodNameLen)
log.Debugf("username=%s serviceName=%s methodName=%s", username, serviceName, methodName)

// Now authenticate the user
authenticated := true // session.AuthenticateUser(username, password)

if authenticated {
// Return success message
message := &APF_USERAUTH_SUCCESS_MESSAGE{
MessageType: APF_USERAUTH_SUCCESS,
}

return message
} else {
// Return failure message
// failureMessage := &APF_USERAUTH_FAILURE_MESSAGE{
// MessageType: APF_USERAUTH_FAILURE,
// AuthenticationsThatCanContinueLength: uint32(len("password")),
// AuthenticationsThatCanContinue: []byte("password"),
// PartialSuccess: 0,
// }
// return failureMessage
return nil
}
}

func ProcessChannelWindowAdjust(data []byte, session *Session) {
adjustMessage := APF_CHANNEL_WINDOW_ADJUST_MESSAGE{}
dataBuffer := bytes.NewBuffer(data)
Expand Down Expand Up @@ -170,11 +411,14 @@ func ProcessGlobalRequest(data []byte) interface{} {
log.Tracef("%+v", tcpForwardRequest)

if genericHeader.String == APF_GLOBAL_REQUEST_STR_TCP_FORWARD_REQUEST {
if tcpForwardRequest.Port == 16992 || tcpForwardRequest.Port == 16993 {
reply = TcpForwardReplySuccess(tcpForwardRequest.Port)
} else {
reply = APF_REQUEST_FAILURE
// if tcpForwardRequest.Port == 16992 || tcpForwardRequest.Port == 16993 {
reply = TcpForwardReplySuccess(tcpForwardRequest.Port)

if tcpForwardRequest.Port == 5900 {
}
// } else {
// reply = APF_REQUEST_FAILURE
// }
} else if genericHeader.String == APF_GLOBAL_REQUEST_STR_TCP_FORWARD_CANCEL_REQUEST {
reply = APF_REQUEST_SUCCESS
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/apf/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ const (
APF_CHANNEL_DATA = 94
APF_CHANNEL_CLOSE = 97
APF_PROTOCOLVERSION = 192
APF_KEEPALIVE_REQUEST = 208
APF_KEEPALIVE_REPLY = 209
APF_KEEPALIVE_OPTIONS_REPLY = 211
)

// disconnect reason codes.
Expand Down Expand Up @@ -93,6 +96,11 @@ type APF_MESSAGE_HEADER struct {
MessageType byte
}

type APF_KEEPALIVE_REPLY_MESSAGE struct {
MessageType byte
Cookie uint32
}

/**
* APF_GENERIC_HEADER - generic request header (note that its not complete header per protocol (missing WantReply)
*
Expand Down
2 changes: 2 additions & 0 deletions pkg/wsman/client/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

import (
"crypto/tls"
"net"
"net/http"
)

Expand All @@ -17,6 +18,7 @@ type Parameters struct {
Transport http.RoundTripper
IsRedirection bool
PinnedCert string
Connection net.Conn
TlsConfig *tls.Config
AllowInsecureCipherSuites bool
}
5 changes: 5 additions & 0 deletions pkg/wsman/client/wsman_tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func NewWsmanTCP(cp Parameters) *Target {
UseTLS: cp.UseTLS,
InsecureSkipVerify: cp.SelfSignedAllowed,
PinnedCert: cp.PinnedCert,
conn: cp.Connection,
bufferPool: sync.Pool{
New: func() interface{} {
return make([]byte, 4096) // Adjust size according to your needs.
Expand All @@ -37,6 +38,10 @@ func NewWsmanTCP(cp Parameters) *Target {
// Connect establishes a TCP connection to the endpoint specified in the Target struct.
func (t *Target) Connect() error {
var err error
// already connected and connection has been provided
if t.conn != nil {
return nil
}

if t.UseTLS {
// check if pinnedCert is not null and not empty
Expand Down
Loading