#161 Unicode
CTFでUnicodeを扱う問題に出会いました。文字コードの扱いや変換などで思いもしないバグが発生することは少なくないので、しっかり勉強しておきたいと思います。
Unicodeとは
Unicodeは、世界で使われているあらゆる文字を、ひとつの文字集合で扱えるようにしたものです。0 - 10FFFFまでのコードポイントで表現され、最大111万4,112文字まで収録できます。
最新のバージョンは、Unicode 16.0.0で、154,998文字が登録されています。
Unicodeの仕様や、歴史的な背景はとにかく複雑でとても追いきれません。それゆえか、実装のミスや勘違いなどから脆弱性につながることも多くあります。例えば、Shift-JISの¥マークとASCIIのバックスラッシュ(\)は、同じコードポイント(0x5C)に割り当てられていますが、バックスラッシュがエスケープなどの特殊な用途に使われることからも間違えると危ないことになります。
UTF-8
プログラムを書いていると、UTF-8をやたらと目にします。あまり意味を理解しないまま使っていましたが、これはUnicodeの符号化方式のひとつです。1から4バイトでUnicodeの文字を表現する方式で、インターネット上では、最もよく使われています。
符号化方式には他にも、UTF-16やUTF-32があり、さらに、それぞれビッグエンディアン・リトルエンディアンのバージョンがあります。BOMをつけたりつけなかったりするパターンもあります。
もう意味不明ですね。
サロゲートペア
UTF-16では、2文字分を使って1文字を表すための仕組みがあります。U+D800 〜 U+DBFFをハイサロゲート、U+DC00 〜 U+DFFFをローサロゲートと呼び、例えば絵文字や、標準でない漢字などの表現に使われています。
セキュリティ
JavaScriptやPythonでは、Unicodeを文字列としてそのまま扱えます。
// javascript
var a = '\u0041' // 'A'
// python
b = '\u0042' // 'B'
これは、特殊記号をフィルターしている場合の、バイパスに使えたりしますね。こういう変な表記方法はフィルターでカバーできていないことが多いですから。
また、Unicodeに限らない、文字コードの問題を考えてみます。
文字化けを見ることはだいぶ少なくなりましたが、Shift-JISで書かれた文書をUTF-8の設定で開くと確実に文字化けしますよね。文字の符号化方式が違うので、当然です。しかし、もし偶然にも、Shift-JISの表現が、UTF-8の表現としても適切なものだったらどうでしょう?
例えば、イメージですが、
(Shift-JIS) 細そうすぎる
↓
(UTF-8)<script>alert(1)</script>
こんな感じで変換されてしまったらやばそうですね。
無害なはずだった文字列が、文字コードが変わるだけで攻撃ペイロードになってしまいます。実際に、文字コードの変換を逆手にとった攻撃は盛んに研究されているようで、CTFでも出題されることがあります。ブラウザや、文字を扱う関数などで、勝手に文字コードを推定して解釈する場合もあるので、思っていた挙動と違うことが起きることもあります。
実際に攻撃に使うには、もっといろいろ実験して、理解を深めないと難しそうです。U+19E0を見て、クメール文字の「᧠」だなとわかるぐらいにはなりたいですね。
EOF