首先通过php解密获得源代码,里面主要有以下文件:
index.php
1 |
|
该界面完成的是用户登录验证功能。进入管理界面的条件是
1 | $_POST['private'] === $_SESSION["pri"] |
$_SESSION[‘pri’]是怎么来的呢?由auth_code(10, false)函数定义。该函数主要实现的功能就是生成一定长度的随机数。关键函数用的是mt_srand和mt_rand
函数简介:
mt_srand():播种 Mersenne Twister 随机数生成器。
mt_rand():使用 Mersenne Twister 算法返回随机整数。语法:mt_rand(min,max);
例如:
1 |
|
rand()产生随机数时,如果用srand(seed)播下种子之后,一旦种子相同,产生的随机数将是相同的。
伪随机数问题
mt_rand() 函数是一个伪随机发生器,即如果知道随机数种子是可以预测的。
1 | $seed = 12345; |
linux 64 位系统中,rand() 和 mt_rand() 产生的最大随机数都是2147483647,正好是 2^31-1,也就是说随机播种的种子也是在这个范围中的,0 – 2147483647 的这个范围是可以爆破的。
但是用 php 爆破比较慢,有一个 C 的版本,可以根据随机数,爆破出种子 (工具:php_mt_seed。)
在 php > 4.2.0 的版本中,不再需要用 srand() 或 mt_srand() 函数给随机数发生器播种,现已由 PHP 自动完成。php 中产生一系列的随机数时,只进行了一次播种,而不是每次调用 mt_rand() 都进行播种。
回到题目中,题目要求anth_code函数生成的16位随机字符串和第二次生成的10位随机字符串一致才会进入后台。根据上面函数漏洞,每个10位的随机数和16位的随机数是一一对应的(并不随机),因此写脚本爆破。
1 |
|
结果类似:
进入admin.php
admin.php
1 |
|
主要目的是令json_decode($auth) == $auth_code
可用弱类型绕过,auth=true
进入file.php
file.php
1 |
|
首先GET提交id参数,且参数里必须有‘jpg’
然后对提交的参数进行正则过滤
1 | "/^php:\/\/.*resource=([^|]*)/i" |
改正则表达式的含义:
php:// + 任意字符或空 + resource + 任意字符
目的就是防止通过伪协议读取flag.php文件。
语法 | 含义 | |
---|---|---|
^ | 开头或取反 | |
. | 匹配除换行符 \n 之外的任何单字符 | |
* | 匹配前面的子表达式零次或多次 | |
() | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用 | |
[] | 标记一个中括号表达式的开始 | |
\ | 指明两项之间的一个选择 |
括号能提取字符串,如(com|cn|net)就可以限制,只能是com或cn或net。
方括号是单个匹配,如[abc]他限制的不是abc连续出现,而是只能是其中一个,这样写那么规则就是找到这个位置时只能是a或是b或是c;
大括号{}: 大括号的用法很简单,就是匹配次数,它需要和其他有意义的正则表达式一起使用。
\^两个含义,只要是^这个字符是在中括号”[]”中被使用的话就是表示字符类的否定,如果不是的话就是表示限定开头。这里说的是直接在”[]”中使用,不包括嵌套使用。
preg_match函数
1 | preg_match ( $pattern , $subject , $matches ) |
搜索subject与pattern给定的正则表达式的一个匹配.
$matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。意思是$matches[1]匹配第一个括号里的匹配的内容
如提交:
1 | http://127.0.0.1/test.php?id=php://filter/read=convert.base64-encode/resource=test.php |
打印$matches变量:
1 | array (size=2) |
(正则看起来没啥用,伪协议主要是迎合正则表达式要求的格式,必须要匹配到,使$id有值,所以jpg的位置不重要)
payload:
1 | id=php://filter/jpgread=convert.base64-encode/resource=test.php |