skip to content
Back to
Home Research Advisories CodeQL Wall of Fame Get Involved Events
July 1, 2020

GHSL-2020-104: OOB read vulnerability in FreeRDP ntlm_av_pair_get - CVE-2020-11097

Antonio Morales


An out-of-bounds (OOB) read vulnerability has been detected in ntlm_av_pair_get function due to a corrupted NTLM_AV_PAIR linked-list.



Tested Version

Development version - master branch (May 22, 2020)

Details: Out-of-bound read in ntlm_av_pair_get

The ntlm_av_pair_get function in ntlm_av_pairs.c performs a call to ntlm_av_pair_get_id(pAvPair) (line 173), where pAvPair is a pointer to a linked-list of NTLM_AV_PAIR. The problem here is that pAvPairList may be a corrupted linked-list:

View on GitHub!

/* winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c */

NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
                               size_t* pcbAvPairListRemaining)
	size_t cbAvPair = cbAvPairList;
	NTLM_AV_PAIR* pAvPair = pAvPairList;

	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
		pAvPair = NULL;

	while (pAvPair)
		UINT16 id = ntlm_av_pair_get_id(pAvPair);

The corruption is a result of a previously read malformed linked-list member values. Let’s take a closer look at how this corruption occurs:

View on GitHub!

/* winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c */

int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
 ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
 AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL);

As you can see above, ChallengeTargetInfo is the linked-list which is passed as an argument to ntlm_av_pair_get function, and that, in turn, is equal to context->ChallengeTargetInfo.pvBuffer. Next we will see how context->ChallengeTargetInfo is used in the ntlm_read_message_fields_buffer function:

View on GitHub!

/* winpr/libwinpr/sspi/NTLM/ntlm_message.c */

ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
 if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0)
 goto fail;

 context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer;

At this point, the problem is that the FreeRDP client is reading these offsets directly from the server, without checking they are correct.

So, a malicious attacker could set a malicious offset and when ntlm_av_pair_get_id will be called, the program will try to access a non-existent list member:

View on GitHub!

/* winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c */

static INLINE UINT16 ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair)
	UINT16 AvId;

	Data_Read_UINT16(&pAvPair->AvId, AvId);

	return AvId;

As a result, OOB reads can occurs resulting in accessing memory that has not been allocated by FreeRDP process.


This issue may lead to Out-of-Bounds read.


Coordinated Disclosure Timeline

This report was subject to the GHSL coordinated disclosure policy.

Supporting Resources


This issue was discovered and reported by GHSL team member @antonio-morales (Antonio Morales).


You can contact the GHSL team at, please include the GHSL-2020-104 in any communication regarding this issue.