您的位置:首页 > 运维架构 > Shell

PHPMYWIND4.6.6前台Refer头注入+后台另类getshell分析

2017-08-16 16:14 1126 查看
下载链接
https://share.weiyun.com/b060b59eaa564d729a9347a580b7e4f2
Refer头注入

全局过滤函数如下

function _RunMagicQuotes(&$svar)
{
//PHP5.4已经将此函数移除
if(@!get_magic_quotes_gpc())
{
if(is_array($svar))
{
foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
}
else
{
if(strlen($svar)>0 &&
preg_match('#^(cfg_|GLOBALS|_GET|_POST|_SESSION|_COOKIE)#',$svar))
{
exit('不允许请求的变量值!');
}

$svar = addslashes($svar);
}
}
return $svar;
}


在前台注册用户并且添加收藏的地方抓包分析

else if($a == 'savefavorite')
{
//die("test");
$aid   = isset($aid)   ? $aid   : '';
$molds = isset($molds) ? $molds : '';
$link  = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';

if($aid == '' or $molds == '' or $link == '')
{
header('location:?c=default');
exit();
}

$r = $dosql->GetOne("SELECT `id`,`expval`,`integral` FROM `#@__member` WHERE `username`='$c_uname'");
$uid   = $r['id'];
$uname = $c_uname;
$time  = time();
$ip    = GetIP();

$r2 = $dosql->GetOne("SELECT `aid`,`molds` FROM `#@__userfavorite` WHERE `aid`=$aid and `molds`=$molds");
if(!is_array($r2))
{
$dosql->ExecNoneQuery("INSERT INTO `#@__userfavorite` (aid,molds,uid,uname,link,time,ip,isshow) VALUES ('$aid','$molds','$uid','$uname','$link','$time','$ip','1')");
//收藏一条增加1经验值2积分
$dosql->ExecNoneQuery("UPDATE `#@__member` SET expval='".($r['expval'] + 1)."', integral='".($r['integral'] + 2)."' WHERE `username`='$c_uname'");
echo '1';
exit();
}
else
{
echo '2';
exit();
}
}


GetIp()函数不能用

