Proxy Automatic Configuration Files

So I finally decided to start blogging, after countless mental arguments with myself about what I will blog about, and whether or not I have time for this shit… Turns out I do have time, and what better topic could I select then that grey area of networks that is PAC, or WPAD scripts?

There has been a lot of hype over the years surrounding the security of PAC scripts, leaving gaping back doors into networks. Hackers can do all sorts of clever things involving DHCP, DNS and WINS spoofing to silently re-route web traffic through a malicious proxy server, exposing valuable credentials, such as network passwords or even financial details.

Although a lot of things can be done client side to prevent such attacks, certain operating systems still remain vulnerable to these scenarios, and studies show that the most effective way to protect your network from these attacks, is to implement them yourself.

So what is a PAC file, and why aren’t they more widely used?

A PAC file is a Proxy Automatic Configuration File. It is used on a network that requires connection to the Internet via a web proxy to publish the settings of the proxy server. The main reason for the lack of uptake, is the complexity of implementation and administration of these files. Although there are more complex systems out there, the advantages of a PAC file are minute when measured up against the administration required to keep them optimized.

So today I decided to do something about the administrative nightmare, and attempt to bring some order back into the good old pac file. I will share my techniques with you, and hopefully help the next average Joe to attempt this in some way.

I by no means believe this to the most secure way to implement PAC files on your network, but I believe it to be an easier administrative task managing exceptions and routes for the PAC file. Bare with me, this is the first time I have ventured into blogging so I may well be useless, but we will see.

So here’s what I did.

First thing that we need to do is configure our network to serve up the PAC or WPAD file. I chose a WPAD file, for simplicity, but both files work in the same way. We will need to configure DNS, DHCP and IIS to accomplish our goal, so we will start with DNS.

A lot of clients will automatically look for a wpad DNS entry on the domain they are authenticated to. So for instance, if your fully qualified computer name was computer.branch.london.company.com, your system would search for wpad.branch.london.company.com. If it doesn’t find the entry, it will drop a level and search for wpad.london.company.com, and then wpad.company.com. It will never search outside of the highest level search domain on your network.

To create our DNS entry, we need to do the following.

  1. Open DNS Management Console from Start > Programs > Administrative Tools >DNS Management.
  2. Drill into the look-up zone you wish to create the entry, and click New Host (A).
  3. In the “Name” box, type “wpad” in lower case without the quotes.
  4. In the “Address” box type the ip address of your web server.
  5. Save the entry and we are done in DNS.

Now we will move onto DHCP. Although you technically only need one form of auto-discovery, in the interest of security we will setup both DNS and DHCP. You could also setup WINS, but we don’t use wins in our production environment, so the configuration of WINS was beyond the scope of this exercise.

To start with, we need to configure the server to allow the option.

  1. Open DHCP Management from Start > Programs > Administrative Tools.
  2. In the left-hand pane, Right-Click the DHCP server and click Set Predefined Options.
  3. Click Add.
  4. In the “Name” field type WPAD.
  5. In the “Code” field type 252.
  6. In the “Data Type” field, select String, followed by OK.
  7. In the “String” field, type the URL of your PAC file. It should look something like this http://192.168.1.10:80/wpad.dat.
  8. Right-Click Server Options and click Configure Options.
  9. Ensure that option 252 is available.

Now we configure each DHCP Scope that we want the wpad file to be sent to.

  1. In DHCP Management, Right-Click on Scope Options, and select Configure Options.
  2. Click on Advanced, and then from Vendor Class select Standard Options.
  3. From Available Options, select 252 Proxy AutoDiscovery and click OK.

That should be out DHCP configuration complete.

Now we need to configure IIS to process PHP scripts. I cheated slightly with the installation of PHP, and used microsofts new Web Application Installation service to install PHP, which I found here http://www.microsoft.com/web/php/.

In your document root (C:inetpubwwwroot by default), create a new file called wpad.dat. By default, the webserver will not server the file, as it does not know what it is or what it does. We need to add a MIME type to IIS.

  1. Open Internet Information Services Management from Start > Programs > Administrative Tools.
  2. Drill down to Default Website in the left-hand pane.
  3. From the right-hand pane select MIME Types.
  4. Right Click the white space in the right-hand pane and select add MIME Type.
  5. In the “File Name Extension” box type .dat.
  6. In the “MIME Type” box, type "application/x-ns-proxy-autoconfig" without quotes.
  7. Click OK.
  8. Restart your server.

