入力の検証や表現の問題は、メタキャラクター、代替エンコーディング、数値表現などによって引き起こされます。セキュリティの問題は、入力を信頼することに起因します。この問題に含まれるのは、「Buffer Overflow」、「Cross-Site Scripting」攻撃、「SQL Injection」などです。
validate()
メソッドを定義しますが、super.validate()
をコールしません。validate()
メソッドを使用して、関連する検証フォームで指定される制約に対して form プロパティのコンテンツをチェックします。つまり、以下のクラスは検証フレームワークの一部である validate()
メソッドを持つことを意味します。
ValidatorForm
ValidatorActionForm
DynaValidatorForm
DynaValidatorActionForm
validate()
メソッドを上書きしてカスタム検証ロジックを実装する場合、validate()
実装の super.validate()
をコールする必要があります。これを行わないと、検証フレームワークはフォームのコンテンツを検証フォームに対してチェックできません。つまり、検証フレームワークは特定のフォームでは無効となります。
ValidatorForm
ValidatorActionForm
DynaValidatorActionForm
DynaValidaorForm
validate()
メソッドを実装することでアプリケーションと連動するため、これらのクラスのいずれかを拡張する必要があります。
ActionForm
DynaActionForm
ActionForm
を使用しています。このような場合、一部のアクションマッピングの下で未使用のままとなるフィールドもあります。未使用のフィールドも検証することが重要です。できれば、未使用フィールドは空か未定義にしかならないように制限してください。未使用フィールドが検証されなかった場合、アクションでの共有ビジネスロジックにより、攻撃者はフォームの他の用途のために実行される検証チェックを回避できる可能性があります。form-bean
エントリを使用して HTML フォームをアクションにマップします。Struts 設定ファイルの <action-mappings>
要素に、<form-bean>
タグを介して定義された関連するアクション フォームに対応するエントリがない場合、アプリケーション ロジックが最新でない可能性があります。bean2
のマッピングを含みません。
<form-beans>
<form-bean name="bean1" type="coreservlets.UserFormBean1" />
<form-bean name="bean2" type="coreservlets.UserFormBean2" />
</form-beans>
<action-mappings>
<action path="/actions/register1" type="coreservlets.RegisterAction1" name="bean1" scope="request" />
</action-mappings>
validate()
メソッドを無効にします。
<action path="/download"
type="com.website.d2.action.DownloadAction"
name="downloadForm"
scope="request"
input=".download"
validate="false">
</action>
ActionForm
クラスに変更を加えるときに、検証ロジックの更新を忘れがちです。検証ロジックが適切に保守されていないことを示す兆候の 1 つは、アクション フォームと検証フォームの間の不整合です。
public class DateRangeForm extends ValidatorForm {
String startDate, endDate;
public void setStartDate(String startDate) {
this.startDate = startDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
}
startDate
および endDate
を持つアクション フォームを示しています。
<form name="DateRangeForm">
<field property="startDate" depends="date">
<arg0 key="start.date"/>
</field>
<field property="endDate" depends="date">
<arg0 key="end.date"/>
</field>
<field property="scale" depends="integer">
<arg0 key="range.scale"/>
</field>
</form>
scale
。3 番目のフィールドの存在は、検証を考慮せずに DateRangeForm
を変更したことを表しています。
app.get('/', function(req, res){
let param = req.params['template']
let val = req.params['templateVal']
let template = Handlebars.compile('{{user}}: {{' + param + '}}');
let templateInput = {}
templateInput['user'] = 'John'
templateInput[param] = val
let result = template(templateInput)
//...
});
Example 1
は、Handlebars
をテンプレート エンジンとして使用し、コンパイルされたテンプレートにユーザー制御データが連結されます。これにより、攻撃者は任意の JavaScript を実行できます。Echo
という名前のクラスを定義します。このクラスは、コンソールで C 言語を使って入力されたコマンドをユーザーにそのまま伝える、ひとつのネイティブメソッドを宣言します。
class Echo {
public native void runEcho();
static {
System.loadLibrary("echo");
}
public static void main(String[] args) {
new Echo().runEcho();
}
}
Echo
クラスで実装されるネイティブメソッドを定義します。
#include <jni.h>
#include "Echo.h" //javah でコンパイルされたExample 1
の java クラス
#include <stdio.h>
JNIEXPORT void JNICALL
Java_Echo_runEcho(JNIEnv *env, jobject obj)
{
char buf[64];
gets(buf);
printf(buf);
}
gets()
を利用するため、Buffer Overflow に対して脆弱です。 Example 1
の脆弱性は、ネイティブメソッド実装のソースコード監査で簡単に検出することができます。これは C ソースコードを利用できるかどうかや、プロジェクトのビルド方法によっては実用的でなかったり可能でないことがありますが、多くの場合は十分です。しかし、Java とネイティブメソッドでオブジェクトを共有できる能力は、潜在的なリスクを油断できないほどに拡げます。Java の誤ったデータ取り扱いがネイティブコードの予測不能な脆弱性につながったり、ネイティブコードでの安全でない使用により Java のデータ構造が破壊されることがあります。Redirect
という名前のクラスを定義します。このクラスは 1 つのネイティブ JavaScript メソッドを宣言し、JavaScript を使用してドキュメントの場所を変更します。
import com.google.gwt.user.client.ui.UIObject;
class MyDiv {
...
public static void changeName(final UIObject object, final String name) {
changeName(object.getElement(), url);
}
public static native void changeName(final Element e, final String name) /*-{
$wnd.jQuery(e).html(name);
}-*/;
...
}
Echo
という名前のクラスを定義します。このクラスは、コンソールで C 言語を使って入力されたコマンドをユーザーにそのまま伝える、ひとつのネイティブメソッドを宣言します。
class Echo
{
[DllImport("mylib.dll")]
internal static extern void RunEcho();
static void main(String[] args)
{
RunEcho();
}
}
Echo
クラスで実装されるネイティブメソッドを定義します。
#include <stdio.h>
void __stdcall RunEcho()
{
char* buf = (char*) malloc(64 * sizeof(char));
gets(buf);
printf(buf);
}
gets()
を利用しているため、Buffer Overflow に対して脆弱です。同様に、buf
も割り当てられたあと解放されていないので、メモリ リークを起こします。Example 1
の脆弱性は、ネイティブメソッド実装のソースコード監査で簡単に検出することができます。これはソースコードを利用できるかどうかや、プロジェクトのビルド方法によっては実用的でなかったり可能でないことがありますが、多くの場合は十分です。しかし、管理対象環境とネイティブ環境でオブジェクトを共有できる能力によって、潜在的なリスクは油断できない環境に変化します。つまり、管理対象コードの不適切なデータ取り扱いがネイティブコードの予期しない脆弱性につながったり、ネイティブコードでの安全ではない操作によって管理対象コードのデータ構造が破壊されることがあります。
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var ctl:String = String(params["ctl"]);
var ao:Worker;
if (ctl == "Add) {
ao = new AddCommand();
} else if (ctl == "Modify") {
ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
ao.doAction(params);
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var ctl:String = String(params["ctl"]);
var ao:Worker;
var cmdClass:Class = getDefinitionByName(ctl + "Command") as Class;
ao = new cmdClass();
ao.doAction(params);
if/else
ブロックは完全に削除され、コマンドディスパッチャを修正しなくとも新しいコマンドタイプを追加することができるからです。Worker
インターフェイスを実装する任意のオブジェクトのインスタンスを作成することができます。コマンドディスパッチャが依然として Access Control の原因である場合、プログラマは Worker
インターフェイスを実装する新規クラスを作成するたびに、ディスパッチャの Access Control コードを忘れずに修正する必要があります。Access Control コードの修正を怠った場合、一部の Worker
クラスに対して一切の Access Control が適用されなくなります。Worker
オブジェクトに Access Control のチェックを実行させることです。リファクタリングされたコードの例を次に示します。
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var ctl:String = String(params["ctl"]);
var ao:Worker;
var cmdClass:Class = getDefinitionByName(ctl + "Command") as Class;
ao = new cmdClass();
ao.checkAccessControl(params);
ao.doAction(params);
Continuation
オブジェクトのコールバック メソッドの決定を許可すると、攻撃者がアプリケーションを介して予期せぬ制御フロー パスを作成できてしまい、セキュリティ チェックをすり抜けてしまう可能性があります。continuationMethod
プロパティを設定します。これは、応答を受信したときに呼び出されるメソッドの名前を決定します。
public Object startRequest() {
Continuation con = new Continuation(40);
Map<String,String> params = ApexPages.currentPage().getParameters();
if (params.containsKey('contMethod')) {
con.continuationMethod = params.get('contMethod');
} else {
con.continuationMethod = 'processResponse';
}
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setEndpoint(LONG_RUNNING_SERVICE_URL);
this.requestLabel = con.addHttpRequest(req);
return con;
}
continuationMethod
プロパティをランタイム リクエスト パラメーターで設定できるようになり、攻撃者が、名前と一致する関数を呼び出すことが可能になります。
...
Dim ctl As String
Dim ao As New Worker()
ctl = Request.Form("ctl")
If (String.Compare(ctl,"Add") = 0) Then
ao.DoAddCommand(Request)
Else If (String.Compare(ctl,"Modify") = 0) Then
ao.DoModifyCommand(Request)
Else
App.EventLog("No Action Found", 4)
End If
...
...
Dim ctl As String
Dim ao As New Worker()
ctl = Request.Form("ctl")
CallByName(ao, ctl, vbMethod, Request)
...
if/else
ブロックは完全に削除され、コマンドディスパッチャを修正しなくとも新しいコマンドタイプを追加することができるからです。Worker
オブジェクトによって実装された任意のメソッドを呼び出すことができます。コマンドディスパッチャが Access Control の原因である場合、プログラマは Worker
クラス内に新規メソッドを作成するたびに、ディスパッチャの Access Control ロジックを忘れずに修正する必要があります。この Access Control ロジックが古くなると、いくつかの Worker
メソッドにはいずれの Access Control も関連付けられなくなります。Worker
オブジェクトに Access Control のチェックを実行させることです。リファクタリングされたコードの例を次に示します。
...
Dim ctl As String
Dim ao As New Worker()
ctl = Request.Form("ctl")
If (ao.checkAccessControl(ctl,Request) = True) Then
CallByName(ao, "Do" & ctl & "Command", vbMethod, Request)
End If
...
clazz
で定義された任意の関数をコールできるようになります。
char* ctl = getenv("ctl");
...
jmethodID mid = GetMethodID(clazz, ctl, sig);
status = CallIntMethod(env, clazz, mid, JAVA_ARGS);
...
例 2: 前の例と同様に、アプリケーションは
...
func beforeExampleCallback(scope *Scope){
input := os.Args[1]
if input{
scope.CallMethod(input)
}
}
...
reflect
パッケージを使用して、コマンドライン引数から、呼び出される関数の名前を取得します。
...
input := os.Args[1]
var worker WokerType
reflect.ValueOf(&worker).MethodByName(input).Call([]reflect.Value{})
...
String ctl = request.getParameter("ctl");
Worker ao = null;
if (ctl.equals("Add")) {
ao = new AddCommand();
} else if (ctl.equals("Modify")) {
ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
ao.doAction(request);
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.doAction(request);
if/else
ブロックは完全に削除され、コマンドディスパッチャを修正しなくとも新しいコマンドタイプを追加することができるからです。Worker
インターフェイスを実装する任意のオブジェクトのインスタンスを作成することができます。コマンドディスパッチャが依然として Access Control の原因である場合、プログラマは Worker
インターフェイスを実装する新規クラスを作成するたびに、ディスパッチャの Access Control コードを忘れずに修正する必要があります。Access Control コードの修正を怠った場合、一部の Worker
クラスに対して一切の Access Control が適用されなくなります。Worker
オブジェクトに Access Control のチェックを実行させることです。リファクタリングされたコードの例を次に示します。
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.checkAccessControl(request);
ao.doAction(request);
Worker
インターフェイスを実装するオブジェクトにすら制約を受けず、システム内の任意のオブジェクトのデフォルト コンストラクタを呼び出すことができます。オブジェクトが Worker
インターフェイスを実装しない場合、ao
への割り当て前に ClassCastException
が発生しますが、コンストラクタが攻撃者に有利に働く操作を実行すると、すでに被害を被ったことになります。このシナリオは、簡単なアプリケーションの場合被害は比較的少なくて済みますが、複雑度が飛躍的に増す大規模アプリケーションの場合では攻撃者は攻撃に利用できるコンストラクタを見つけられると考えるのが妥当です。performSelector
メソッドの引数を制御できるため、セキュリティ チェックを回避して、アプリケーションに想定外の制御フロー パスを作成できる可能性があります。UIApplicationDelegate
クラスで定義されたメソッド シグネチャに一致する任意の関数をコールできるようになります。
...
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
NSString *query = [url query];
NSString *pathExt = [url pathExtension];
[self performSelector:NSSelectorFromString(pathExt) withObject:query];
...
$ctl = $_GET["ctl"];
$ao = null;
if (ctl->equals("Add")) {
$ao = new AddCommand();
} else if ($ctl.equals("Modify")) {
$ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
$ao->doAction(request);
$ctl = $_GET["ctl"];
$args = $_GET["args"];
$cmdClass = new ReflectionClass(ctl . "Command");
$ao = $cmdClass->newInstance($args);
$ao->doAction(request);
if/else
ブロックは完全に削除され、コマンドディスパッチャを修正しなくとも新しいコマンドタイプを追加することができるからです。Worker
インターフェイスを実装する任意のオブジェクトのインスタンスを作成することができます。コマンドディスパッチャが依然として Access Control の原因である場合、プログラマは Worker
インターフェイスを実装する新規クラスを作成するたびに、ディスパッチャの Access Control コードを忘れずに修正する必要があります。Access Control コードの修正を怠った場合、一部の Worker
クラスに対して一切の Access Control が適用されなくなります。Worker
オブジェクトに Access Control のチェックを実行させることです。リファクタリングされたコードの例を次に示します。
$ctl = $_GET["ctl"];
$args = $_GET["args"];
$cmdClass = new ReflectionClass(ctl . "Command");
$ao = $cmdClass->newInstance($args);
$ao->checkAccessControl(request);
ao->doAction(request);
Worker
インターフェイスを実装するオブジェクトにすら制約を受けず、システム内の任意のオブジェクトのデフォルト コンストラクタを呼び出すことができます。オブジェクトが Worker
インターフェイスを実装しない場合、$ao
への割り当て前に ClassCastException
が発生しますが、コンストラクタが攻撃者に有利に働く操作を実行すると、すでに被害を被ったことになります。このシナリオは、簡単なアプリケーションの場合被害は比較的少なくて済みますが、複雑度が飛躍的に増す大規模アプリケーションの場合では攻撃者は攻撃に利用できるコンストラクタを見つけられると考えるのが妥当です。
ctl = req['ctl']
if ctl=='add'
addCommand(req)
elsif ctl=='modify'
modifyCommand(req)
else
raise UnknownCommandError.new
end
ctl = req['ctl']
ctl << "Command"
send(ctl)
if/else
ブロックは完全に削除され、コマンドディスパッチャを修正しなくとも新しいコマンドタイプを追加することができるからです。define_method()
を使用して動的に作成するか、missing_method()
の上書きによってコールすることです。こうした状況とそこでアクセス制御コードがどう使用されるかを監査し、追跡するのは非常に困難です。また、他のどのライブラリ コードがロードされたかにも依存することを考えると、この作業をこの方法で適切に行うことはほぼ不可能です。
def exec(ctl: String) = Action { request =>
val cmdClass = Platform.getClassForName(ctl + "Command")
Worker ao = (Worker) cmdClass.newInstance()
ao.doAction(request)
...
}
if/else
ブロックは完全に削除され、コマンド ディスパッチャを修正しなくとも新しいコマンド タイプを追加することができるからです。Worker
インターフェイスを実装する任意のオブジェクトのインスタンスを作成することができます。コマンド ディスパッチャが依然として Access Control の原因である場合、プログラマは Worker
インターフェイスを実装する新規クラスを作成するたびに、ディスパッチャの Access Control コードを忘れずに修正する必要があります。Access Control コードの修正を怠った場合、一部の Worker
クラスに対して一切の Access Control が適用されなくなります。Worker
オブジェクトに Access Control のチェックを実行させることです。リファクタリングされたコードの例を次に示します。
def exec(ctl: String) = Action { request =>
val cmdClass = Platform.getClassForName(ctl + "Command")
Worker ao = (Worker) cmdClass.newInstance()
ao.checkAccessControl(request);
ao.doAction(request)
...
}
Worker
インターフェイスを実装するオブジェクトにすら制約を受けず、システム内の任意のオブジェクトのデフォルト コンストラクタを呼び出すことができます。オブジェクトが Worker
インターフェイスを実装しない場合、ao
への割り当て前に ClassCastException
が発生しますが、コンストラクタが攻撃者に有利に働く操作を実行すると、すでに被害を被ったことになります。このシナリオは、簡単なアプリケーションの場合被害は比較的少なくて済みますが、複雑度が飛躍的に増す大規模アプリケーションの場合では攻撃者は攻撃に利用できるコンストラクタを見つけられると考えるのが妥当です。performSelector
メソッドの引数を制御できるため、セキュリティ チェックを回避して、アプリケーションに想定外の制御フロー パスを作成できる可能性があります。UIApplicationDelegate
クラスで定義されたメソッド シグネチャに一致する任意の関数をコールできるようになります。
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
...
let query = url.query
let pathExt = url.pathExtension
let selector = NSSelectorFromString(pathExt!)
performSelector(selector, withObject:query)
...
}
...
Dim ctl As String
Dim ao As new Worker
ctl = Request.Form("ctl")
If String.Compare(ctl,"Add") = 0 Then
ao.DoAddCommand Request
Else If String.Compare(ctl,"Modify") = 0 Then
ao.DoModifyCommand Request
Else
App.EventLog "No Action Found", 4
End If
...
...
Dim ctl As String
Dim ao As Worker
ctl = Request.Form("ctl")
CallByName ao, ctl, vbMethod, Request
...
if/else
ブロックは完全に削除され、コマンドディスパッチャを修正しなくとも新しいコマンドタイプを追加することができるからです。Worker
オブジェクトによって実装された任意のメソッドを呼び出すことができます。コマンドディスパッチャが依然として Access Control の原因である場合、プログラマは Worker
クラス内に新規メソッドを作成するたびに、ディスパッチャの Access Control コードを忘れずに修正する必要があります。Access Control コードの修正を怠った場合、一部の Worker
メソッドに対して一切の Access Control が適用されなくなります。Worker
オブジェクトに Access Control のチェックを実行させることです。リファクタリングされたコードの例を次に示します。
...
Dim ctl As String
Dim ao As Worker
ctl = Request.Form("ctl")
If ao.checkAccessControl(ctl,Request) = True Then
CallByName ao, "Do" & ctl & "Command", vbMethod, Request
End If
...
HttpRequest
クラスにより、プログラムは QueryString
、Form
、Cookies
、または ServerVariables
コレクションの変数に配列アクセスの形でアクセスすることができます (Request["myParam"]
など)。同じ名前の変数が 2 個以上存在する場合、.NET フレームワークは次の順序でコレクションを検索して最初に検出した変数の値を返します。QueryString
、Form
、Cookies
、ServerVariables
。QueryString
は最初に検索されるため、QueryString
のパラメーターがフォーム、cookie、およびサーバーの変数の値より優先される可能性があります。同様に、フォームの値は Cookies
と ServerVariables
コレクションの変数より優先され、Cookies
コレクションの変数は ServerVariables
の変数より優先される場合があります。
...
String toAddress = Request["email"]; //Expects cookie value
Double balance = GetBalance(userID);
SendAccountBalance(toAddress, balance);
...
Example 1
のコードが http://www.example.com/GetBalance.aspx
にアクセス中に実行されると仮定してみましょう。攻撃者が認証済みユーザーに http://www.example.com/GetBalance.aspx?email=evil%40evil.com
をリクエストするリンクをクリックさせることができる場合、そのユーザーの口座残高が記載された電子メールは evil@evil.com
に送信されてしまいます。HttpRequest
クラスにより、プログラムは QueryString
、Form
、Cookies
、または ServerVariables
コレクションの変数に配列アクセスの形でアクセスすることができます (Request["myParam"]
など)。同じ名前の変数が 2 個以上存在する場合、.NET フレームワークは次の順序でコレクションを検索して最初に検出した変数の値を返します。QueryString
、Form
、Cookies
、ServerVariables
。QueryString
は最初に検索されるため、QueryString
のパラメーターがフォーム、cookie、およびサーバーの変数の値より優先される可能性があります。同様に、フォームの値は Cookies
と ServerVariables
コレクションの変数より優先され、Cookies
コレクションの変数は ServerVariables
の変数より優先される場合があります。www.example.com
からリクエストが送信されたことを確認するために、HTTP リファラー ヘッダーのサーバー変数をチェックしています。
...
if (Request["HTTP_REFERER"].StartsWith("http://www.example.com"))
ServeContent();
else
Response.Redirect("http://www.example.com/");
...
Example 1
のコードが http://www.example.com/ProtectedImages.aspx
にアクセス中に実行されると仮定してみましょう。攻撃者がこの URL に対して直接リクエストを送信すると、適切なリファラーヘッダーが設定されず、そのリクエストは失敗します。しかし、攻撃者が必要な値を持つ偽の HTTP_REFERER
パラメーター (http://www.example.com/ProtectedImages.aspx?HTTP_REFERER=http%3a%2f%2fwww.example.com
など) を送信した場合には、このルックアップによって ServerVariables
ではなく QueryString
の値が返され、チェックに合格することになります。
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
...
DATA(ixml) = cl_ixml=>create( ).
DATA(stream_factory) = ixml->create_stream_factory( ).
istream = stream_factory->create_istream_string(
`<?xml version="1.0" encoding="UTF-8"?> ` &&
`<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> ` &&
`<stockCheck>&xxe;</stockCheck>` ).
istream->set_dtd_restriction( level = 0 ).
DATA(document) = ixml->create_document( ).
parser = ixml->create_parser(
stream_factory = stream_factory
istream = istream
document = document ).
parser->set_validating( mode = `0` ).
DATA(rc) = parser->parse( ).
...
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/winnt/win.ini" >]><foo>&xxe;</foo>
- (void) parseSomeXML: (NSString *) rawXml {
BOOL success;
NSData *rawXmlConvToData = [rawXml dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *myParser = [[NSXMLParser alloc] initWithData:rawXmlConvToData];
[myParser setShouldResolveExternalEntities:YES];
[myParser setDelegate:self];
}
rawXml
を制御できると考えてみます。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
ファイルの内容が含まれます。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>
String xml = "...";
...
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.println(new String(ch, start, length));
}
};
saxParser.parse(new InputSource(new StringReader(xml)), handler);
} catch (Exception e) {
e.printStackTrace();
}
...
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>
- (void) parseSomeXML: (NSString *) rawXml {
BOOL success;
NSData *rawXmlConvToData = [rawXml dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *myParser = [[NSXMLParser alloc] initWithData:rawXmlConvToData];
[myParser setShouldResolveExternalEntities:YES];
[myParser setDelegate:self];
}
rawXml
を制御できると考えてみます。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
ファイルの内容が含まれます。
...
<?php
$goodXML = $_GET["key"];
$doc = simplexml_load_string($goodXml);
echo $doc->testing;
?>
...
Example 2
のコードに以下の XML が渡されると仮定してください。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
ファイルのコンテンツが埋め込まれます。攻撃者は、データを盗み出したり、ネットワーク リソースの存在に関する情報を取得するために、クライアントに返される XML 要素を利用することができます。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
/etc/passwd
のコンテンツを読み込み、それらをドキュメントに含めます。
def readFile() = Action { request =>
val xml = request.cookies.get("doc")
val doc = XMLLoader.loadString(xml)
...
}
func parseXML(xml: String) {
parser = NSXMLParser(data: rawXml.dataUsingEncoding(NSUTF8StringEncoding)!)
parser.delegate = self
parser.shouldResolveExternalEntities = true
parser.parse()
}
rawXml
コンテンツを攻撃者が制御できる場合を考えてみましょう。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
ファイルの内容が含まれます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。
...
<?php
$goodXML = $_GET["key"];
$doc = simplexml_load_string($goodXml);
echo $doc->testing;
?>
...
Example 2
のコードに以下の XML が渡されると仮定してください。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
ファイルのコンテンツが埋め込まれます。攻撃者は、データを盗み出したり、ネットワーク リソースの存在に関する情報を取得するために、クライアントに返される XML 要素を利用することができます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。shoes
を攻撃者が制御できる場合を考えてみましょう。
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
を shoes</item><price>1.00</price><item>shoes
に置き換えるとします。新しい XML は以下のようになります。
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
の値により最初の <price>
タグの値が上書きされます。これにより、攻撃者は $100 の靴を $1 で購入できます。a:t
タグを制御できると仮定します。
<a:t>YoY results: up 10%</a:t>