July 1, 2020

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

Antonio Morales

Summary

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.

Product

FreeRDP

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.

Impact

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

CVE

  • CVE-2020-11097

Coordinated Disclosure Timeline

This report was subject to the GHSL coordinated disclosure policy.

  • 05/22/2020: Vendor contacted
  • 05/26/2020: Vendor acknowledges report
  • 06/22/2020: Bug fixed and patch released by the vendor

Supporting Resources

Credit

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

Contact

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