ネットエージェント株式会社 オフィシャルブログ

長谷川陽介

bashにおける脆弱性「Shellshock」について

LinuxやMac OS XなどのUNIX系OSで広く使用されているbashに見つかった脆弱性(Shellshockと呼ばれています)が先日から話題になっています。
弊社でもこのbashの脆弱性について調査を行いました。

■概要
環境変数に特定の文字列を設定するだけでその環境変数内の文字列をシェルが関数として実行してしまいます。
シェルを通じてコマンド等を実行する幅広い環境で影響がありますが、特に顕著に影響を受けるのはCGI等のWebアプリケーション環境です。
CGIをはじめとするWebアプリケーションではWebブラウザからのHTTPリクエストヘッダなどに含まれる各種の情報を環境変数を通じて取得するため、攻撃にも応用しやすいからです。

今回の脆弱性は、攻撃者にとっては非常に簡単な方法で攻撃が可能であり、現在すでにこの脆弱性を利用した攻撃が広く観測されているため、早急に対応が必要となります。
特に、CentOSではデフォルトで/bin/shがbashへのシンボリックリンクとなっており、影響を受けやすいため注意が必要です。

■脆弱性のあるbashかどうかの確認方法
コマンドライン上で
$ X='() { :;}; echo vuln' bash -c 'echo'
を実行します。このとき、画面に vuln の文字列が表示されるようであればお使いのbashは脆弱性のあるバージョンとなります。

※vuln の文字列が表示されない場合であっても、脆弱性に対応するために現在リリースされているパッチでは修正が不十分という可能性もありますので、ベンダの情報やJPCERT/CCによる緩和策等を参考にしてください。

参考: GNU bash の脆弱性に関する注意喚起(JPCERT/CC)

