バッファアンダーフローはどのようにして64ビットでのリモートコード実行につながる可能性がありますか?

git‑shell /bin/bashは実行するプログラムに置き換えられているため、他のことを行うことはできません)

struct _raw_uncapped_ssh_string { // no limit on the size of the string; uint32_t len; char non_null_terminated_string[]; // by protocol design it have a minimum length of 1 }; typedef struct _raw_uncapped_ssh_string raw_ssh_string; union buffer { void * uncapped_zlib_decompressed_network_data; // yes, the size is uncapped, so it’s possible to put 4Gb of // data in it that would be copied later into memory. zlib // allow easily to turn some Mb in Gb of data, but it’s not // the point of the question. raw_ssh_string st; }; get_command (compressed_network_data) { size_t len; char * command; buffer string=uncompress_to_buffer(compressed_network_data); len=ntohl(string.st.len)+1; command=malloc(len+1); command[len]=0; // here’s the point, both the string length and content as // well it’s supplied size is controlled by the attacker. memcpy(command,string.st.data,len); return command; } 

これがコマンドが後でどのように実行されるか(文字列commandget_command()の後も変更されません)

const char *args[]={"/bin/bash",command,NULL}; // /bin/bash isn’t the shell, it has been replaced by git‑shell. // redirect the program output to the network. dup2(stdin, 0); dup2(stdout,1); dup2(stdout,2); close(stdin); close(stdout); //if this return execution failed and print an error message return execv(args[0],(char * const *)args); // I don’t know which is the system, so I can’t know about the libc behaviour. 

memcpy(command,string.st.data,0) memcpyの3番目のメンバーが最小サイズは1で、私のコンテキストでは、size_tは64ビットの整数を使用していますが、len

私にできることは、lenstring.st.dataに割り当てられた値よりも大きい値に設定することだけです。これは、未割り当てのメモリを読み取ることができるバッファアンダーフローです。
サーバーメモリを読み取ることはできますが、パブリックsshサーバーが保持できる機密データを確認できません(私の場合は、 ssh is publicを実行できます)

リモートでのバッファアンダーフローも同様ですmemcpyコード実行?

コメント

  • コードが実際に実行される場合command[len] = 0長さlenのバッファの最大インデックスはlen-1であるため、これはバッファオーバーフローです。または、実際のコードがmalloc(len)ではなくmalloc(len+1)を実行する場合は、

    の値を0xFFFFFFFFに設定します。

  • @ThomasPornin:これは私の部分からのエラーではありません。実際、いくつかの関数を呼び出して実行します。この。残りが真であると仮定します。
  • @ThomasPornin:64ビットについて話します。lenはsize_tであるため、64ビットの整数を使用します。したがって、整数オーバーフローの方法はありません。
  • @ThomasPornin彼らはlen+1を割り当てるので、0への設定は有効であるはずです。
  • @RoraΖ:彼はstring.st.lenを‑1に設定することについて話していました。

回答

一般に、いいえ、バッファアンダーフローをリモートコード実行に使用することはできません。攻撃者が制御するデータが割り当てられたスペースを離れることはないため、プログラムの実行フローを引き継ぐことはできません。

バッファアンダーフローには、次のような他のタイプの攻撃の可能性があります。情報の開示(プログラムがバッファの元のコンテンツが新しいデータによって消去されることを期待している場合)

コメント

  • または私として最近gitで見たが、後でバッファオーバーフローに変わる。

回答

この応答を最初に書いたとき、あなたが抱いているいくつかの誤解を私は理解したようです。これらの誤解は、あなたが私の答えを理解するのを妨げる可能性があります。明確にするために、私はこのテキストを大きくして強調し、軽蔑しないようにします。

使用する用語の多くは、あなたがそれらが意味すると思われることを意味するものではありません。

例:

  • memcpyの3番目のメンバーは、

    は関数であり、structまたはunionではありません。

