GNU/Linux >> Belajar Linux >  >> Linux

Linux Shellcode Halo, Dunia!

Seperti yang disebutkan BSH, kode shell Anda tidak berisi byte pesan. Melompat ke MESSAGE beri label dan panggil GOBACK rutin tepat sebelum mendefinisikan msg byte adalah langkah yang baik karena alamat msg akan berada di bagian atas tumpukan sebagai alamat pengirim yang dapat dimunculkan ke ecx , tempat alamat msg disimpan.

Tetapi kode milik Anda dan BSH memiliki sedikit batasan. Ini berisi NULL bytes ( \x00 ) yang akan dianggap sebagai akhir string saat direferensikan oleh penunjuk fungsi.

Ada cara cerdas untuk mengatasi hal ini. Nilai yang Anda simpan ke dalam eax, ebx and edx cukup kecil untuk ditulis langsung ke nibble yang lebih rendah dari masing-masing register sekaligus dengan mengakses al, bl and dl masing-masing. Gigitan bagian atas mungkin mengandung nilai sampah sehingga dapat di-xor.

b8 04 00 00 00 ------ mov $0x4,%eax


menjadi

b0 04          ------ mov $0x4,%al
31 c0          ------ xor    %eax,%eax


Berbeda dengan set instruksi sebelumnya, set instruksi baru tidak berisi byte NULL.

Jadi, program terakhirnya terlihat seperti ini :

global _start

section .text

_start:
jmp message

proc:
    xor eax, eax
    mov al, 0x04
    xor ebx, ebx
    mov bl, 0x01
    pop ecx
    xor edx, edx
    mov dl, 0x16
    int 0x80

    xor eax, eax
    mov al, 0x01
    xor ebx, ebx
    mov bl, 0x01   ; return 1
    int 0x80

message:
    call proc
    msg db " y0u sp34k 1337 ? "

section .data

Merakit dan menghubungkan :

$ nasm -f elf hello.asm -o hello.o
$ ld -s -m elf_i386 hello.o -o hello
$ ./hello
 y0u sp34k 1337 ? $ 

Sekarang ekstrak kode shell dari hello binary :

$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done

keluaran:

\xeb\x19\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x12\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xb3\x01\xcd\x80\xe8\xe2\xff\xff\xff\x20\x79\x30\x75\x20\x73\x70\x33\x34\x6b\x20\x31\x33\x33\x37\x20\x3f\x20

Sekarang kita dapat memiliki program driver untuk meluncurkan kode shell.

#include <stdio.h>

char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb"
                   "\xb3\x01\x59\x31\xd2\xb2\x12\xcd"
                   "\x80\x31\xc0\xb0\x01\x31\xdb\xb3"
                   "\x01\xcd\x80\xe8\xe2\xff\xff\xff"
                   "\x20\x79\x30\x75\x20\x73\x70\x33"
                   "\x34\x6b\x20\x31\x33\x33\x37\x20"
                   "\x3f\x20";


int main(int argc, char **argv) {
    (*(void(*)())shellcode)();
    return 0;
}

Ada fitur keamanan tertentu dalam kompiler modern seperti perlindungan NX yang mencegah eksekusi kode di segmen atau tumpukan data. Jadi kita harus secara eksplisit menentukan kompiler untuk menonaktifkan ini.

$ gcc -g -Wall -fno-stack-protector -z execstack launcher.c -o launcher

Sekarang launcher dapat dipanggil untuk meluncurkan kode shell.

$ ./launcher
 y0u sp34k 1337 ? $ 

Untuk kode shell yang lebih kompleks, akan ada rintangan lain. Kernel Linux modern memiliki ASLR atau Address Space Layout Randomization Anda mungkin perlu menonaktifkan ini sebelum menyuntikkan kode shell, terutama saat melewati buffer overflows.

[email protected]:~# echo 0 > /proc/sys/kernel/randomize_va_space 

Saat Anda menyuntikkan kode shell ini, Anda tidak tahu apa yang ada di message :

mov ecx, message

dalam proses yang disuntikkan, itu bisa berupa apa saja tetapi tidak akan menjadi "Hello world!\r\n" karena itu ada di bagian data saat Anda hanya membuang bagian teks. Anda dapat melihat bahwa shellcode Anda tidak memiliki "Hello world!\r\n" :

"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xb9\x00\x00\x00\x00"
"\xba\x0f\x00\x00\x00"
"\xcd\x80\xb8\x01\x00"
"\x00\x00\xbb\x00\x00"
"\x00\x00\xcd\x80";

Ini adalah masalah umum dalam pengembangan shellcode, cara mengatasinya adalah dengan cara ini:

global _start

section .text

_start:
    jmp MESSAGE      ; 1) lets jump to MESSAGE

GOBACK:
    mov eax, 0x4
    mov ebx, 0x1
    pop ecx          ; 3) we are poping into `ecx`, now we have the
                     ; address of "Hello, World!\r\n" 
    mov edx, 0xF
    int 0x80

    mov eax, 0x1
    mov ebx, 0x0
    int 0x80