■攻撃有無の簡易的な確認
Webサーバのアクセスログから「() {」という文字列を含むリクエストが存在していないかを調べます。
[root@www httpd]# grep '() {' access_log
2xx.1xx.2xx.7x - - [25/Sep/2014:07:15:16 +0900] "GET / HTTP/1.0" 200 2217 "() { :; }; ping -c 11 2xx.xxx.xxx.7x" "shellshock-scan (http://blog.*********.com/2014/09/bash-shellshock-scan-of-internet.html)"
2xx.1xx.2xx.7x - - [25/Sep/2014:13:41:18 +0900] "GET / HTTP/1.0" 200 2217 "() { :; }; ping -c 11 2xx.xxx.xxx.7x" "shellshock-scan (http://blog.*********.com/2014/09/bash-shellshock-scan-of-internet.html)"


これは脆弱性がある場合には攻撃者の用意したサイトへpingを発行するという攻撃の準備のためのコードをリファラに仕込んでいたときのログで、研究を目的としたスキャンのようです。
ただし、このログによる確認方法は簡易的なものであり、User-Agentやリファラ以外の例えばAccept-Encodingやその他のカスタムリクエストヘッダなどに攻撃用コードを仕込んでいた場合には一般的にはログに記録されないため、この確認方法では攻撃の有無を把握することはできません。

そのため、攻撃を確実に把握するためにはすべてのHTTPの通信を記録しておくことが望ましいと言えます。弊社 PacketBlackHole を用いるとHTTPをはじめとする通信の記録、確認が容易に行えます。

■影響の範囲
Webサーバをはじめとし、bashがインストールされているLinuxやUNIX環境すべてが対象となりますが、その脆弱性を利用して外部から実際に攻撃、侵入ができるかどうかについては設定や使用しているプログラムによるところが大きく、すべてのサーバが即座に侵入可能というわけではありません。

脆弱性のあるbashが存在するWebサーバに対しては、攻撃者がHTTPリクエストヘッダに脆弱性を利用した攻撃コードを含めてHTTPリクエストを発行し、それに対してWebアプリケーション攻撃が応答するだけで攻撃が成立してしまいます。

Webアプリケーションが影響を受けるのは、シェルを経由して外部コマンドを起動する部分となります。各言語において外部コマンドを起動するための関数や命令は異なっており、それぞれがシェルを経由するか否かはWebアプリケーション開発者にとっても把握が難しいため注意が必要です。

以下、代表的な事例としてPHPおよびPerlにおける影響点を記載しておきます。

○PHP

PHPではCGIモードで起動させた場合にbashの脆弱性を利用した攻撃が非常に容易に行えることを確認しています。
execやshell_exec、sysytem、proc_open といった明示的に外部コマンドを起動する関数の呼び出しだけでなく、メール送信のために広く利用されている mail 関数や mb_send_mail 関数も内部的にシェルを起動しているため、今回のbashの脆弱性の影響を受けます。これらを利用しているPHPスクリプトの動作環境では早急に対応が必要となります。

○Perl
system、exec、``、open など外部コマンドを利用している場合に影響を受ける可能性があります。特に、open( FH, "| nkf -j | sendmail" ) のように多段にパイプを介している場合にはシェルを起動してのコマンド実行となるため確実に影響を受けることになります。

また、外からみた場合には明示的にWebアプリケーションに見えない、静的なHTMLファイルであったとしても、内部でSSI(Server Side Include)を使用している場合には <!--#exec cgi=... --> などの機能により外部コマンドを呼び出している場合があり、これらもbashの脆弱性の影響を受けるため注意が必要です。


企業内、ファイアウォール内のサーバやBASIC認証等で保護されているサーバなど、攻撃者が直接的にアクセスできない場合であっても、そのサーバ上の攻撃可能なCGIなどのURLが攻撃者にとって既知である場合には、攻撃者はわなページ上のJavaScriptからXMLHttpRequestによって攻撃用のコードをを該当CGIへ送信することで任意コードの実行が可能となります。

以上、bashの脆弱性についての調査結果となります。繰り返しになりますが、現在提供されているパッチでは脆弱性への対応が不十分という話もあるため、パッチの適用に加え、万が一の場合に備えた対策を合わせてとっておくことが大切であり、弊社によるネットワークの監視カメラ「PacketBlackHole」のような製品が重要となります。
また、弊社でもサポートするSaaS型のWeb Application Firewallである「Scutum」ではすでに本攻撃に対するシグネイチャの対応を終えており、導入することにより本脆弱性を利用した攻撃からWebアプリケーションを守ることができます。



日本から世界に向けてのセキュリティカンファレンスCODE BLUE始動!

すでに報道をご覧になった方も多いかと思いますが、来年2月に日本から世界に向けて情報を発信するセキュリティカンファレンス「CODE BLUE」を開催することになりました。

CODE BLUEでは、最新のセキュリティ情報を共有し、国際会議での発表の場、世界屈指のセキュリティ専門家同士の情報交換、交流の場を提供することを目的とし、そのために世界屈指のセキュリティ専門家を海外から招聘し、最新の研究を共有するとともに、 国内の優秀な研究成果を国際社会に発信する事を目指しています。

今回、私もCODE BLUEへ応募された論文の査読を行うレビューボードのメンバーの末席に名を連ねることとなりました。他のメンバーはFFRIの鵜飼さんトレンドマイクロの新井さんサイボウズ・ラボの竹迫さんというまさに日本を代表して世界で活躍されている豪華メンバーです。

現在、国内では毎週末のように多数の勉強会が開かれているのは周知のとおりですが、そういった勉強会に実際に参加すると、世界でもトップクラスではないかという高い技術レベルに圧倒されることも多々あります。そういった方々に勉強会という枠を超えて世界レベルのカンファレンスで発表しないのかと尋ねると、やはり英語の壁をはじめいきなり海外へ飛び込むことへの障壁が大きいという答えが返ってきます(私自身もまったく同じですが…)。
今回CODE BLUEを開催することで、国内で日本語での応募、日本語での発表も可能であり、なおかつ世界からも注目される場を提供できることで、そういった方々を少しでもサポートでき、研究の本質に専念した発表が行えるのではないかと思っています。

私自身は2008年に国内で最後の開催となったBlack Hat Japanでスピーカーとして発表する機会を得ることができましたが、その発表を通じ世界中の研究者から問い合わせや情報交換の連絡が来るなど、世界のコミュニティとつながるきっかけをもらうことができました。CODE BLUEが同じように国内の優秀な技術者を世界へ飛びたたせるための舞台となればいいと思っています。

普段、セキュリティ技術に興味を持ち、いつもと違う場所で発表してみたいとお考えの方は、ぜひ応募をご検討頂ければと思います。よろしくお願いいたします。

先日開催されたプレス向け発表会の様子
先日開催されたプレス向け発表会の様子です。レビューア一同、CODE BLUEの開催を心から楽しみにしています。

たまにはハードウェア工作を楽しもう!

 こんにちは。ネットエージェント株式会社、研究開発部の長谷川です。今日は少し低レイヤの話ということで簡単なハードウェア工作を楽しもうと思います。

-----

■ ディスプレイを回転させたい!
 デュアルディスプレイの便利さはみなさんご存じのとおりだと思いますが、PDFやWordなどでA4サイズの文書を表示させているときなどに「ディスプレイを縦向きに表示させたい!」と思うことはありませんか? 私は普段からそう感じており、一時期、サブで使用しているディスプレイを縦向きに使用(表示)して使っていたのですが、日常的な作業では、やはり縦よりも横のほうが向いていることもあり、なかなか思ったほど気持ちよく作業できる環境ではありませんでした。
 というわけで、もう少し気軽に縦横を変えられる仕組みを実現しようと思い、ディスプレイ回転ツールを自作しました。

■ 材料
 今回使用した材料は以下になります。
  1. 液晶ディスプレイ用アーム(ARM-41C)
  2. スイッチ(5Aマイクロスイッチ)
  3. USB-シリアル変換ケーブル(USB-シリアル変換ケーブルUC-SGT)
  4. シリアルケーブル
  5. みんな大好きフリスクケース
 まず必要なのは液晶ディスプレイ用のアームです。一般的な液晶ディスプレイ用アームは、視野に対する角度などは細かく調整できますが、ディスプレイそのものの縦横を回転できるものは少ないです。それでも、丹念に探すと液晶の縦横回転機構を備えたものもそれなりの価格で見つかります。今回調達したものは、ライブクリエータ社のARM-41Cというもので、ヨドバシカメラで7000円を切る価格で手に入りました。
 次にスイッチですが、これはディスプレイの縦横を検出するために使用します。どのようなものでも構いませんが、今回はおもちゃ売り場で売っていたタミヤの5Aマイクロスイッチを使用しました。
 また、スイッチのON/OFFをPCに取り込むために、シリアル通信(いわゆるRS-232C)を利用することにし、今時のPCだとCOMポートがついていないため、USB経由でCOMポートを利用可能にするために、エレコムのUSB-シリアル変換ケーブルUC-SGTを使いました。
 あとは、クロスでもストレートでも構いませんので、スイッチに接続するために使用するシリアルケーブル。そして、スイッチを固定する台座として、みんな大好きフリスクケース。それ以外にもネジや両面テープなど適宜用意しておくと便利です。

■ ハードウェア工作
 fig1まずは、フリスクケース2個を振り子になるようネジで固定し、回転したときにスイッチが押されるようにスイッチも固定します。振り子側は、きちんとスイッチを押さえられるように中にコインを重りとして入れています(左図)。
 fig2シリアルケーブルのDTR、DSRをスイッチにハンダ付けします。また、ケーブルの自重でスイッチやハンダ付け部分が痛まないようにケースにケーブルを固定しておきます(右図)。
 fig3スイッチ部分ができあがれば、液晶ディスプレイ背面に両面テープでスイッチ機能付きフリスクケースを取り付けます。しっかりとスイッチが押されるように少し斜めに取り付けるのがコツです。縦、横とディスプレイの向きを変えたときにきちんとスイッチがON/OFFされるか確認します(左図-横、右図-縦)。
 fig4これで、ハードウェアの準備は完了です。あまりお金をかけない簡単な工作で、ディスプレイの向きに応じてシリアルポートのDTR-DSRがON/OFFされる装置が出来上がりました。

■ ソフトウェアの準備
 ハードウェアを作成したので、次はソフトウェアを組みます。
 ディスプレイの向きはシリアルポートのDSR信号を監視することで把握でき、監視するコードは、概ね以下のようになります(監視コードはサービスとして動作させています)。

HANDLE hComm;
OVERLAPPED ov;
DWORD dwCommState;

/* 略 */

EscapeCommFunction( hComm, SETDTR ); // DTR信号をON
SetCommMask( hComm, EV_DSR ); // DSR信号の変化を監視
ResetEvent( ov.hEvent ); // 非同期I/Oのためイベントをリセット

WaitCommEvent( hComm, &dwCommState, &ov ); // DSRの監視スタート
WaitForSingleObject( ov.hEvent, 30000 ); // イベント発生まで待機

 ディスプレイ表示の向きを変えるには、以下のようなコードで実現できます(エラー処理等は省略)。

int iDevNum = 1; // Display No.2
DISPLAY_DEVICE d;
DEVMODE dm;
int w;

ZeroMemory( &d, sizeof( d ) );
d.cb = sizeof( d );

EnumDisplayDevices( NULL, iDevNum, &d, 0 ) );
EnumDisplaySettings( d.DeviceName, ENUM_CURRENT_SETTINGS, &dm ) );

w = dm.dmPelsHeight;
dm.dmPelsHeight = dm.dmPelsWidth;
dm.dmPelsWidth = w;
dm.dmDisplayOrientation = DMDO_90; // 90度回転

ChangeDisplaySettingsEx( d.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL );

 全ソースコードはGitHub上に置いてあります。興味がある方は参照してください。
 サービスとしてシリアルポートを監視していると、ユーザのディスプレイ(デスクトップ)とは直接対話できないため、シリアルポートからの信号を受け取った時点でログオンしているユーザのトークンを用いてCreateProcessAsUserを使ってディスプレイ表示の向きを変えるためのプログラムを起動しています。

■ さいごに
fig5 このように、ディスプレイの向きを検出するスイッチと、それに応じて表示の向きを変えるプログラムを作成することによって、ディスプレイの向きを物理的に変えることで表示も連動して変わり、非常に快適になりました(左図:縦表示)。
 ソフトウェアエンジニアにとって、ハードウェア工作は若干敷居が高そうに思えるかもしれませんが、ソフトウェアと同じくらい面白く、また出来ることの幅、可能性も広がると思います。興味があればぜひとも挑戦してみてください。
 それにしてもフリスクケースはちょっとした工作にはとても便利ですね。Enjoy!

第1回 Win32 API 探検隊

 こんにちは。ネットエージェント株式会社、研究開発部の長谷川です。
 今回は、ちょっと軽めのネタということで、MSDN Library を眺めていて見つけた、少し変わった Windows API 関数を紹介したいと思います。

■ 使い道がありそうで見つからない PathIsExe
 Shell32.dll に含まれる PathIsExe 関数は、引数で指定したファイルが実行可能なファイルかどうかを、ファイル名の拡張子を見て判断します。例えば、"*.exe" や "*.cmd" といった拡張子であれば TRUE が返ります。
 Shell32 に含まれるということで、Explorer のようなシェルやシェル拡張などを書いている場合には(もしかすると)利用するかも知れませんが、一般のアプリケーションを開発する場合にはあまりお世話になる機会はなさそうです。
 同じ Shell32.dll には、PathIsSlow という面白い関数もあります。これは、指定したパスが遅延の大きなネットワークドライブなどであった場合に TRUE を返すようです。
 また、Shlwapi.dll にはこれらとよく似た名前で、PathIsURL という関数もあります。引数で指定された文字列がURLの書式に合致すれば TRUE を返すようですが、"http:" や "ftp:" だけでなく、"+-:" や "..:" などでも TRUE が返ってくるというおもしろ仕様なので、大抵の場合は自分で似たような関数を用意しなければなりません。

■ ちょっと便利な StrFormatByteSize
 Shlwapi.dll に含まれる StrFormatByteSize 関数一族は、数値を KB や MB といった単位付きのサイズ文字列に変換する関数です。
 例えば、23506 という数値を StrFormatByteSize64 に渡すと、"22.9KB" という、人間に読みやすい形に単位を変換して書式化した文字列を得られます。ファイルやメモリのサイズを表示する場合に、自分で書いてもたいしたコード量にはなりませんが、覚えておくとちょっとだけ便利です。
 さて、MSDN Library には、以下の5種類の関数の説明が掲載されています。
  1. StrFormatByteSize64
  2. StrFormatByteSizeA
  3. StrFormatByteSizeEx
  4. StrFormatByteSizeW
  5. StrFormatByteKBSize
 ぱっと見て気がつくのは、ANSI バージョンである StrFormatByteSizeA と Unicodeバージョンである StrFormatByteSizeW がそれぞれ別々に定義されている点です。実は、StrFormatByteSizeA と StrFormatByteSizeW は、単純に ANSI 版と Unicode 版という関係ではなく、ANSI 版が DWORD で 32 ビットまでのサイズにしか対応していないのに対して、Unicode 版は LONGLONG で 64 ビットのサイズに対応しています。また、StrFormatByteSize64 という関数は、ANSI 版である StrFormatByteSize64A しか定義されておらず、Unicode 環境では StrFormatByteSizeW が呼び出されます。
 使いそうであまり使わず、それでいて自分で作ってもたいしたコードでもないような関数が用意されていて、にも関わらずチグハグ感が満載というあたり、いかにも Windows らしいですね(編注:そんなWindowsが大好きなんです!)。