1     function CheckSql($sql, $querytype='select')
2     {
3
4         $clean   = '';
5         $error   = '';
6         $pos     = -1;
7         $old_pos = 0;
8
9
10         //如果是普通查询语句,直接过滤一些特殊语法
11         if($querytype == 'select')
12         {
13             if(preg_match('/[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}/', $sql))
14             {
15                 $this->DisplayError("$sql||SelectBreak",1);
16             }
17         }
18
19         //完整的SQL检查
20         while(true)
21         {
22             $pos = strpos($sql, '\'', $pos + 1);
23             if($pos === false)
24             {
25                 break;
26             }
27             $clean .= substr($sql, $old_pos, $pos - $old_pos);
28
29             while(true)
30             {
31                 $pos1 = strpos($sql, '\'', $pos + 1);
32                 $pos2 = strpos($sql, '\\', $pos + 1);
33                 if($pos1 === false)
34                 {
35                     break;
36                 }
37                 else if($pos2 == false || $pos2 > $pos1)
38                 {
39                     $pos = $pos1;
40                     break;
41                 }
42                 $pos = $pos2 + 1;
43             }
44
45             $clean .= '$s$';
46             $old_pos = $pos + 1;
47         }
48
49         $clean .= substr($sql, $old_pos);
50         $clean  = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));
51         var_dump($clean);
52
53
54         //老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它
55         if(strpos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0)
56         {
57             $fail  = true;
58             $error = 'union detect';
59         }
60
61         //发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们
62         else if(strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, '#') !== false)
63         {
64             $fail  = true;
65             $error = 'comment detect';
66         }
67
68         //这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
69         else if(strpos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
70         {
71             $fail  = true;
72             $error = 'slown down detect';
73         }
74         else if(strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
75         {
76             $fail  = true;
77             $error = 'slown down detect';
78         }
79         else if(strpos($clean, 'load_file') !== false && preg_match('~(^|[^a-z])load_file($|[^[a-z])~s', $clean) != 0)
80         {
81             $fail  = true;
82             $error = 'file fun detect';
83         }
84         else if(strpos($clean, 'into outfile') !== false && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~s', $clean) != 0)
85         {
86             $fail  = true;
87             $error = 'file fun detect';
88         }
89
90         //老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息
91         else if(preg_match('~\([^)]*?select~s', $clean) != 0)
92         {
93             $fail  = true;
94             $error = 'sub select detect';
95         }
96
97         if(!empty($fail))
98         {
99             $this->DisplayError("$sql,$error",1);
100         }
101         else
102         {
103             return $sql;
104         }
105     }


View Code
这是80sec的防sql注入函数

通过跟踪这段代码发现,它有个特征就是会将两个单引号之间的内容用$s$替换,例如’select’会被替换为$s$,这里用两个@`'`包含敏感字,这样$clean变量中就不会出现敏感字,从而绕过CheckSql()函数检测

这里可以设置title为如下代码,一方面绕过ids防注入代码检测,另一方面加一个#注释掉后面的代码,但是还要做一下变形,就是这个char(@`'`)了。因为#@__feedback的所有字段都被设置为NOT NULL,而@`'`是一个变量,默认为NULL,直接插入@`'`的话会报错,所以需要以char(@`'`)的方法转换一下。



后台另类getshell

在后台网站配置处 admin/web_config.php





理论上说有全局过滤应该就不能闭合拿shell了

但是仔细读一下他的流程

先把东西存到数据库- 然后在从数据库中都出来构造字符串写进文件

if($action == 'update')
{
foreach($_POST as $k=>$v)
{
//统计代码转义
$v = _RunMagicQuotes($v);

if(!$dosql->ExecNoneQuery("UPDATE `#@__webconfig` SET `varvalue`='$v' WHERE varname='$k'"))
{
ShowMsg('更新变量失败,可能有非法字符!', 'web_config.php');
exit();
}
}

WriteConfig();

ShowMsg('成功保存变量并更新配置文件!', 'web_config.php');
exit();
}


更新文件的函数

1 function WriteConfig()
2 {
3     global $dosql, $config_cache;
4
5     //die($config_cache);
6
7     $str = '<?php    if(!defined(\'IN_PHPMYWIND\')) exit(\'Request Error!\');'."\r\n\r\n";
8     $dosql->Execute("SELECT `varname`,`vartype`,`varvalue`,`vargroup` FROM `#@__webconfig` ORDER BY orderid ASC");
9     while($row = $dosql->GetArray())
10     {
11         //强制去掉 '
12        //强制去掉最后一位 /
13         $vartmp = str_replace("'",'',$row['varvalue']);
14
15         if(substr($vartmp, -1) == '\\')
16         {
17             $vartmp = substr($vartmp,1,-1);
18         }
19
20
21         if($row['vartype'] == 'number')
22         {
23             if($row['varvalue'] == '')
24             {
25                 $vartmp = 0;
26             }
27
28             $str .= "\${$row['varname']} = ".$vartmp.";\r\n";
29         }
30         else
31         {
32             $str .= "\${$row['varname']} = '".$vartmp."';\r\n";
33         }
34     }
35     $str .= '?>';
36     //die($str);
37
38     if(!Writef($config_cache,$str))
39     {
40         ShowMsg("变量成功保存,但由于 config.cache.php 无法写入,因此不能更新配置!", 'web_config.php');
41         exit();
42     }
43
44     RewriteURL();
45 }


上述代码第13行

$vartmp = str_replace("'",'',$row['varvalue']);


有多少单引号也给过滤了

但是下面一个操作

//强制去掉最后一位


有这样的操作

如果我写两个\\\进去 从数据库出来的时候 还是三个\ 但是

15         if(substr($vartmp, -1) == '\\')找他的最后一数是不是\
16         {
17             $vartmp = substr($vartmp,1,-1);
         这里的操作是让变量登入字符串从下标为1开始一直到从后面数第二个的
         三个\\\就是 下标1 是\ 倒数第二个跟他一样的

18         }


经过上面的操作就只剩下一个\

意思就是



上面的单引号被转移 就跟下面连起来了

再接着/*多行注释就起作用了



很老的一个洞了 还是很值的学习的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: