设为首页 收藏本站
查看: 405|回复: 0

[经验分享] A XSS Vulnerability in Almost Every PHP Form I’ve Ever Written

[复制链接]
发表于 2017-4-11 07:36:41 | 显示全部楼层 |阅读模式
  I've spent a lot of time over the past few months writing an enterprise application in PHP. Despite what some people may say, I believe that PHP is as secure or insecure as the developer who is writing the code. Anyway, I'm at the point in my development lifecycle where I decided that it was ready to run an application vulnerability scanner against it. What I found was interesting and I think it's worth sharing with you all.
  Let me preface this by saying that I'm the guy who gives the training to our developers on the OWASP Top 10, writing secure code, etc. I'd like to think that I have a pretty good handle on programming best practices, input validation, and HTML encoding. I built all kinds of validation into this application and thought that the vulnerability scan would come up empty. For the most part I was right, but there was one vulnerability, one flaw in particular, that found it's way into every form in my application. In fact, I realized that I've made this exact same mistake in almost every PHP form that I've ever written. Talk about a humbling experience.
  So here's what happened. I created a simple page with a form where the results of that form are submitted back to the page itself for processing. Let's assume it looks something like this:

<html>
<body>
<?php
if (isset($_REQUEST['submitted']) && $_REQUEST['submitted'] == '1') {
echo "Form submitted!";
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>

  It looks fairly straightforward, right? The problem has to do with that $_SERVER['PHP_SELF'] variable. The intent here is that PHP will display the path and name of the current page so that the form knows to submit back to the same page. The problem is that $_SERVER['PHP_SELF'] can actually be manipulated by the user. Let's say as the user I change the URL from http://www.webadminblog.com/example.php to http://www.webadminblog.com/example.php"><script>alert('xss');</script>. This will end the form action part of the code and inject a javascript alert into the page. This is the very definition of cross site scripting. I can't believe that with as long as I've been writing in PHP and as long as I've been studying application security, I've never realized this. Fortunately, there are a couple of different ways to fix this. First, you could use the HTML entities or HTML special character functions to sanitize the user input like this:
  htmlentities($_SERVER['PHP_SELF]);
  htmlspecialchars($_SERVER['PHP_SELF]);
  This fix would still allow the user to manipulate the URL, and thus, what is displayed on the page, but it would render the javascript invalid. The second way to fix this is to use the script name variable instead like this:
  $_SERVER['SCRIPT_NAME'];
  This fix would just echo the full path and filename of the current file. Yes, there are other ways to fix this. Yes, my code example above for the XSS exploit doesn't do anything other than display a javascript alert. I just wanted to draw attention to this issue because if it's found it's way into my code, then perhaps it's found it's way into yours as well. Happy coding!
  A predominant PHP developer (whose name I didn't get permission to drop, so I won't, but many of you know who I mean) has been doing a bunch of research related to Cross Site Scripting (XSS), lately. It's really opened opened my eyes to how much I take user input for granted.
  Don't get me wrong. I write by the "never trust users" mantra. The issue, in this case, is something abusable that completely slipped under my radar.
  Most developers worth their paycheque, I'm sure, know the common rules of "never trust the user", such as "escape all user-supplied data on output," "always validate user input," and "don't rely on something not in your control to do so (ie. Javascript cannot be trusted)." "Don't output unescaped input" goes without saying, in most cases. Only a fool would "echo $_GET['param'];" (and we're all foolish sometimes, aren't we?).
  The problem that was demonstrated to me exploited something I considered to be safe. The filename portion of request URI. Now I know just how wrong I was.
  Consider this: you build a simple script; let's call it simple.php but that doesn't really matter. simple.php looks something like this:

<html>
<body>
<?php
  if (isset($_REQUEST['submitted']) && $_REQUEST['submitted'] == '1') {
    echo "Form submitted!";
  }
  ?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>
  Alright. Let's put this script at: http://example.com/tests/simple.php. On a properly-configured web server, you would expect the script to always render to this, on request:

<html>
<body>
<form action="/tests/simple.php">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>
  Right? No.
  What I forgot about, as I suspect some of you have, too (or maybe I'm the only loser who didn't think of this (-; ), is that $_SERVER['PHP_SELF'] can be manipulated by the user.
  How's that? If I put a script at /simple/test.php, $_SERVER['PHP_SELF'] should always be "/simple/test.php", right?
  Wrong, again.
  See, there's a feature of Apache (I think it's Apache, anyway) that you may have used for things like short URLs, or to optimize your query-string-heavy website to make it search-engine friendly. $_SERVER['PATH_INFO']-based URLs.
  Quickly, this is when scripts are able to receive data in the GET string, but before the question mark that separates the file name from the parameters. In a URL like http://www.example.com/download.php/path/to/file, download.php would be
  executed, and /path/to/file would (usually, depending on config) be available to the script via $_SERVER['PATH_INFO'].
  The quirk is that $_SERVER['PHP_SELF'] contains this extra data, opening up the door to potential attack. Even something as simple the code above is vulnerable to such exploits.
  Let's look at our simple.php script, again, but requested in a slightly different manner: http://example.com/tests/simple.php/extra_data_here
  It would still "work"--the output, in this case, would be:

<html>
<body>
<form action="/tests/simple.php/extra_data_here">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>
  I hope that the problem is now obvious. Consider: http://example.com/tests/simple.php/%22%3E%3Cscript%3Ealert('xss')%3C/script%3E%3Cfoo
  The output suddenly becomes very alarming:

<html>
<body>
<form action="/tests/simple.php/"><script>alert('xss')</script><foo">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>
  If you ignore the obviously-incorrect <foo"> tag, you'll see what's happening. The would-be attacker has successfully exploited a critical (if you consider XSS critical) flaw in your logic, and, by getting a user to click the link (even through a redirect script), he has executed the Javascript of his choice on your user's client (obviously, this requires the user to have Javascript enabled). My alert() example is non-malicious, but it's trivial to write similarly-invoked Javascript that changes the action of a form, or usurps cookies (and submits them in a hidden iframe, or through an image tag's URL, to a server that records this personal data).
  The solution should also be obvious. Convert the user-supplied data to entities. The code becomes:

<html>
<body>
<?php
  if (isset($_REQUEST['submitted']) && $_REQUEST['submitted'] == '1') {
    echo "Form submitted!";
  }
  ?>
<form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>
  And an attack, as above, would be rendered:

<html>
<body>
<form action="/tests/simple.php/&amp;quot;&amp;gt;&amp;lt;script&amp;gt;alert('xss')&amp;lt;/script&amp;gt;&amp;lt;foo">
<input type="hidden" name="submitted" value="1" />
<input type="submit" value="Submit!" />
</form>
</body>
</html>
  This still violates the assumption that the script name and path are the only data in $_SERVER['PHP_SELF'], but the payload has been neutralized.
  Needless to say, I felt silly for not thinking of such a simple exploit, earlier. As the aforementioned PHP developer said, at the time (to paraphrase): if guys who consider themselves experts in PHP development don't notice these things, there's little hope for the unwashed masses who have just written their first 'echo "hello world!/n";'. He's working on a generic user-input filtering mechanism that can be applied globally to all user input. Hopefully we'll see it in PECL, soon. Don't forget about the other data in $_SERVER, either..
  ... ...
  Upon experimenting with this exploit on my own server (and watching the raw data in my _SUPERGLOBALS, conveniently, via phpinfo()), I noticed something very interesting that reminded me that even though trusting this data was a stupid mistake on my part, I'm not the only one to do so. A fun (and by fun, I mean nauseating) little game to play: create a file called "info.php" (or whatever name you like). In it, place only "<php phpinfo(); ?>". Now request it like this: http://your-server/path/to/info.php/%22%3E%3Cimg%20src=http://www.perl.com/images/75-logo.jpg%3E%3Cblah
  Nice huh? A little less nauseating: it's fixed in CVS.



<!-- comments -->

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-363101-1-1.html 上篇帖子: php过滤广告内容(兼职,QQ号,淘宝兼职,网址) 下篇帖子: Blumentals 三剑客 Rapid PHP、Rapid CSS、HTMLPad 2010 汉化发布
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表