■ 末尾の Ex が 2 段重ねの関数
 Windows API で、あとから機能が拡張されたために名前の末尾に Ex のつく関数はたくさんありますが、EnumCalendarInfoExExEnumDateFormatsExExLogOnUserExExW は、末尾の Ex が 2 個重ねられた名前となっています。あと 3 年くらいしたら、ExExEx などになるのでしょうか。
 ちなみに、Win32 API で現存するもっとも長い関数名は、おそらく ConvertSecurityDescriptorToStringSecurityDescriptor あるいは ConvertStringSecurityDescriptorToSecurityDescriptor の 51 文字だそうです。IDE やエディタの入力支援がなければ、何度も打つのはうんざりしてしまいそうです。

■ APIとしては高機能すぎる SendARP
 Iphlpapi.dll に含まれる SendARP 関数は、その名前の通りコマンドラインの arp コマンドのように、ARP リクエストを送信します。なかなかアプリケーションから ARP を送ることは少ないと思いますし、ARP 自体が小さいとはいえ単一のプログラムとして成り立つくらいのものであり、それを API関数 として用意しているというのはちょっとビックリです。

■ 指定したアドレスのメモリの読み書き権限を調べる IsBadReadPtr / IsBadWritePtr
 Kernel32.dllに含まれる IsBadReadPtr 関数や IsBadWritePtr 関数は、引数として指定されたアドレスのメモリが読み書きできるかを調べる関数です(Vista以降ではサポートされていません)。サードパーティ DLL において渡されたパラメータが適切なものかどうかを判断するといった利用が想定されていたようですが、普通に考えると SEH を利用してコード全体を保護するほうが効率が良さそうです。

■ さいごに
 最後にちょっとしたTIPSを。MSDN Libraryは、表示の設定を "Classic"、"Lightweight"、"ScriptFree" から選択できますが、URLにおいて ( ) 内に "classic"、"lightweight"、"loband" などを指定することでも表示を切り替えられます。例えば http://msdn.microsoft.com/en-us/library/aa363858(VS.85,classic).aspx にアクセスすると classic 表示に、http://msdn.microsoft.com/en-us/library/aa363858(VS.85,loband).aspx にアクセスすると ScriptFree の表示に切り替わります。覚えておくとちょっと便利ですね。

ここまでできる! node.js に見る記号プログラミング


 こんにちは。ネットエージェント株式会社、研究開発部の長谷川です。先日、弊社の愛甲、サイバー大学の園田道夫氏とともに「非公式セキュリティキャンプ・キャラバン」と称して北海道情報セキュリティ勉強会(セキュポロ)に講師として参加してきました。例年であれば、セキュリティ&プログラミングキャンプの事業の一環として公式なキャラバンが開催されるのですが、今年は様々な事情で公式なキャラバンの開催が難しく講師としても心苦しく思っていたところ、ちょうどセキュポロのみなさんから勉強会の打診を頂きましたので、機会に乗じて非公式ながら「セキュリティキャンプ・キャラバン」という形を取らせて頂いたのでした。

-----

 さて、今日のテーマは流行りの node.js です。node.js は高効率な Web アプリケーションを、書き慣れた JavaScript で実現するための、サーバサイドで動く JavaScript 実装です。「最近、node.js も話題なので少しは触っておかないとな…」などと考えていたところに、愛甲から突然電話がかかってきました。
 電話の内容は「今、node.js で []()+! の6種類の記号だけの JavaScript を書こうとしてるんだけど、うまく動かないんだよね」というものでした。愛甲といえば、普段から「0と1しか興味ない」と公言しているほどのバイナリアンであり、そんな彼が0も1も使わない JavaScript を書いているということに少し衝撃を受けた私は、全く node.js を触ったことがないにも関わらず「いや、多分なんとかなると思うので、やってみます」と返事をしてしまい、node.js の世界に飛び込んだのでした。
 とりあえず、記号だけで JavaScript を動かす基本形として、まずは以下のようなコードを考えます。

Function( Function( "return\"console.log(1)\"" )() )()

 これは、無名関数内で console.log を使って「1」というメッセージを表示するコードですが、Number.constructor が Function であることを利用すると、以下のように書き変えられます。

(0).constructor.constructor( 
(0).constructor.constructor(
"return\"console.log(1)\""
)()
)()

 さらに、メソッドの呼び出しを連想配列形式に置き換えます。

(0)["constructor"]["constructor"](
(0)["constructor"]["constructor"](
"return'console.log(1)'"
)()
)()

 数字の 0 は、+[] で生成できます。また、「constructor」「return」という文字列は以下のように各文字を生成して + で連結します。

"c" : ([].filter + [])[3]         // "function filter() { 
// [native code] }"[3]
"o" : (true + [].filter + [])[10] // "truefunction filter() {
// [native code] }"[10]
"n" : (undefined+[])[1] // "undefined"[1]
"s" : (false + [])[3] // "false"[3]
"t" : (true + [])[0] // "true"[0]
"r" : (true + [])[1] // "true"[1]
"u" : (undefined + [])[0] // "undefined"[0]
"c" : ([].filter + [])[3] // "function filter() {
// [native code] }"[3]
"t" : (true + [])[0] // "true"[0]
"o" : (true + [].filter + [])[10] // "truefunction filter() {
// [native code] }"[10]
"r" : (true + [])[1] // "true"[1]

"r" : (true + [])[1]              // "true"[1]
"e" : (true + [])[3] // "true"[3]
"t" : (true + [])[0] // "true"[0]
"u" : (undefined + [])[0] // "undefined"[0]
"r" : (true + [])[1] // "true"[1]
"n" : (undefined+[])[1] // "undefined"[1]

 「filter」という文字列やtrue、false、undefinedといった値、数値なども、同様な方法で生成します。

"f" : (false + [])[0]             // "false"[0]
"i" : (false + undefined)[10] // "falseundefined"[10]
"l" : (false + [])[2] // "false"[2]
"t" : (true + [])[0] // "true"[0]
"e" : (true + [])[3] // "true"[3]
"r" : (true + [])[1] // "true"[1]

true      : !![]
false : ![]
undefined : [][[]]
0 : +[]
1 : +!+[]
2 : !+[]+!+[]
3 : !+[]+!+[]+!+[]
10 : +!+[]+[+[]]

 「constructor」「return」の各文字列や数値が []()!+ の記号だけで生成できましたので、あとは「'console.log(1)'」という、実行するコード部分を記号で生成すれば任意のコードを記号だけで書けそうです。
 JavaScript では、文字列定数は "\101\102\103" のように ASCII コードを \ に続けて8進数で記述することで、US-ASCII の範囲内の文字であれば表現できます。これを利用すると、「'console.log(1)'」という部分は「'\143\157\156\163\157\154\145\56\154\157\147\050\061\051'」になります。任意の数字は []()!+ の6種の記号から自由に生成できますので、あとは「\」と「'」の2文字を生成すればいいことになりますが、さてどうしよう…、というところで実は行き詰ったわけですが、node.js をいろいろ触っていると、console.dir が利用できることに気が付きました。console.dir( console.dir + []) を実行してみると、次のような文字列が返ってきます。

function (object) {
var util = require('util');
process.stdout.write(util.inspect(object) + '\n');
}

 うまい具合に、(consile.dir+[])[97] と (console.dir+[])[41] に「\」と「'」が存在していました。そして、「console」「dir」は次のように記号だけで書けます。

"c" : ([].filter + [])[3]         // "function filter() { 
// [native code] }"[3]
"o" : (true + [].filter + [])[10] // "truefunction filter() {
// [native code] }"[10]
"n" : (undefined+[])[1] // "undefined"[1]
"s" : (false + [])[3] // "false"[3]
"o" : (true + [].filter + [])[10] // "truefunction filter() {
// [native code] }"[10]
"l" : (false + [])[2] // "false"[2]
"e" : (true + [])[3] // "true"[3]

"d" : (undefined+[])[2]           // "undefined"[2]
"i" : (false + undefined)[10] // "falseundefined"[10]
"r" : (true + [])[1] // "true"[1]

 これで、任意のコードを []()!+ の6種類だけで書けることがわかりましたので、実際に「console.log(1)」を記号だけで書いてみると、こんなふうになります。たった1行が4万文字を超えるスクリプトになってしまいました(笑)。
 この方法で、node.js らしくhttpサーバも記号だけに変換してみようと思ったのですが、require や module などが Function() 内ではうまく動かず結局断念しました。require のみグローバルなコンテキストから引数で渡してやることで、ほとんどの部分を記号だけで書いた JavaScript による http サーバはこちらになります(ブラウザによっては表示に時間がかかりますのでご注意ください)。require なども記号だけで実現する、何かよい方法があればこっそり教えてください。
 ということで、記号だらけですっかり混乱してしまった頭をすっきりさせるために、今日も飲みに行くのでした。
記事検索
月別アーカイブ
QRコード
QRコード