MESSAGE:
    call GOBACK       ; 2) we are going back, since we used `call`, that means
                      ; the return address, which is in this case the address 
                      ; of "Hello, World!\r\n", is pushed into the stack.
    db "Hello, World!", 0dh, 0ah

section .data

Sekarang buang bagian teks:

$ nasm -f elf shellcode.asm
$ ld shellcode.o -o shellcode
$ ./shellcode 
Hello, World!
$ objdump -d shellcode

shellcode:     file format elf32-i386


Disassembly of section .text:

08048060 <_start>:
 8048060:   e9 1e 00 00 00   jmp    8048083 <MESSAGE>

08048065 <GOBACK>:
 8048065:   b8 04 00 00 00   mov    $0x4,%eax
 804806a:   bb 01 00 00 00   mov    $0x1,%ebx
 804806f:   59               pop    %ecx
 8048070:   ba 0f 00 00 00   mov    $0xf,%edx
 8048075:   cd 80            int    $0x80
 8048077:   b8 01 00 00 00   mov    $0x1,%eax
 804807c:   bb 00 00 00 00   mov    $0x0,%ebx
 8048081:   cd 80            int    $0x80

08048083 <MESSAGE>:
 8048083:   e8 dd ff ff ff   call   8048065 <GOBACK>
 8048088:   48               dec    %eax                    <-+
 8048089:   65               gs                               |
 804808a:   6c               insb   (%dx),%es:(%edi)          |
 804808b:   6c               insb   (%dx),%es:(%edi)          |
 804808c:   6f               outsl  %ds:(%esi),(%dx)          |
 804808d:   2c 20            sub    $0x20,%al                 |
 804808f:   57               push   %edi                      |
 8048090:   6f               outsl  %ds:(%esi),(%dx)          |
 8048091:   72 6c            jb     80480ff <MESSAGE+0x7c>    |
 8048093:   64               fs                               |
 8048094:   21               .byte 0x21                       |
 8048095:   0d               .byte 0xd                        |
 8048096:   0a               .byte 0xa                      <-+

$

Baris yang saya tandai adalah "Hello, World!\r\n" kita string:

$ printf "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"
Hello, World!

$ 

Jadi bungkus C kita akan menjadi:

char code[] = 

    "\xe9\x1e\x00\x00\x00"  //          jmp    (relative) <MESSAGE>
    "\xb8\x04\x00\x00\x00"  //          mov    $0x4,%eax
    "\xbb\x01\x00\x00\x00"  //          mov    $0x1,%ebx
    "\x59"                  //          pop    %ecx
    "\xba\x0f\x00\x00\x00"  //          mov    $0xf,%edx
    "\xcd\x80"              //          int    $0x80
    "\xb8\x01\x00\x00\x00"  //          mov    $0x1,%eax
    "\xbb\x00\x00\x00\x00"  //          mov    $0x0,%ebx
    "\xcd\x80"              //          int    $0x80
    "\xe8\xdd\xff\xff\xff"  //          call   (relative) <GOBACK>
    "Hello wolrd!\r\n";     // OR       "\x48\x65\x6c\x6c\x6f\x2c\x20\x57"
                            //          "\x6f\x72\x6c\x64\x21\x0d\x0a"


int main(int argc, char **argv)
{
    (*(void(*)())code)();

    return 0;
}

Mari kita coba, menggunakan -z execstack untuk mengaktifkan read-implies-exec (di seluruh proses, meskipun namanya "tumpukan") sehingga kita dapat mengeksekusi kode di .data atau .rodata bagian:

$ gcc -m32 test.c -z execstack -o test
$ ./test 
Hello wolrd!

Berhasil. (-m32 diperlukan juga, pada sistem 64-bit. int $0x80 ABI 32-bit tidak berfungsi dengan alamat 64-bit seperti .rodata dalam PIE yang dapat dieksekusi. Juga, kode mesin dirakit untuk 32-bit. Kebetulan urutan byte yang sama akan mendekode ke instruksi yang setara dalam mode 64-bit tetapi tidak selalu demikian.)

GNU modern ld menempatkan .rodata di segmen terpisah dari .text , sehingga tidak dapat dieksekusi. Dulu cukup menggunakan const char code[] untuk meletakkan kode yang dapat dieksekusi di halaman data hanya-baca. Setidaknya untuk shellcode yang tidak ingin memodifikasi dirinya sendiri.


Linux
  1. Memulai dengan perintah cat Linux

  2. Linux – Bagaimana Mono Ajaib?

  3. Smalltalk Hello World Contoh:Cara Menulis dan Menjalankan Program Smalltalk di OS Linux

  1. Fortran Hello World Contoh:Cara Menulis dan Menjalankan Program Fortran di OS Linux

  2. Contoh XQuery Hello World:Cara Menulis dan Menjalankan Program XQuery di OS Linux

  3. Bagaimana cara menambahkan perangkat lunak saya sendiri ke paket Buildroot Linux?

  1. Linux – Izin File Hanya Jalankan?

  2. Gunakan perintah grep Linux

  3. Skrip Bash - Contoh Halo Dunia