今読んだ記事によると、関数printf
とstrcpy
は、バッファオーバーフローによるセキュリティの脆弱性と見なされています。私はstrcpy
がどのように脆弱であるかを理解していますが、printfが実際にどのように脆弱であるかどうかを誰かが説明できますか、それとも間違っていると理解しています。
こちらが記事です: https://www.digitalbond.com/blog/2012/09/06/100000-vulnerabilities/#more-11658
具体的なスニペットは次のとおりです。
ベンダーはソースコードを機械的に検索しており、「strcpy()」や「printf()」などのバッファオーバーフロー対応のCライブラリ関数が50,000奇数回使用されていることを発見しました。
ありがとう!
printf()
ではなくprintf(arg)
のようなユーザー提供の引数をフォーマット文字列として使用することにより、printf("%s", arg)
で問題が発生する可能性があります。私はそれがあまりにも頻繁に行われるのを見てきました。呼び出し元は追加の引数をプッシュしなかったため、偽の_%
_指定子を含む文字列を使用して、スタックにあるものを読み取ることができ、_%n
_を使用すると、いくつかの値がメモリに書き込まれます(_%n
_は、「次の引数は_int *
_です。これまでに出力された文字数をそこに書き込んでください)。
しかし、あなたが引用した記事に単純な誤植が含まれていて、実際にはsprintf()
ではなくprintf()
を意味しているほうが、もっともらしいと思います。
(gets()
を除いて、本質的に脆弱なC関数はなく、careで使用する必要のある関数のみであると主張することもできます。 snprintf()
のような「安全な」置換は実際には問題を解決しません;バッファオーバーフローをサイレントトランケーションに置き換えることで非表示にします。
@Tomによる回答に加えて、 OWASPコードレビューガイドライン にもご案内します。printf()の使用に関するいくつかの問題が強調表示されており、- this 回答です。 cs.stackexchange Webサイトで同様の質問に。
このオーバーフローがどのように役立つかを示す例を次に示します。プライベートメンバー(pwdなど)にアクセスできない場合を想像してください。printfを使用すると、この変数の内容を確認できます。
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
struct SecureLogin{
SecureLogin(const char * login_)
{
strcpy(login,login_);
strcpy(pwd,"ijk");//the user does not see this part of the source code as it is in a DLL
}
char login[8];
private:
char pwd[8];
};
int main() {
// your code goes here
SecureLogin log("abc");
printf("Pwd = %s\n",(&log.login[0])+8);
// Pass a string address which is the base address of the login
// field, but add 8 bytes, which skips onto the pwd field (we know
// login is 8 bytes)
return 0;
}
出力:
Pwd = ijk
一部のprintfディレクティブ(つまり、%n)はスタックにあるアドレスに副作用があるため、明示的な出力が正しく実装されていても、printディレクティブは危険な場合があります。