In context of my work on protection against
Billion Laughs Attacks
I played with the existing protection
against those attacks. As an unintended byproduct,
that led me to finding a bypass of that protection,
a new vulnerability in libxml2
prior to 2.9.11
that I call Parameter Laughs;
it has been assigned CVE number
CVE-2021-3541 and is known as libxml2 issue 228 upstream.
Parameter Laughs is based upon well-known ideas from the Billion Laughs Attack — both use nested entities to amplify a small payload of a few hundred bytes up to gigabytes of content to process and hence wasting loads of RAM, CPU time, or both — but in contrast Parameter Laughs…
- uses parameter entities
%) rather than general entities (syntax
- uses delayed interpretation
to effectively sneak use of parameter entities
into the so-called "internal subset" of the XML document
(the "here" in
<!DOCTYPE r [here]>) where undisguised parameter entities are not allowed, with regard to the XML specification.
What do I mean by "delayed interpretation"? Let us declare a parameter entity like this:
<!ENTITY % pe_2 "%pe_1;<!---->%pe_1;">
Now during replacement of reference
% is turned into
That triggers two new rounds of replacement
%pe_2; has been fully replaced —
there you have the delay (and the exponential growth).
Here is what Parameter Laughs looks like as a complete XML document (added 2021-05-25):
<?xml version="1.0"?> <!-- "Parameter Laughs", i.e. variant of Billion Laughs Attack using delayed interpretation of parameter entities Copyright (C) Sebastian Pipping <firstname.lastname@example.org> --> <!DOCTYPE r [ <!ENTITY % pe_1 "<!---->"> <!ENTITY % pe_2 "%pe_1;<!---->%pe_1;"> <!ENTITY % pe_3 "%pe_2;<!---->%pe_2;"> %pe_3; <!-- not at full potential, increase towards "%pe40;" carefully --> ]> <r/>
Compared to something like arbitrary code execution, Parameter Laughs is "only" a denial of service attack. Its eager use of RAM made my machine need a hard reset in practice: maybe that's something that you want to be protected against, too.