shadow1ng/fscan · error

Unknown data pdu type2 0x%02x

Error message

Unknown data pdu type2 0x%02x

What it means

readDataPDU in libs/grdp/protocol/pdu/data.go dispatches on the share-data header's pduType2 field. When the received slow-path data PDU type2 is not one the library implements (e.g. an unhandled control/server-directory/notification type), it returns this error. It means the server sent a share control/data PDU type this client cannot decode.

Source

Thrown at libs/grdp/protocol/pdu/data.go:480

	case PDUTYPE2_CONTROL:
		d = &ControlDataPDU{}

	case PDUTYPE2_FONTLIST:
		d = &FontListDataPDU{}

	case PDUTYPE2_SET_ERROR_INFO_PDU:
		d = &ErrorInfoDataPDU{}

	case PDUTYPE2_FONTMAP:
		d = &FontMapDataPDU{}

	case PDUTYPE2_SAVE_SESSION_INFO:
		glog.Debug("SAVE_SESSION_INFO event triggered, login successful")
		d = &SaveSessionInfo{}

	default:
		err = errors.New(fmt.Sprintf("Unknown data pdu type2 0x%02x", header.PDUType2))
		glog.Error(err)
		return nil, err
	}

	err = d.Unpack(r)
	if err != nil {
		glog.Error("Read data pdu:", err)
		return nil, err
	}

	p := &DataPDU{
		Header: header,
		Data:   d,
	}
	return p, nil
}

type DataPDUData interface {

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Identify the 0x%02x value and add a case/struct for that PDUTYPE2 in data.go, or change the default branch to skip/ignore unknown data PDUs and continue the session loop
  2. Disable server features that trigger the exotic PDU (disable session info advertisement, RAIL, status tracking) in the client's capability/negotiation data
  3. Confirm the stream is aligned — a misparsed earlier PDU shifts bytes so a random byte lands in pduType2; test against a reference client (mstsc) to the same server
  4. Update grdp to a version with broader PDUTYPE2 coverage

Example fix

// before (data.go readDataPDU)
default:
	err = errors.New(fmt.Sprintf("Unknown data pdu type2 0x%02x", header.PDUType2))
	glog.Error(err)
	return nil, err
// after: tolerate unknown types
default:
	glog.Warn("ignoring unknown data pdu type2 0x%02x", header.PDUType2)
	return nil, nil
Defensive patterns

Strategy: try-catch

Try / catch

pdu, err := session.ReadDataPDU()
if err != nil {
    if strings.Contains(err.Error(), "Unknown data pdu type2") {
        log.Printf("skipping unsupported PDU: %v", err)
        return nil // tolerate and continue session
    }
    return err
}

Prevention

When it happens

Trigger: During an RDP session, the server sends a slow-path Data PDU whose pduType2 byte is outside the supported set (PDUTYPE2_UPDATE, PDUTYPE2_CONTROL, PDUTYPE2_POINTER, PDUTYPE2_INPUT, PDUTYPE2_SYNCHRONIZE, PDUTYPE2_SAVE_SESSION_INFO, etc.), typically inside readDataPDU invoked by the session read loop.

Common situations: Windows servers emitting optional PDUs (e.g. PDUTYPE2_STATUS_WINDOW_TRACKING, PDUTYPE2_SHUTDOWN_DENIED) the Go client never implemented; stream desynchronization after a previous malformed PDU; connecting to terminal servers with session-redirection or RAIL features enabled.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/2fa974a38d0039bc. Report an issue: GitHub.