Web Buggery: Analyzing Tracking Images
Web Bugs are images (Gifs, Jpegs, PNGs, etc.) that companies and organizations put into web pages, e-mails and other HTML supporting documents to track information about the viewer. These images are sometime know by other names such as tracking bugs, pixel tags, web beacons or clear gifs. What ever the name, their function is largely the same.
Under normal circumstances an organization would just look at their web logs to find the kind of information that a Web Bug might provide them. However, if the content the web bugger wishes to track is not hosted on their site, but instead its hosted from a third party's server, then the web bugger can not obtain this information since they would not have access to the web server logs. By putting an image from one of their servers into an HTML E-mail or a third party's webpage the Web Buggers can find the data they want about the contents viewer. Some of the interesting information items that can be obtained about the viewer are:
#!/bin/bash echo "Content-Type: image/gif" echo cat x.gif OUTPUT=" $QUERY_STRING,$REMOTE_ADDR,$HTTP_USER_AGENT,$HTTP_ REFERER,`date`" echo $OUTPUT >> log.txt sleep 2.5
Explanation: The Bash script above is pretty simple. To get this script to run on your server use the following steps:
1. Create a gif image of any size (for my tests I used a 1 by 1 gif) and save it into your cgi-bin.
2. Copy the script text above into a file and call it webbug.cgi.
3. Make the script executable with the following command: chmod +x webbug.cgi
4. Create a blank text file and set permissions with the following three commands:
touch log.txt chown www-data log.txt chmod 600 log.txt
Note: You could set the permissions using the command "chmod 666 log.txt" but this is not a very secure way to do things. It's far better to find out the account Apache is running under (in my case www-data) and assign write permissions to that account only. If you do not know what account Apache is running under try using the "lsof –i" command to figure it out.
What this Bash script will do is send the proper headers and the gif data to the requesting browser then log the client information to a CSV text file (log.txt in this case). The last line "sleep 2.5" is there because I kept getting error messages like "Premature end of script headers" when I used the script. The sleep time can be lessened if you want to play around with it, or a better programmer than I might have a more elegant solution. A line of output from the log.txt file should look something like the following:
<QUERY_STRING>,192.168.18.33,Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1),http://irongeek.com/bugtest/index.php,Wed Oct 13 17:15:21 EDT 2004
Where <QUERY_STRING> is the contents of the server variable QUERY_STRING that was passed to the CGI. The QUERY_STRING variable contains whatever information is inserted past the question mark at the end of the image URL. You will see how we pass the QUERY_STRING variable later in the article.
$im = imagecreatefrompng("1by1.PNG");
imagecolortransparent ( $im,imagecolorallocate($im, 255, 255, 255));
$QUERY_STRING = preg_replace("%[^/a-zA-Z0-9@,_]%", '', $_SERVER['QUERY_STRING']);
$filename = 'webbug.csv';
$fp = fopen($filename, "a");
.date("D dS M,Y h:i a").'"'."\n";
$write = fputs($fp, $string);
//end Write Log
Explanation: The PHP script above needs some image manipulation libraries for PHP installed on your server, see http://us3.php.net/manual/en/ref.image.php for more information on the libraries you will need. To get this PHP script to work on your server use the following steps:
1. Create a PNG image of any size (for my tests I used a 1 by 1 PNG) and save it to the same directory where you plan to put the PHP file.
2. Copy the script text above into a file and call it webbug.php.
3. Create a blank CSV file and set permissions with the following three commands:
touch webbug.csv chown www-data webbug.csv chmod 600 webbug.csv
Note: You could set the permissions using the command "chmod 666 webbug.csv" but this is not a very secure way to do things. It's far better to find out the account Apache is running under (in my case www-data) and assign write permissions to that account only. If you do not know what account Apache is running under try using the "lsof –i" command to figure it out.
What this PHP script will do is send the proper headers and PNG data to the requesting browser then log the client information to a CSV text file (in this case webbug.csv). The PHP script is a little harder to get working than the Bash script, but far more flexible for modification and a bit more secure. A line of output from the webbug.csv file should look something like the following:
"<QUERY_STRING>,","192.168.26.138","adrian.irongeek.com","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910","","Wed 13th Oct,2004 11:04 am"
Where <QUERY_STRING> is the contents of the server variable QUERY_STRING that was passed to the CGI. The QUERY_STRING variable contains whatever information is inserted past the question mark at the end of the image URL. You will see how we pass this variable in the next section.
Placing Web Bugs into Web Pages
If you know a little HTML placing a web bug into a page is easy. Just a simple image tag will do it:
The string past the question mark (some-extra-stuff) is the data that will be passed into the QUERY_STRING server variable. It could contain and email address, or as the next example shows, information about the viewer's client pulled from java script:code:
adc,Netscape,1024x768,true,32,32,,192.168.170.55,Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007,http://irongeek.com/bugtest/index.php,Wed Oct 13 20:06:09 EDT 2004
As you can see the above data contains information such as screen resolution, color depth and other data about the browser. Pretty cool huh?
Placing Web Bugs into a Web Forum
Many forums allow users to place images in their posts and signatures. Look at the forum's documentation to figure out how to insert an image. Please note that most forum systems require that the last part of a URL to an image ends in png, gif or jpeg/jpg. We can still get a web bug script to work by setting up a redirect in Apache. The rediect can be made by adding a line like the following to our httpd.conf file:
Redirect /webbug.png /webbug.php
By doing this we can use the URL http://tux.irongeek.com/webbug.png as the URL to our web bug image. For example, to put a web bug into a post or signature on a phpBB system the bugger could use the following site code:
This site code works for many popular forum systems, including the one Antionline uses (at least for signatures).code:
E-mailing a Web Bug
E-mailing a Web Bug is a little more involved than just placing it on a web page. Newer clients should have options to disallow HTML e-mails or to not download off site images (Gmail does not download off site images by default), but many folks ignore these options or choose to download external images anyway. In this section I'll show how to send and HTML e-mail by telneting to port 25 on the mail server of the target e-mail address' domain. For my demonstration I will be emailing two web bugs to my Gmail account.
The first thing we need to do is find out the Mail Exchange (MX ) of the domain we want to e-mail. To do this in Windows we can use the following command:
The above command should work in Linux also, but since the nslookup command is depreciated in Linux you may need to use the following dig command instead:code:
nslookup -querytype=mx gmail.com
By using the nslookup command we get the following information:code:
dig gmail.com mx
From the above output we see that gsmtp171.google.com is one of the mail servers, so lets telnet to port 25 on gsmtp171.google.com to establish a connection and send som email:code:
C:\>nslookup -querytype=mx gmail.com Server: dns2.irongeek.com Address: 192.168.162.1 Non-authoritative answer: gmail.com MX preference = 10, mail exchanger = gsmtp171.google.com gmail.com MX preference = 20, mail exchanger = gsmtp57.google.com gmail.com nameserver = ns4.google.com gmail.com nameserver = ns1.google.com gmail.com nameserver = ns2.google.com gmail.com nameserver = ns3.google.com gsmtp171.google.com internet address = 126.96.36.199 ns1.google.com internet address = 188.8.131.52 ns2.google.com internet address = 184.108.40.206 ns3.google.com internet address = 220.127.116.11 ns4.google.com internet address = 18.104.22.168 C:\>
Once the connection is established we use SMTP commands to create an HTML email with image tags pointing to our web bugs. In the following dialog the blue text is what the mail server sends us and the red text is what we send to the mail server:code:
C:\>telnet gsmtp171.google.com 25
220 mx.gmail.com ESMTP 70si2094099rnb
250 mx.gmail.com at your service
354 Please start mail input.
Subject: Webbug test
Content-Type: text/html; charset="ISO-8859-1";
<h2>Web Bug Test</h2>
Here's a Web Bug Test!
250 Mail queued for delivery.
221 Closing connection. Good bye.
Connection to host lost.
In the above example I set the senders name as my account on the Irongeek.com domain, but I could have just as easily faked the information and sent it as any email address I wished (email@example.com for example). If the above works, when the target opens the email we should see an entry in our logs like the following:
"firstname.lastname@example.org","192.168.26.138","adrian.irongeek.com","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910","http://gmail.google.com/gmail?view=cv&search=inbox&th=ff8f2f8f4869ea0&zx=a0b38249bec42991407828296","Tue 12th Oct,2004 06:05 pm"
If a spammer used a web bug and HTML e-mail like this one they would now know that Irongeek@ggmail.com is a valid e-mail address and a little more about the victim's web browser and ISP.
Detection and Prevention
You can find web bugs by viewing the HTML source code of a web page and looking for strange image tags like the ones in the examples above, or by finding images that don't show on the page because they are one pixel is size and/or transparent. Unfortunately even looking for these signs is no guarantee that you will spot a web bug since it could be any image on the page.
Preventing web bugs in e-mail is pretty simple, just look in your e-mail readers documentation for how to disable HTML e-mail or block external images. Some web e-mail services like Gmail disable external images by default, which is a good thing. Some newer mail clients, like Outlook 20003, also default to not loading image from outside sites.
For the most part I feel that web bugs outside of e-mail are only a problem for the most paranoid among us. I use web bugs regularly myself to track pages I host on web servers I can't get the logs for and web bugs have some great beneficial uses for a web master trying his best to tailor his site to the reader's web browser by finding out the most common browser types and screen resolutions. I do however recommend turning off images in HTML email since they can be used by spammers to confirm e-mail addresses.
I think that's about all I have to say on the subject of web bugs, so I guess I bugger off now.
WebBug Source Code
If you would like a more complicated example of a web bug, please take a look at this source code:
It's more or less the same code I use for my sites logo script. It logs to a MySQL server so it's easy to query results using something like PHPMyAdmin, you just have to make some minor changes to config.php.
The Electronic Frontier Foundation had a great FAQ on Web Bugs:
Wikipedia enty on Web Bugs.
7 reason why HTML e-mail is EVIL:
Using the HOSTS file in Linux, Windows and Mac OS to block web bugs and ads:
Special thanks to Jake Howlett who wrote the following article that help me figure out how to send HTML in e-mail:
07/04/2008: Added source code for my PHP & MySQL web bug. I also cleaned up the page's layout and changed email addresses to make them non-valid.
10/15/2004: Article first posted.