プロジェクト

全般

プロフィール

ZeroWidthSpace » 履歴 » リビジョン 2

リビジョン 1 (kanata, 2025/04/13 14:02) → リビジョン 2/3 (kanata, 2025/04/13 14:03)

# ZeroWidthSpace 

 {{rawhtml(<canvas id="map"></canvas><script src="/javascripts/pagemap.min.js"></script><script>pagemap(document.querySelector("#map"));</script>)}} 

 {{toc}} 

 {{rawhtml(<iframe src="//www.slideshare.net/slideshow/embed_code/key/xsLdg6etgkh9K6" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/kanata1/unicode-104771309" title="Unicodeゼロ幅文字 難読化シェル芸" target="_blank">Unicodeゼロ幅文字 難読化シェル芸</a> </strong> from <strong><a href="https://www.slideshare.net/kanata1" target="_blank">kanata -</a></strong> </div>)}} 


 # 動機 : 先日こういう話題があった 

 {{rawhtml(<blockquote class="embedly-card"><h4><a href="http://developer.cybozu.co.jp/akky/2018/04/leaker-detection-by-zero-width-characters/">ゼロ幅文字にエンコードした隠し情報で、文書をリークしたメンバーを特定</a></h4><p>とある会員制掲示板からの文書の流出に困った運営者が、 ユニコードの見えない文字「ゼロ幅文字(Zero-Width characters)」を使って流出させたユーザーを特定した、という話 が出ていました。 ...</p></blockquote><script async src="//cdn.embedly.com/widgets/platform.js" charset="UTF-8"></script>)}} 

 * 要約 
  * 競技ビデオゲームのチームが、プライベートの掲示板を利用 
  * 外部の掲示板にコピペしているやつがいた 
  * 見た目がわからない文字を仕込んで犯人を特定 

 # 原理 : Unicodeゼロ幅スペースを仕込んだ 

 ## ゼロ幅スペース([Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%BC%E3%83%AD%E5%B9%85%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9)) 

 コンピュータの組版に用いられる非表示文字で、文書処理システムに対して語の切れ目を示すのに用いる 

 [めっちゃ種類ある](http://anti.rosx.net/etc/memo/002_space.html) 

 U+034F , U+200B , U+200C , U+200D , U+200E , U+200F , U+2028 , U+2029 , U+202A , U+202B , U+202C , U+202D , U+202E , U+2061 , U+2062 , U+2063 , U+FEFF 

 # いろんな事に(難読化シェル芸)に使えるんじゃ・・・! 

 [元ネタ](https://github.com/umpox/zero-width-detection/blob/071dfd52aede7510952b05840ffec7f8a940e6cb/src/utils/usernameToZeroWidth.js)に習って4種類を使う ⇒ 4進数で表現できる! 

 | CodePoint | 名称         | デコード時 | 
 |-----------|-----------|------------| 
 | U+200B      | ゼロ幅空白                       | 0 
 | U+200C      | ゼロ幅非接合子(筆記体の時の制御) | 1 
 | U+200D      | ゼロ幅接合子(筆記体の時の制御)     | 2 
 | U+FEFF      | ゼロ幅のノーブレークスペース       | 3 

 ## ゼロ幅スペースにエンコード 

 1. 文字を16進数に変換(xxd) 
 2. 16進数を4進数に変換(bc) 
 3. 0 1 2 3 をゼロ幅スペースに置換(sed) 

 ```bash 
 ZWS1=$'\u200b' 
 ZWS2=$'\u200c' 
 ZWS3=$'\u200d' 
 ZWS4=$'\ufeff' 

 echo "unko" |xxd -p|tr a-z A-Z \ 
   |sed 's/^/obase=4; ibase=16; &/g'|bc \ 
   |sed s/0/$ZWS1/g |sed s/1/$ZWS2/g \ 
   |sed s/2/$ZWS3/g |sed s/3/$ZWS4/g  
 ``` 

 ## 仕込んだゼロ幅スペースのデコード 

 1. ゼロ幅スペースを 0 1 2 3 に置換(sed) 
 2. 16進数に変換(bc) 
 3. バイナリに変換(xxd) 

 ```bash 
 ZWS1=$'\u200b' 
 ZWS2=$'\u200c' 
 ZWS3=$'\u200d' 
 ZWS4=$'\ufeff' 

 echo '‌‌‌‌‍‍‌‍‍‌‍​​‍‍' \ 
   |sed s/$ZWS1/0/g |sed s/$ZWS2/1/g \ 
   |sed s/$ZWS3/2/g |sed s/$ZWS4/3/g \ 
   |sed 's/^/obase=16; ibase=4; &/g'|bc|xxd -ps -r 
 ``` 

 ※ echo '' の''にはゼロ幅スペース入ってる 

 # Twitter用 Unicodeゼロ幅スペースぶっ込みツール に作り直した 

 TwitterやSNSで使える種類が限られていることがわかった。 

 {{rawhtml(<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">こんどTwitter対応やってみます <a href="https://twitter.com/hashtag/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8?src=hash&amp;ref_src=twsrc%5Etfw">#シェル芸</a> <a href="https://twitter.com/hashtag/%E3%81%99%E3%81%BF%E3%81%BE%E3%81%9B%E3%82%93%E5%8B%95%E3%81%8F%E3%81%A3%E3%81%A6%E8%A8%80%E3%81%A3%E3%81%A6%E5%8B%95%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%E3%81%A7%E3%81%97%E3%81%9F%E8%A8%B1%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%81%AA%E3%82%93%E3%81%A7%E3%82%82%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B%E3%82%89?src=hash&amp;ref_src=twsrc%5Etfw">#すみません動くって言って動きませんでした許してくださいなんでもしますから</a> <a href="https://t.co/gUjAI3x9wt">https://t.co/gUjAI3x9wt</a></p>&mdash; kanata (@kanata201612) <a href="https://twitter.com/kanata201612/status/1016273710846697472?ref_src=twsrc%5Etfw">2018年7月9日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>)}} 

 調査してTwitter用に良さそうな4種類のゼロ幅スペースを確認する 

 {{rawhtml(<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">結果、Twitterに仕込んでも大丈夫そうなゼロ幅スペース <a href="https://twitter.com/hashtag/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8?src=hash&amp;ref_src=twsrc%5Etfw">#シェル芸</a><br><br>U+200B<br>U+200C<br>U+200D<br>U+2062<br><br>もうちょっと確認してみよう</p>&mdash; kanata (@kanata201612) <a href="https://twitter.com/kanata201612/status/1018409987654053889?ref_src=twsrc%5Etfw">2018年7月15日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> )}} 

 [シェル芸bot](https://twitter.com/minyoruminyon)氏のことも考慮して、割と真面目に作り直した 

 ## Instration 

 ファイルダウンロードして実行権限をつけるだけ 

 ```bash 
 $ wget https://raintrees.net/attachments/download/486/zws 
 $ chmod u+x ./zws 
 ``` 

 ### 最新版について 

 現在、githubにて最新版を管理しています。インタフェースをbase64と全く同じに修正(してもらい)ました。 
 https://github.com/kanata2003/ZeroWidthSpace 

 ### 動作環境 

 ただのシェルスクリプトなので、だいたいの環境(Linux,Mac,Unix)で動くのでは 

 以下で、動作確認しました。 

 * CentOS Linux release 7.2.1511 x86_64 

 ## Usage 

 ### エンコード 

 実行すると '' が出力されるが間にゼロ幅スペースが詰まっている 

 ```bash 
 ./zws unko 
 '‌⁢‌‌​​‍‍‌‍⁢‍​​‍‍‌‍‍⁢​​‍‍‌‍⁢⁢​​‍‍' 
 ``` 

 パイプ経由でもできる 

 ```bash 
 echo "unko"|./zws 
 '‌⁢‌‌​​‍‍‌‍⁢‍​​‍‍‌‍‍⁢​​‍‍‌‍⁢⁢​​‍‍' 
 ``` 

 ちなみにTwitterでは、ゼロ幅スペースはアスキー文字と同等に数えられるらしく、140文字ではなく280文字までいけた 
 エンコードサイズが280文字を超えるとWARNINGを出すようにしている(エンコード自体はする) 

 ```bash 
 ./zws aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
 [WARN] This encoded size over 280 characters. You can not tweet. Now 285 characters. 
 '‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌‌‍​‌​​‍‍' 
 ``` 

 [シェル芸bot](https://twitter.com/minyoruminyon)氏はゼロ幅スペースを普通にマルチバイト文字として数える(140文字制限)ので、bot氏に処理をお願いする時は140文字までの制限を意識する必要がございます 

 ゼロ幅スペースの文字数を数えるには wc -m コマンドで数えることができます 

 ```bash 
 ./zws 'I hava an apple'|wc -m 
 67 
 ``` 

 この短めの文で67文字も使うのでTwitterにはあまり長い文字列が仕込めません 

 ### デコード 

 base64コマンドっぽいインタフェースにした 
 ゼロ幅スペース以外の文字があっても、そこは無視してデコードする 

 ```bash 
 ./zws -d 'this is a pen‌⁢‌‌​​‍‍‌‍⁢‍​​‍‍‌‍‍⁢​​‍‍‌‍⁢⁢​​‍‍' 
 unko 
 ``` 

 もちろんパイプ経由でもいける 

 ```bash 
 echo '‌⁢‌‌​​‍‍‌‍⁢‍​​‍‍‌‍‍⁢​​‍‍‌‍⁢⁢​​‍‍'|./zws -d 
 unko 
 ``` 

 # 使えるシュチュエーション 
 ## このシェル芸を実行したのは誰だ! 

 ```bash 
 ./zws -d 'echo unko⁢‍‌⁢‍‍‌⁢‍​​‌⁢‍​⁢‍​​‌‍‍‌⁢⁢‍​⁢‍​​‌‍‌‍‌​​‍‍' 
 私です 
 ``` 
 ## 裏手順を隠しておく 

 ```bash 
 ./zws -d 'stop.sh #アプリを停止、yを入力‌⁢​​‌‍‍⁢‌‍‍‌‌‍⁢​‌‍⁢​​‍​​‌‍​‌‌⁢​​‌‍⁢​‌‍‍‌​​‍‍' 
 pkill apli 
 ``` 

 ## 呪いを込めておく 

 ```bash 
 ./zws -d 'Start.sh #アプリ起動⁢‍‌‌‍⁢‍​‍⁢​​⁢‍​⁢‍​​‍‍​‍‍⁢‍​⁢‍​​‌‍‌⁢⁢⁢‍​⁢‍​​‌‍​‌​​​‍‍' 
 帰りたい 
 ``` 

 ## 暗号的やり取り 

 実はTwitterはゼロ幅スペースが使えます 

 他のSNSでも使えそう(未確認) 

 ```bash 
 ./zws -d '草⁢‍‌⁢‍​‍‌‍⁢‍‌⁢‍‌‌‍‍​⁢‍⁢​‍⁢‍​⁢‍​​‌‍‍​​⁢‍​⁢‍​​‌‍‌⁢‍​​‍‍' 
 特売だぞ 
 ``` 

 ## 難読化シェル芸 

 echoと見せかけたdateの実行 

 ```bash 
 echo 'echo unko‌‍‌​‌‍​‌‌⁢‌​‌‍‌‌​​‍‍'|./zws -d|bash 
 2018年    7月 16日 月曜日 10:26:37 JST 
 ``` 

 # 他の実装 

 * ExcelのVBAで[風柳](https://twitter.com/furyutei)さんが実装しています 

 [Excel][VBA] ゼロ幅スペースを利用した情報隠蔽の試み 
 https://gist.github.com/furyutei/6bba0eaf5e0bcb4ae1ee30f916cfcb04 

 * 短縮URLのサービスで実装されています 

 Zero Width Shortener 
 https://zws.im/