AppSec Blog

Spot the Vuln - Proportion - Cross Site Scripting


Affected Software: Lazyest-Gallery

Fixed in Version: 0.9

Issue Type: Cross Site Scripting (XSS)

Original Code: Found Here


For most security issues, I give the developer the benefit of the doubt. It's tough to keep track of all the corner cases and security nuances. For this diff however, there is no excuse.

First, let's cover what the patch fixes. On line 18, the developer was taking a tainted value passed via query string parameter and using that value to build HTML markup. This is XSS in its most classic form. Also, on line 58 the same tainted input is used to build the SRC attribute for an image tag, also resulting in XSS. The developer chose to encode both of these tainted values before using them in the HTML output.

Now, let's talk about the problems with this patch. First, the tainted value used to build the SRC attribute for an image tag needs additional validation. SRC attributes are tricky as they usually cause the browser to issue a request. Escaping the tainted SRC value only prevents the attacker from breaking out of the attribute and injecting their own HTML. Escaping doesn't prevent the attacker from passing a well formed URI like javascript:javascript-payload-here. I can let the developer slide on this one? chalk it up as a lesson on corner cases. Now, if you look at the patched line, you'll see that the ALT attribute for the same image tag also contains a XSS vulnerability. Yes, the developer missed a XSS vulnerability that is less than 5 characters away from a fixed XSS vulnerability. This also shows that the developer never tested the patch. The tainted query string parameter is the same for all the vulnerable sections. If the developer tried to test this patch, they would have discovered they were still exposed?

Developers Solution

<?php // Don't remove this lines: require_once('../../../wp-blog-header.php'); global $lg_gallery; ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ""> <html xmlns=""> <head> <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" /> <meta name="generator" content="WordPress <?php bloginfo('version'); ?>" /> -<title><?php echo $_GET['image'] ?></title> +<title><?php echo esc_html($_GET['image']) ?></title> <style type="text/css"> body { text-align:center; margin:0; padding:0; } img { border:none; } </style> <script type="text/javascript"> function WinWidth(){ if (window.innerWidth!=window.undefined) return window.innerWidth; if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth; if (document.body) return document.body.clientWidth; return window.undefined; } function WinHeight() { if (window.innerHeight!=window.undefined) return window.innerHeight; if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight; if (document.body) return document.body.clientHeight; return window.undefined; } function FitPic() { iWidth=WinWidth(); iHeight=WinHeight(); iWidth = document.images[0].width - iWidth; iHeight = document.images[0].height - iHeight; window.resizeBy((iWidth), (iHeight)) self.focus(); } </script> </head> <body onload="FitPic()"> <a href="javascript:self.close()" title="<?php _e('Click to close', $lg_text_domain); ?>"> -<img src="<?php echo str_replace(" ", "%20", $lg_gallery->address.$_GET['folder'].$_GET['image']); ?>" alt="<?php echo $_GET['image']; ?>" /> +<img src="<?php echo str_replace(" ", "%20", $lg_gallery->address.esc_attr($_GET['folder']).esc_attr($_GET['image'])); ?>" alt="<?php echo $_GET['image']; ?>" /> </a> </body> </html> <?php ?>

Post a Comment


* Indicates a required field.