permissions := strconv.Atoi(os.Getenv("filePermissions"));
fMode := os.FileMode(permissions)
os.chmod(filePath, fMode);
...
String permissionMask = System.getProperty("defaultFileMask");
Path filePath = userFile.toPath();
...
Set<PosixFilePermission> perms = PosixFilePermissions.fromString(permissionMask);
Files.setPosixFilePermissions(filePath, perms);
...
$rName = $_GET['publicReport'];
chmod("/home/". authenticateUser . "/public_html/" . rName,"0755");
...
publicReport
に悪意のある値 (../../localuser/public_html/.htpasswd
など) を指定した場合、指定されたファイルは攻撃者から読み取り可能となります。
...
$mask = $CONFIG_TXT['perms'];
chmod($filename,$mask);
...
permissions = os.getenv("filePermissions");
os.chmod(filePath, permissions);
...
...
rName = req['publicReport']
File.chmod("/home/#{authenticatedUser}/public_html/#{rName}", "0755")
...
publicReport
に悪意のある値 (../../localuser/public_html/.htpasswd
など) を指定した場合、指定されたファイルは攻撃者から読み取り可能となります。
...
mask = config_params['perms']
File.chmod(filename, mask)
...
services-config.xml
ディスクリプタファイルは "Logging" XML 要素を指定して、ログの各要素を記述します。次のようになります。
<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Debug">
<properties>
<prefix>[BlazeDS]</prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
<filters>
<pattern>Endpoint.*</pattern>
<pattern>Service.*</pattern>
<pattern>Configuration</pattern>
</filters>
</target>
</logging>
target
タグでは、ログレベルを示す level
と呼ばれる属性をオプションで使用できます。デバッグ レベルが詳細すぎるレベルに設定されている場合、アプリケーションが機密データをログ ファイルに書き込む可能性があります。sprintf()
、FormatMessageW()
、または syslog()
などの関数に渡される場合。snprintf()
を使用してコマンド ライン引数をバッファにコピーしています。
int main(int argc, char **argv){
char buf[128];
...
snprintf(buf,128,argv[1]);
}
%x
など) を入力することでスタックから読み取ることができます(この例では、関数はフォーマットのための引数を取っていません)。%n
書式指定子を使用することで攻撃者はスタックに書き込み、snprintf()
にそこまでの出力バイト数を指定した引数に書き出させることができます (引数から値を読み出すのが本来の動作です)。この攻撃を高度にしたものは、タイミングをずらして 4 回書き込みを行うことで、スタック上のポインタ値を完全に支配下に置きます。
printf("%d %d %1$d %1$d\n", 5, 9);
5 9 5 5
Example 1
で挙げたような、タイミングをずらして 4 回書き込みする手間を大幅に軽減することができます。syslog()
関数は、ときおり次のように使用されます。
...
syslog(LOG_ERR, cmdBuf);
...
syslog()
の 2 番目のパラメーターは Format String なので、cmdBuf
に含まれる書式指定子は Example 1
に記載したのと同様に解釈されます。syslog()
の正しい使用例です。
...
syslog(LOG_ERR, "%s", cmdBuf);
...
sprintf()
、FormatMessageW()
、syslog()
、NSLog
、または NSString.stringWithFormat
などの関数に渡される場合。NSString.stringWithFormat:
で Format String としてコマンド ライン引数を使用しています。
int main(int argc, char **argv){
char buf[128];
...
[NSString stringWithFormat:argv[1], argv[2] ];
}
%x
など) を入力することでスタックから読み取ることができます(この例では、関数はフォーマットのための引数を取っていません)。
printf("%d %d %1$d %1$d\n", 5, 9);
5 9 5 5
Example 1
で挙げたような、タイミングをずらして 4 回書き込みする手間を大幅に軽減することができます。syslog()
関数は、ときおり次のように使用されます。
...
syslog(LOG_ERR, cmdBuf);
...
syslog()
の 2 番目のパラメーターは Format String なので、cmdBuf
に含まれる書式指定子は Example 1
に記載したのと同様に解釈されます。syslog()
の正しい使用例です。例 4: Apple コア クラスは、Format String の脆弱性を悪用するための方法を提供しています。
...
syslog(LOG_ERR, "%s", cmdBuf);
...
String.stringByAppendingFormat()
関数は、ときおり次のように使用されます。
...
NSString test = @"Sample Text.";
test = [test stringByAppendingFormat:[MyClass
formatInput:inputControl.text]];
...
stringByAppendingFormat()
の正しい使用例です。
...
NSString test = @"Sample Text.";
test = [test stringByAppendingFormat:@"%@", [MyClass
formatInput:inputControl.text]];
...
strncpy()
など境界が定められた関数の場合も、不正に使用されると脆弱性の原因になります。メモリの操作と、データのサイズや構成に関する誤った想定が同時に発生することが、大部分の Buffer Overflow の根本的な原因です。
void wrongNumberArgs(char *s, float f, int d) {
char buf[1024];
sprintf(buf, "Wrong number of %.512s");
}
strncpy()
など境界が定められた関数の場合も、不正に使用されると脆弱性の原因になります。メモリの操作と、データのサイズや構成に関する誤った想定が同時に発生することが、大部分の Buffer Overflow の根本的な原因です。%d
を使用して、浮動小数点数から f
を不正に変換しています。
void ArgTypeMismatch(float f, int d, char *s, wchar *ws) {
char buf[1024];
sprintf(buf, "Wrong type of %d", f);
...
}
script
タグについて考えてみましょう。
<script src="http://www.example.com/js/fancyWidget.js"></script>
www.example.com
以外の Web サイトでこのタグが表示される場合、このサイトは www.example.com
に依存し、正しい悪意のないコードが提供されます。攻撃者が www.example.com
を乗っ取っている場合、fancyWidget.js
の内容を改変して、サイトのセキュリティが侵害される場合があります。たとえば、fancyWidget.js
にユーザーの機密情報を盗むコードが追加される可能性があります。
...
String lang = Request.Form["lang"];
WebClient client = new WebClient();
client.BaseAddress = url;
NameValueCollection myQueryStringCollection = new NameValueCollection();
myQueryStringCollection.Add("q", lang);
client.QueryString = myQueryStringCollection;
Stream data = client.OpenRead(url);
...
en&poll_id=1
のような lang
を指定できる可能性を考慮しておらず、攻撃者が思いのままに poll_id
を変更できます。
...
String lang = request.getParameter("lang");
GetMethod get = new GetMethod("http://www.example.com");
get.setQueryString("lang=" + lang + "&poll_id=" + poll_id);
get.execute();
...
en&poll_id=1
のような lang
を指定できる可能性を考慮しておらず、攻撃者が思いのままに poll_id
を変更できます。
<%
...
$id = $_GET["id"];
header("Location: http://www.host.com/election.php?poll_id=" . $id);
...
%>
name=alice
を指定していますが、さらに name=alice&
を追加しています。これが最初に出現するサーバーで使用されると、alice
になりすましてそのアカウントに関する情報をさらに取得します。
String arg = request.getParameter("arg");
...
Intent intent = new Intent();
...
intent.setClassName(arg);
ctx.startActivity(intent);
...
Intent
が検出されています。暗黙的な内部インテントにより、システムが内部コンポーネントに対する中間者攻撃にさらされる可能性があります。Intent
は、内部コンポーネントによって定義されたカスタム アクションを使用します。暗黙的なインテントを使用すると、特定のコンポーネントを知らなくても、外部コンポーネントからのインテントの呼び出しが容易になります。この 2 つを組み合わせることで、アプリケーションは、目的のアプリケーション コンテキストの外部から、特定の内部使用のために指定されたインテントにアクセスできるようになります。Intent
を処理できることにより、情報漏洩や Denial of Service からリモート コード実行に至るまで、Intent
で指定された内部アクションのキャパシティに応じて、さまざまな深刻度の中間者攻撃が可能になります。Intent
を使用しています。
...
val imp_internal_intent_action = Intent("INTERNAL_ACTION_HERE")
startActivity(imp_internal_intent_action)
...
PendingIntent
が検出されています。暗黙的なペンディング インテントは、Denial of Service、個人情報やシステム情報の漏洩、権限昇格などのセキュリティ上の脆弱性を引き起こす可能性があります。Intent
を提供するために作成されます。暗黙的インテントは、一般的な名前やフィルタを使用して実行を決定することで、外部コンポーネントからのインテントの呼び出しを容易にします。Intent
が PendingIntent
として作成されると、Intent
が、想定される一時的なコンテキスト外で実行されている、意図しないコンポーネントに送信される可能性があります。その結果、システムが、Denial of Service、個人情報やシステム情報の漏洩、特権昇格などの攻撃にさらされることになります。PendingIntent
を使用しています。
...
val imp_intent = Intent()
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable_impintintent = PendingIntent.getService(
this,
0,
imp_intent,
flag_mut
)
...
FLAG_MUTABLE
に設定された PendingIntent
が検出されています。フラグ値 FLAG_MUTABLE
を使用して作成されたペンディング インテントでは、未指定の Intent
フィールドにダウンストリームを設定されやすく、その結果、Intent
のキャパシティが変更され、システムが攻撃にさらされやすくなります。PendingIntent
の基盤となる Intent
の変更を、作成後に許可すると、システムが攻撃にさらされやすくなります。これは主に、基盤となる Intent
の全体的な機能に依存します。ほとんどの場合、PendingIntent
フラグを FLAG_IMMUTABLE
に設定することが、潜在的な問題を防ぐためのベスト プラクティスです。FLAG_MUTABLE
を使用して作成された PendingIntent
が含まれています。
...
val intent_flag_mut = Intent(Intent.ACTION_GTALK_SERVICE_DISCONNECTED, Uri.EMPTY, this, DownloadService::class.java)
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable = PendingIntent.getService(
this,
0,
intent_flag_mut,
flag_mut
)
...
Intent
を使用してアクティビティを開始し、サービスを開始し、ブロードキャストを配信すると、攻撃者は内部アプリケーション コンポーネントを自由に起動し、内部コンポーネントの振る舞いを制御し、一時的な権限許可を通してコンテンツ プロバイダーから保護データに間接的にアクセスできるようになる可能性があります。Intent
の Extras Bundle にネスト化された任意の Intent
を受け入れます。startActivity
、startService
、または sendBroadcast
を呼び出すことで、任意の Intent
を使用してコンポーネントを起動します。Intent
を受け入れ、その Intent
を使用してアクティビティを開始しています。
...
Intent nextIntent = (Intent) getIntent().getParcelableExtra("next-intent");
startActivity(nextIntent);
...
search
メソッドに渡された javax.naming.directory.SearchControls
インスタンスで returningObjectFlag
を true
に設定するか、代わりにこのフラグを設定するライブラリ関数を使用することで、オブジェクトを返す検索を実行します。
<beans ... >
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="ou=users,dc=example,dc=org"
group-search-filter="(uniqueMember={0})"
group-search-base="ou=groups,dc=example,dc=org"
group-role-attribute="cn"
role-prefix="ROLE_">
</ldap-authentication-provider>
</authentication-manager>
</beans>
chroot()
などの操作を実行するのに必要な、昇格した権限レベルは、操作を実行したらすぐに降格させます。chroot()
などの権限を持つ関数をコールする場合、先に root
権限を獲得する必要があります。権限付きの操作が完了したら、プログラムは root
権限を降格させ、呼び出したユーザーの権限レベルに戻さなければなりません。chroot()
をコールして、アプリケーションを APP_HOME
配下のファイル システムのサブセットに制限することで、攻撃者がプログラムを使用して他の場所にあるファイルに無許可でアクセスできないようにしています。コードはユーザーが指定したファイルを開き、ファイルの内容を処理しています。
...
chroot(APP_HOME);
chdir("/");
FILE* data = fopen(argv[1], "r+");
...
setuid()
をコールしない場合、アプリケーションは不必要な root
権限で動作し続けます。悪意ある操作はすべてスーパーユーザーの権限で実行されることになるので、攻撃者によってアプリケーションに対して実行される悪用が成功すると権限昇格攻撃になります。アプリケーションが権限レベルを root
以外のユーザーに降格していれば、被害の可能性は大幅に減少します。CREATE
コマンドを作成します。攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
final String foldername = request.getParameter("folder");
IMAPFolder folder = (IMAPFolder) store.getFolder("INBOX");
...
folder.doCommand(new IMAPFolder.ProtocolCommand() {
@Override
public Object doCommand(IMAPProtocol imapProtocol) throws ProtocolException {
try {
imapProtocol.simpleCommand("CREATE " + foldername, null);
} catch (Exception e) {
// Handle Exception
}
return null;
}
});
...
USER
および PASS
コマンドを作成します。攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
String username = request.getParameter("username");
String password = request.getParameter("password");
...
POP3SClient pop3 = new POP3SClient(proto, false);
pop3.login(username, password)
...
VRFY
コマンドを作成します。攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入する可能性があります。
...
c, err := smtp.Dial(x)
if err != nil {
log.Fatal(err)
}
user := request.FormValue("USER")
c.Verify(user)
...
VRFY
command that is sent to the SMTP server.攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
String user = request.getParameter("user");
SMTPSSLTransport transport = new SMTPSSLTransport(session,new URLName(Utilities.getProperty("smtp.server")));
transport.connect(Utilities.getProperty("smtp.server"), username, password);
transport.simpleCommand("VRFY " + user);
...
VRFY
command that is sent to the SMTP server.攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
user = request.GET['user']
session = smtplib.SMTP(smtp_server, smtp_tls_port)
session.ehlo()
session.starttls()
session.login(username, password)
session.docmd("VRFY", user)
...
null
を戻すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。Item
プロパティによって戻される文字列が null
かどうかを、メンバー関数 Equals()
をコールする前にチェックしないので、null
Dereference の原因になる可能性があります。
string itemName = request.Item(ITEM_NAME);
if (itemName.Equals(IMPORTANT_ITEM)) {
...
}
...
null
値を間接参照してプログラムが異常終了するのにまかせても同じことです。」null
を返すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。malloc()
で戻されたポインタを使用する前に、メモリの割り当てが正しく行われたかチェックしていません。
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
malloc()
のコールが失敗に終わった理由が、req_size
の超過によるものか、許容範囲外の同時処理によるものか定かではありません。時間の経過とともに蓄積された Memory Leak によるものかも不明です。エラー処理を怠ると、原因を究明する術はありません。null
を返すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。getParameter()
によって戻される文字列が null
かどうかを、メンバー関数 compareTo()
をコールする前にチェックしないので、null
Dereference の原因になる可能性があります。例 2:次のコードは、
String itemName = request.getParameter(ITEM_NAME);
if (itemName.compareTo(IMPORTANT_ITEM)) {
...
}
...
null
に設定され、それが「常に定義される」という誤った前提でプログラマによって後から間接参照されるシステムプロパティを示します。
System.clearProperty("os.name");
...
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95") )
System.out.println("Not supported");
null
値を間接参照してプログラムが異常終了するのにまかせても同じことです。」NullException
を引き起こします。cmd
」という名前の定義されたプロパティがあると前提しています。攻撃者がプログラムの環境を制御して「cmd
」を未定義にできる場合、プログラムが Trim()
メソッドのコールを試みると NULL ポインタ例外が発生します。
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
null
であるかを確認する前に、null
の可能性があるポインタを間接参照する場合です。チェック後間接参照のエラーが発生するのは、プログラムが null
に対して明示的チェックを実行したにも関わらず、null
であることが判明しているポインタを間接参照した場合です。この種のエラーの多くは、タイプミスかプログラマの不注意が原因です。格納後間接参照のエラーは、プログラムが明示的にポインタを null
に設定し、後でそのポインタを間接参照した場合に発生します。このエラーは通常、変数の宣言時にプログラマがその変数を null
に初期化したことが原因で発生します。ptr
は NULL
ではないと仮定してします。この仮定は、プログラマがポインタを間接参照したときに明らかになります。その後プログラマが ptr
と NULL
を比較したときに、この仮定は成り立たなくなります。ptr
が if
ステートメントでチェックされたときに NULL
であるとすれば、間接参照されたときにも NULL
である可能性があり、これがセグメンテーション違反の原因となる場合があります。例 2: 次のコードでは、プログラマは変数
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
が NULL
であることを確認してから、続いてそれを誤って間接参照しています。ptr
が if
ステートメントでチェックされたときに NULL
になっていると、null
Dereference が発生し、これがセグメンテーション違反の原因となります。例 3: 次のコードでは、プログラマが文字列
if (ptr == null) {
ptr->field = val;
...
}
'\0'
(実際は 0) または NULL
を忘れたため、NULL ポインタを間接参照し、セグメンテーション違反を引き起こしています。例 4: 次のコードでは、プログラマは明示的に変数
if (ptr == '\0') {
*ptr = val;
...
}
ptr
を NULL
に設定しています。続いて、オブジェクトの null
値をチェックする前に ptr
を間接参照しています。
*ptr = NULL;
...
ptr->field = val;
...
}
NullPointerException
を引き起こします。cmd
」という名前の定義されたプロパティがあると前提しています。攻撃者がプログラムの環境を制御して「cmd
」を未定義にできる場合、プログラムが trim()
メソッドのコールを試みると NULL ポインタ例外が発生します。
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
unserialize()
関数に渡される前に適切にサニタイズされないときに発生します。攻撃者は特別製のシリアライズされた文字列を脆弱な unserialize()
コールに渡すことができ、アプリケーション スコープへの任意の PHP オブジェクト挿入を引き起こします。この脆弱性の重大度はアプリケーション スコープで利用可能なクラスに依存します。__wakeup
や __destruct
のような PHP マジック メソッドを実装したクラスは、攻撃者がそれらのメソッド内でコードを実行できるので、狙われます。__destruct()
マジックメソッドを実装し、クラスのプロパティとして定義されるシステム コマンドを実行する PHP クラスを示します。ここに、ユーザー指定データを使用した unserialize()
に対する安全でないコールもあります。
...
class SomeAvailableClass {
public $command=null;
public function __destruct() {
system($this->command);
}
}
...
$user = unserialize($_GET['user']);
...
Example 1
では、アプリケーションはシリアライズされた User
オブジェクトと予測される可能性がありますが、攻撃者は command
プロパティ向けの事前定義された値とともに SomeAvailableClass
のシリアル化されたバージョンを実際に提供できます。
GET REQUEST: http://server/page.php?user=O:18:"SomeAvailableClass":1:{s:7:"command";s:8:"uname -a";}
$user
オブジェクトに対するその他の参照がない場合にはデストラクタ メソッドがすぐに呼び出され、攻撃者により提供されたコマンドを実行します。unserialize()
が、BlackHat 2010 会議で Stefan Esser により紹介された、「Property Oriented Programming」として知られている技術を使用して呼び出されたときに、宣言された異なるクラスを繋げることができます。この技術により攻撃者は既存のコードを再利用してそのコード自身のペイロードを作成することができます。YAML.load()
のようなデータをデシリアライズする関数に渡される前に適切にサニタイズされないときに発生します。攻撃者は特別製のシリアライズされた文字列を脆弱な YAML.load()
コールに渡すことができます。その結果、デシリアライズの際にクラスがアプリケーションに読み込まれるのであれば、任意の Ruby オブジェクトをプログラムに挿入できます。これはさまざまな攻撃の機会を与える可能性があります。たとえば、Cross-Site Scripting の脆弱性を検出する検証ロジックをバイパスしたり、ハードコーディングされているように見える値で SQL Injectionを許したり、あるいは完全なコード実行を許すこともあります。YAML.load()
に対する安全でないコールもあります。
...
class Transaction
attr_accessor :id
def initialize(num=nil)
@id = num.is_a?(Numeric) ? num : nil
end
def print_details
unless @id.nil?
print $conn.query("SELECT * FROM transactions WHERE id=#{@id}")
end
end
end
...
user = YAML.load(params[:user]);
user.print_details
...
Example 1
では、アプリケーションはシリアライズされた User
オブジェクトを要求する可能性があり、print_details
という名前の関数も与えられます。しかしながら、攻撃者は実際にはシリアライズされたバージョンの Transaction
オブジェクトとその @id
属性の事前定義された値を与えることができます。そのため、次のような要求は、@id
が数値であることを確認する検証チェックのバイパスを許可します。
GET REQUEST: http://server/page?user=!ruby%2Fobject%3ATransaction%0Aid%3A4%20or%205%3D5%0A
user
パラメーターに !ruby/object:Transaction\nid:4 or 5=5\n
が割り当てられることがわかります。Transaction
型のオブジェクトが作成され、@id
が "4 or 5=5"
に設定されます。開発者は User#print_details()
をコールしているつもりでも、Transaction#print_details()
がコールされており、Ruby の文字列補間の結果、SQL クエリは SELECT * FROM transactions WHERE id=4 or 5=5
をクエリとして実行するように変更されます。句が追加されたことで、このクエリは true
として評価され、開発者が意図した単一行ではなく、transactions
テーブルにあるすべての行が返されます。YAML.load()
が、BlackHat 2010 会議で Stefan Esser により紹介された、「Property Oriented Programming」として知られている技術を使用して呼び出されたときに、宣言された異なるクラスを繋げることができます。この技術により攻撃者は既存のコードを再利用してそのコード自身のペイロードを作成することができます。