  • lenがあるため、バッファオーバーフローを実行できません。また、ガソリンがあるため、ガソリンが不足することはありません。質問?特に理論的に言えば、あなたのコードはバッファオーバーフローを引き起こす可能性があるので、私にはぴったりのアナロジーのようです。
  • 「私にできることはを設定することだけです。 div id = “82b7b4b452″>

string.st.dataに割り当てられた値よりも大きい値にします。これはバッファアンダーフローです…」いいえ、これはバッファアンダーフローの定義ではありません。負のインデックスまたは原因となるインデックスを使用して範囲外の配列にアクセスすると、バッファアンダーフローが発生します。ポインタ演算のラッピングが発生します。後者は一部の構成で可能かもしれませんが(「64ビットシステム」でも、それが意味するものは何でも)、これらの単語を書いていたときにこれが意味したことではないかと思います。 with:

  • “…割り当てられていないメモリを読み取れるようにします。” おそらく「初期化されていないメモリ」を意味していると思います。明確にするために、あなたはあなたが「超過分を割り当て、超過分を初期化せずに残しました。おそらく、それについて何かしたいと思うでしょう(callocまたはmemset)。
  • char *fubar = NULL;について少し考えてみましょう…この種のポインタは通常ゼロ値。逆参照は nullポインター逆参照と見なされますが、0["hello"]のように記述すると、"hello"[0](つまり、"h")。したがって、攻撃者が中括弧の間の式を制御する場合、攻撃でnullポインターの逆参照が使用される可能性があります(状況に応じて)。

    fubar事; memset(&fubar, UCHAR_MAX, sizeof fubar);とすると、fubarはすべて1ビットになります。つまり、アドレスである可能性があります これは、システムが(理論的に)対応できる最大のアドレスです。fubar[1]にアクセスするとどうなりますか?最大のアドレスのの要素にアクセスするにはどうすればよいですか?アドレスはその後ラップアラウンドしますか?技術的には、これはすべて未定義の動作ですが、一般的なアーキテクチャで 名前を付けると、次のようになります。

    1. の算術オーバーフローポインタ、それにつながる…
    2. Nullポインタの逆参照、および/または潜在的にバッファアンダーフロー

    memcpyのバッファアンダーフローはリモートコード実行を許可しますか?

    バッファアンダーフローにより、攻撃者は問題の配列の前のメモリ領域にある関数ポインタを上書きする可能性があります。これらの関数ポインタがシェルコードを指すようになっている場合、そのシェルコードは後で呼び出されたときに実行されます。

    このややあいまいなコードでは、「intの幅が広い場合にバッファアンダーフローのリスクがあるように見えます。 uint32_tよりもドメイン。ntohl(string.st.len)+1を使用すると、uint32_tの値がintタイプ。たとえば、INT_MIN-42949672960 - UINT32_MAXより1つ小さい)である場合を考えてみます。 INT_MAX4294967295です…これは基本的に33ビットのintです。バイトの幅までパディングするパディング。珍しいですが、可能です。この状況では、式ntohl(string.st.len)+1はタイプがuint32_tではありません。タイプはintであり、符号なし整数オーバーフローが発生したときに0にラップバックするのではなく、おそらく-4294967296 符号付き整数オーバーフローが発生した場合。

    バッファアンダーフローに対する保証を探している場合は、整数リテラルサフィックス(つまり、ntohl(string.st.len)+1U)。その場合、式はuint32_tまたはunsigned intのいずれかになります(どちらのタイプが最大かによって異なります)。ドメイン)。

    ntohl(string.st.len)がその符号なし型の最大値(それが何であれ)よりも1つ小さい値を返す可能性があると考える場合は、len=ntohl(string.st.len)+1は最大値になり、malloc(len+1) unsigned wrapping を引き起こすため、、次にcommand[len]=0は、配列の終わりを超えて正しく書き込みます。その後、もちろん、また memcpy(command,string.st.data,len);に問題が発生します(これはバッファオーバーフローです)。

    バッファアンダーフローとオーバーフローだけがリスクではありません。 しない場合は、malloc

    NULLを返し、nullポインターの逆参照を使用して任意のコードを実行できます。これは、

    が失敗して発信者に返されます。これは、同じ方法を使用して、ラッピングの問題を確認して発信者に通知できることも意味します。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です