robbat2: (ubercoder)

One of my past consulting customers, came to me with a problem. He'd been relatively diligent in upgrading his servers since last I spoke (it had been some years), and now the admin panel on one of his client's very old PHP websites was no longer working.

I knew the code had some roots back to at least PHP3, at the file headers I'd previously seen had copyright dates back to 1999. Little did I know, I was in for a treat today.

When last I visited this codebase, due to it's terrible nature with hundreds of globals, I had to put some hacks in for PHP 5.4, since register_globals were no longer an option. The hack for this is quite simple:

foreach($_POST as $__k => $__v) { $$__k = $__v; }
foreach($_GET as $__k => $__v) { $$__k = $__v; }

Well it seems since the last upgrade, they had also changed the register_long_arrays setting by demand of another project, and the login on the old site was broken. Quite simple this, just need to s/HTTP_SERVER_VARS/_SERVER/ (and similarly for POST/GET/COOKIE depending on your site).

Almost all was well now, except that the next complain was file uploads didn't work for several forms. I naively duplicated the _POST/_GET block above to $_FILES. No luck. Thus, my memory not remembering how file uploads used to work in early PHP, I set out to fix this.

I picked a good one to test with, and noticed that it used some of the very old PHP variables for file uploads (again globals). These files dated back to 1997 and PHP/FI!. The initial solution was to map $_FILES[x]['tmp_name'] to $x, and the rest of $_FILES[x][y] to $x_y. Great it seems to work now.

Except... one file upload form was still broken; it had multiple files allowed in a single form. Time for a more advanced hack:

# PHP/FI used this structure for files:
foreach($_FILES as $__k => $__v) { 
  if(!is_array($__v['tmp_name'])) {
    $s = $__k;
    $$s = $__v['tmp_name'];
    $keys = array('name','size','type');
    foreach($keys as $k) {
      $s = $__k.'_'.$k;
      $$s = $__v[$k];
  } else {
    for($i = 0; $i <= count($__v['tmp_name']); $i++) {
      if(defined($__v['tmp_name']) && defined($__v['tmp_name'][$i])) {
        $s = $__k.'['.$i.']';
        $$s = $__v['tmp_name'][$i];
        $keys = array('name','size','type');
        foreach($keys as $k) {
          $s = $__k.'_'.$k.'['.$i.']';
          $$s = $__v[$k][$i];

Thus I solved the problem, and had to relearn back how it used to be done with PHP/FI.

robbat2: (Default)

Recently I've been digging around in the annuls of Gentoo history, working on what will hopefully be the final tree-signing proposal before it actually becomes a full reality. During the midst of this, Stuart came up to me in #gentoo-dev:

<Stuart> robbat2: btw, did you see this week's LWN?
<Stuart> robbat2: the one of using Google Code to find PHP apps that are vulnerable to allow_url_fopen attacks
<Stuart> robbat2: you were right, all those years ago. just wanted to tell you that.

I wasn't the first to come up with the idea, the BSD ports folk were talking about it around the same time we were in mid-July 2003, and I was aware of their discussion, but I believe that Gentoo was the first Linux distribution to make this jump in turning it off. I took a lot of flak at the time for breaking many PHP applications in the name of security, but history has now shown that allow_url_fopen is a very common PHP exploit, and with the advent of Google Code, many sites may now considerably more vulnerable - and all of this could have been mostly avoided a long time ago if PHP had just included a taint mode from the start...

I hadn't read LWN yet, it's only been out a few hours, yet here the article is: "Remote file inclusion vulnerabilities". Stuart also posted a link back into the murky depths of the Gentoo CVS, with a commit I made in July 2003, that turned off allow_url_fopen by default in Gentoo.

May 2017

141516171819 20


RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags