0
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#define MAX 3
#define ARG "cat .passwd"
integer main( integer argc, char ** argv )
{
char * names[] = {"strlen", "atoi", "printf", "puts"};
void (*reachable_functions[])( char * ) = {strlen, atoi, printf, puts};
void (*unreachable_functions[])( char * ) = {system};
integer i, index = 0;

for( i=1; i<argc; i++ )
{
    index += strlen(argv[i]);
}

if( index <= MAX )
{
    (reachable_functions[MAX-1])( "Calling ");
    (reachable_functions[MAX-1])( names[index] );
    (reachable_functions[MAX-1])( ".\n" );
    (reachable_functions[index])( ARG );
}
else
{
    (reachable_functions[MAX])( "Out of bounds !\n" );
}

return 0;
}

セグメンテーション フォールトを取得できますが、到達不能関数を呼び出すことはできません!?! 整数に問題があることは知っていますが、それを悪用することはできません.... :(それを呼び出す方法はありますか? Thx

4

1 に答える 1

3

十分な長さの十分な引数を渡すと、長さの合計がオーバーフローする可能性があります (整数型が 32 ビットの場合、シェルが実際にそのような引数を処理できるかどうかはわかりませんが、16 ビット整数では機能するはずです)。

符号付き整数のオーバーフロー ( であるintegerべきだと思いますint) は未定義の動作であるため、その場合に何が起こるかは、コンパイラとプラットフォーム (そしておそらく月の満ち欠け) によって異なりますが、合計は負の数に戻る可能性があります。その場合、コンパイラが配列をどのように配置したかに応じて、呼び出し

(reachable_functions[index])( ARG );

実際に「到達不能」関数を呼び出すことができます。これは、より未定義の動作であり、負のインデックスで配列にインデックスを付けますが、エクスプロイトの可能性があります。

その悪用を防ぐために (未定義の動作が許す限り)、index比較で符号なしの型にキャストすることができます。

if( (unsigned int)index <= MAX )

unsigned intの幅が の幅に等しいすべての合理的な実装では、が実際に非負intであることを保証します (ここでも、未定義の動作が発生した後、標準はプログラムの動作について何も保証しないことに注意してください)。indexより大きい数値INT_MAX

妄想的な人は、インデックス作成操作でキャストすることもできます。

于 2012-09-20T07:04:25.007 に答える