Our wpad file will now work once the client is set to “Automatically Configure Proxy Settings”. But that was not the goal of this whole excercise. In order to dynamically generate the wpad file every time it is requested, the server needs to process the file on request in PHP. To accomplish this, we need to tell IIS that .dat files are to be sent to the PHP engine we installed earlier.

  1. In Default Website, within IIS Management, Select Handler Mappings.
  2. Right-click on the white space in the right-hand pane, and select “New Module Mapping”.
  3. In “Request Path” type wpad.dat.
  4. Select “FastCGIModule” from the “Module” list.
  5. In the “Executable” field type “C:Program FilesPHPphp-cgi.exe” including the quotes.
  6. In the “Name” filed, type WPAD.
  7. Click OK.
  8. Restart IIS.

Now the wpad.dat file will be processed in php every time it is requested. We decided that we would like to hold proxy server details in a text file called settings.txt, URL Exceptions in a file called URLex.txt, and Network Exceptions in a file called netex.txt, which we placed in a folder called proxy within the document root of the website. These files will be read by PHP every time the wpad file is requested, and the wpad file will be written “on-the-fly” before it is sent to the user.

The content of the files are shown below.

192.168.0.0, 255.255.0.0, D, Internal Network.

The fields are separated by commas, and different entries are separated by lines. The Fields are , , , .

The Network, Subnet Mask, and Comment are all pretty self explanatory, but the action needs a little more explanation…. In order to add methods to both send traffic both direct, and via proxy, we needed a way to define which route the traffic should take. D stands for DIRECT, and P stands for PROXY.

The contents of urlex.txt:

http://www.example.co.uk*, P, Example Website
http://*.example2.co.uk*, D, Example Services
http://*.example.local*, D, Local Domain

This file is formatted as , , . The URL pattern can contain *’s as a wild card character.

The Contents of settings.txt:

0, PROXY proxy.domain.com:8080, DIRECT, PROXY proxy.domain.com:8080, Local Config

,

, , , . The P and D Action Destinations correspond to the options in the exceptions files. Default destination are where we send requests that do not match anything in the exceptions files.

Now, for the content of our wpad.dat file. Providing you have followed this post to the letter, and I haven’t missed anything out, your wpad system should work fine after this file has been populated.

$urlfile = "proxy/urlex.txt";
$netfile = "proxy/netex.txt";
$setfile = "proxy/settings.txt";
$sett = fopen($setfile, 'r');
$settings = explode(", ", fgets($sett));
fclose($sett);
$actions = array();
$actions['D'] = $settings[2];
$actions['P'] = $settings[1];
if($settings[0] == '1') { $function .= ' alert("Debug Mode Enabled!"); '; }
$function = ' function FindProxyForURL(url, host) { ';
if($settings[0] == '1') { $function .= ' alert("Reading URL Exceptions List"); '; }
$fh = fopen($urlfile, 'r');
$ln = 0;
while ($line= fgets ($fh)) {
++$ln;
$split_point =', ';
$split_string = explode($split_point, $line);
$function .= ' if (shExpMatch(url, "'.$split_string[0].'")) {';
if($settings[0] == '1') { $function .= ' alert("URL Match Found: '.$split_string[0].'"); '; }
$function .= ' return "'.$actions[$split_string[1]].'"; } ';
}
fclose($fh);
$fh = fopen($netfile, 'r');
$ln = 0;
while ($line = fgets ($fh)) {
++$ln;
$split_point =', ';
$split_string = explode($split_point, $line);
$function .= ' if (isInNet(host, "'.$split_string[0].'", "'.$split_string[1].'")) {';
if($settings[0] == '1') { $function .= ' alert("Network Match Found: '.$split_string[0].'"); '; }
$function .= 'return "'.$actions[$split_string[2]].'"; } ';
}
fclose($fh);
if($settings[0] == '1') { $function .= ' alert("No Match Found - Drop to Default Path...."); '; }
$function .= 'return "'.$settings[3].'"; ';
$function .= ' }';
echo $function;
?>

Basically this script will read the files and “echo” a bunch of compiled text that the web browser will interpret as JavaScript. Here is the output text of the script. It may not be as neat as a conventional PAC file, but your browser will still know what to do with it.

function FindProxyForURL(url, host) { if (shExpMatch(url, “http://www.example.co.uk*”)) { return “PROXY proxy.domain.com:8080”; } if (shExpMatch(url, “http://*.example2.co.uk*”)) { return “DIRECT”; } if (shExpMatch(url, “http://*.example.local*”)) { return “DIRECT”; } if (isInNet(host, “192.168.0.0”, “255.255.0.0”)) {return “DIRECT”; } return “PROXY proxy.domain.com:8080”; }

I recommend a server reboot, followed by a client reboot before you test this system.

I hope you all find this script useful, I know there isn’t a great deal of information available online on this subject.

This script could also easily be expanded to use a database as the data source instead of text file. All it would take is a little bit of PHP and MySQL know how. Who Knows? I might even post something a bit more dynamic one day when I’m bored….

Please feel free to leave any comments, feedback, help requests or additional information in the comments, and I will do my best to help you out.