AT&T U-Verse VAP2500: The Passwords, They Do Nothing!

You may have heard by now that AT&T has a “wireless” cable box offering for its U-Verse customers, which is pretty sweet. But what I wasn’t aware of is that, in order for this cable box to connect to your network, you need to put their special wireless access point on your network as well. Basically, this means that a device you have no control over is now sitting there on your network waiting for wifi connections. Never one to put an unknown like that in my environment, I decided to dig a little deeper, and what I found did not exactly inspire confidence.

The “special wireless access point” in question here is an Arris VAP2500. Arris apparently bought this technology as part of their Motorola Mobility acquisition a while back as it still says Motorola all over the one I have. The VAP2500 uses WPS to pair with the cable box, which is less than ideal, but at least the WPS isn’t constantly on; it’s enabled for a brief period by pressing a button on the front of the device. Also, it uses WPA2 for its wifi security with a long, seemingly arbitrary key, so that’s a plus. So far so good! On to the running services.

Some initial port scanning revealed that there was a web service and a SOAP service running, but that’s about it. Let’s just focus on the web side for now. Browsing to the web portal showed a typical login screen. Since we don’t know the credentials, this would seem to be a pretty big stumbling block. Every page you visit just redirects you back to this login screen until you manage to successfully authenticate yourself.

Well, I should say, almost every page. Which leads me to the first vulnerability I found. There was a plain text file in the root of the web server named admin.conf that contained the following:

1
2
ATTadmin,1b12957d189cde9cda68e1587c6cfbdd,0
super,71a5ea180dcd392aabe93f11237ba8a9,0

“That’s strange,” I thought. “Those look suspiciously like usernames and password hashes. Surely they wouldn’t put sensitive information like that in an unprotected, plain text file in the root of the web server, right?” Alas, that is exactly what they did. Every user account’s credentials are stored in that file, presumably for easy use in the verification process.

But before you go churning away on those hashes with your fancy, mineral-oil-soaked GPUs, let’s pull out the firmware and take a peak at the source code for the authentication algorithm. You know, just for the sake of curiosity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
if (isset($_POST['user']) && isset($_POST['pwd']))
{
  $user=$_POST['user'];
  $pwd=md5(trim($_POST['pwd']));
  $flag=0;
  $file_path = trim(shell_exec("call_qcsapi get_file_path security"));
  $file_path = $file_path."admin.conf";
  $fp = fopen($file_path, 'r');
  while(!feof($fp))
  {       
    $buffer = stream_get_line($fp, 100, "\n");
    $arraylist=split(',',$buffer);
    if($arraylist[0]==$user && $arraylist[1]==$pwd)
    {
      $flag=1;
      break;
    }
  }
  fclose($fp);
  if ($flag==1)
  {
    echo "<script language='javascript'>createCookie(\"p\", \"".md5($user)."\", 2);</script>";
    echo "<script language='javascript'>location.href='status_device.php'</script>";
  } 
  else
    {echo "<script language='javascript'>alert(\"Login Failed\")</script>";}
}
?>

OK, so they take the user and pwd POST params and compare them with the values from the admin.conf file as we suspected. If they match, the cookie “p” gets set, and we get redirected inside. However, there seems to be something off about the value they’re using for that cookie. Go look at it again, really let the implications of what they’re doing here sink in, and when you get back, we’ll talk about the second vulnerabillity.

Yup, that’s right. They’re using the username as the cookie. That’s it. The password doesn’t even come into play here. If you know a username, you have everything you need. Just set p=[md5 hash of username] in your cookie header, and you’re in. More than that, if an account got compromised, changing its password would do absolutely nothing. Checking the source code on the interior pages confirms this and also shows that adding and deleting user accounts is not going to be easy, since the default usernames are hardcoded into the source of every page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (isset($_COOKIE['p']))
{  
  // Start Moto Customized Passwd
  if($_COOKIE['p']==md5("ATTadmin"))
  {$priority=0;}
  else
  if($_COOKIE['p']==md5("super"))
  {$priority=0;}
  // End Moto Customized Passwd
  else
  {
    echo "<script language='javascript'>location.href='login.php'</script>";
    return;
  } 
}
else
{
  echo "<script language='javascript'>location.href='login.php'</script>";
  return;
}

So, now that we’re in the web management interface, what can we do? Pretty much the same things you can do from any access point’s web interface - change wifi and security settings, manage dhcp, examine logs, upgrade firmware, etc. All that’s fine and good, but for real, what can we do? Well, it’s a PHP web app…so…how about some command injection?

There were multiple possibilities for discussing the third vulnerability here, but the most straightforward example was in the page tools_command.php which is basically designed specifically to feed commands directly to the shell of the device. Doesn’t get much easier than that. This page takes two POST parameters: cmb_header, which has a default value of “call_qcsapi”, and txt_command, which is supposed to be the command string that you want to feed to the “call_qcsapi” binary. These two values are then concatenated together and used as the argument for a call to PHP’s shell_exec() method. The problem is that there is no verification on either of these params, so you can do a POST request with something akin to “cmb_header=&txt_command=whoami” in the data section, and the server would happily execute “whoami” from the device’s shell and send you back the response (which in this case was “root”, just so you know).

And there you have it. Putting all of this together, you grab a username from the admin.conf file, set a cookie “p” to an md5 hash of that username, and use that cookie in a POST request to inject commands that then get executed on the shell of the device as the root user. Just like that you go from having absolutely no access to having complete control over the most fundamental levels of the device.

I, of course, did the “responsible” thing and disclosed these issues to Arris through ZDI. They addressed the issues I told them about via a firmware update that got pushed out to devices this month, so they are slightly less insecure now. More importantly, now that those updates have finally been released, I can stop holding my tongue about all this awesomeness and share it with you nice folks. And I can start working on the next round of slightly higher hanging fruit. For anyone interested, here’s a ruby script I wrote that makes use of all these vulns to modify the root password and enable telnet on vulnerable VAP2500 devices [Use at your own risk! I am not responsible for whatever you end up screwing up!]: vap2500_root.rb

Until next time!

The views and opinions expressed herein do not necessarily represent those of my employer...You know the drill...