web-dev-qa-db-ja.com

C / C ++のprintf()はどのようにバッファオーバーフローの脆弱性ですか?

今読んだ記事によると、関数printfstrcpyは、バッファオーバーフローによるセキュリティの脆弱性と見なされています。私はstrcpyがどのように脆弱であるかを理解していますが、printfが実際にどのように脆弱であるかどうかを誰かが説明できますか、それとも間違っていると理解しています。

こちらが記事です: https://www.digitalbond.com/blog/2012/09/06/100000-vulnerabilities/#more-11658

具体的なスニペットは次のとおりです。

ベンダーはソースコードを機械的に検索しており、「strcpy()」や「printf()」などのバッファオーバーフロー対応のCライブラリ関数が50,000奇数回使用されていることを発見しました。

ありがとう!

14
DarkMantis

printf()ではなくprintf(arg)のようなユーザー提供の引数をフォーマット文字列として使用することにより、printf("%s", arg)で問題が発生する可能性があります。私はそれがあまりにも頻繁に行われるのを見てきました。呼び出し元は追加の引数をプッシュしなかったため、偽の_%_指定子を含む文字列を使用して、スタックにあるものを読み取ることができ、_%n_を使用すると、いくつかの値がメモリに書き込まれます(_%n_は、「次の引数は_int *_です。これまでに出力された文字数をそこに書き込んでください)。

しかし、あなたが引用した記事に単純な誤植が含まれていて、実際にはsprintf()ではなくprintf()を意味しているほうが、もっともらしいと思います。

gets()を除いて、本質的に脆弱なC関数はなく、careで使用する必要のある関数のみであると主張することもできます。 snprintf()のような「安全な」置換は実際には問題を解決しません;バッファオーバーフローをサイレントトランケーションに置き換えることで非表示にします。

18
Tom Leek

@Tomによる回答に加えて、 OWASPコードレビューガイドライン にもご案内します。printf()の使用に関するいくつかの問題が強調表示されており、- this 回答です。 cs.stackexchange Webサイトで同様の質問に。

6
Jor-el

このオーバーフローがどのように役立つかを示す例を次に示します。プライベートメンバー(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

3
Gabriel

一部のprintfディレクティブ(つまり、%n)はスタックにあるアドレスに副作用があるため、明示的な出力が正しく実装されていても、printディレクティブは危険な場合があります。

2
ddyer