Supesite 各种注入组合。

2014-11-29 13:36:05 16 7283 3
小菜刚来t00ls   啥权限都没。。 发个帖子挣点权限。。
其他板块没啥权限 发这来了。

已经wooyun过了 不过supesite 早就停止维护了 也就没补丁。

select update insert delete && 二次注入。

_______________________________________________________________________________

0x01 update注入 可提升自己为管理

在index.php中
if($_SGET['action'] != 'index') {

        if(empty($channels['menus'][$_SGET['action']]['upnameid']) && $channels['menus'][$_SGET['action']]['upnameid'] != 'news') {

                $scriptfile = S_ROOT.'./'.$_SGET['action'].'.php';

        } else {

                $scriptfile = S_ROOT.'./news.php';

        }
这里包含文件进来。 来看看$_SGET 怎么来的。
if(empty($parsegetvar)) {

        $parsegetvar = empty($_SERVER['QUERY_STRING'])?'':$_SERVER['QUERY_STRING'];

}



if(!empty($parsegetvar)) {

        $parsegetvar = addslashes($parsegetvar); //这里转义了

        $_SGET = parseparameter(str_replace(array('-','_'), '/', $parsegetvar)); // 这里 注册了这变量

}
function parseparameter($param, $nofix=1) {

        global $_SCONFIG;



        $paramarr = array();



        if($nofix && !empty($_SCONFIG['pagepostfix'])) {

                if(strrpos($param, $_SCONFIG['pagepostfix'])) {

                        $param = substr($param, 0, strrpos($param, $_SCONFIG['pagepostfix']));

                }

        }



        $sarr = explode('/', $param);

        if(empty($sarr)) return $paramarr;

        if(is_numeric($sarr[0])) $sarr = array_merge(array('uid'), $sarr);

        if(count($sarr)%2 != 0) $sarr = array_slice($sarr, 0, -1);

        for($i=0; $i<count($sarr); $i=$i+2) {

                if(!empty($sarr[$i+1])) $paramarr[$sarr[$i]] = addslashes(str_replace(array('/', '\\'), '', rawurldecode(stripslashes($sarr[$i+1]))));

        }

        return $paramarr;

}
这里用/来切割成数组 然后就return 。

在viewcomment.php中
if(!empty($_SGET['op']) && $_SGET['op'] == 'delete') {



        $cid = empty($_SGET['cid'])?0:intval($_SGET['cid']);

        $ismodle = empty($_SGET['ismodle']) ? 0 : intval($_SGET['ismodle']);

        $table_name = ( $ismodle && !empty($_SGET['type']) ? $_SGET['type'] : 'space' ).'items';

       

        if(empty($cid)) showmessage('not_found', S_URL);

        $itemid = empty($_SGET['itemid'])?0:intval($_SGET['itemid']);

        if(empty($itemid)) showmessage('not_found', S_URL);



        $deleteflag = false;



        if(empty($_SGLOBAL['group'])) {

                showmessage('no_permission');

        }



        if($cid && $itemid && $_SGLOBAL['supe_uid']) {

                $query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacecomments').' WHERE cid=\''.$cid.'\'');

                if($comment = $_SGLOBAL['db']->fetch_array($query)) {

                        if($_SGLOBAL['group']['groupid'] == 1 || $comment['authorid'] == $_SGLOBAL['supe_uid']) {

                                $_SGLOBAL['db']->query('UPDATE '.tname($table_name).' SET replynum=replynum-1 WHERE itemid=\''.$comment['itemid'].'\'');

                                $_SGLOBAL['db']->query('DELETE FROM '.tname('spacecomments').' WHERE cid=\''.$cid.'\'');
这里 我们来看这里 UPDATE '.tname($table_name).
$ismodle = empty($_SGET['ismodle']) ? 0 : intval($_SGET['ismodle']);

        $table_name = ( $ismodle && !empty($_SGET['type']) ? $_SGET['type'] : 'space' ).'items';  //这里如果$ismodle为true的话 那么$table_name 就为$_SGET['type'] 刚好$ismodle 也是$_SGET来的  在结合index.php里的注册$_SGET 那么则table_name可控了
if($cid && $itemid && $_SGLOBAL['supe_uid']) { //这里cid 和 itemid 都是index.php中注册的$_SGET来的 $_SGLOBAL['supe_uid'] 这个只要登录了用户就行

                $query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacecomments').' WHERE cid=\''.$cid.'\'');//把评论查询出来

                if($comment = $_SGLOBAL['db']->fetch_array($query)) {

                        if($_SGLOBAL['group']['groupid'] == 1 || $comment['authorid'] == $_SGLOBAL['supe_uid'])//这里必须是管理员 或者 你查看的是自己的评论 那么我们就自己评论一个

{

                                $_SGLOBAL['db']->query('UPDATE '.tname($table_name).' SET replynum=replynum-1 WHERE itemid=\''.$comment['itemid'].'\'')//table_name可控 注入;
首先先注册一个会员

这里我们先随便找一个新闻页面 然后自己评论一下

'SELECT * FROM '.tname('spacecomments').' WHERE cid=\''.$cid.'\''

这里由于我们只能查看自己的评论

这里怎么查看自己评论的cid呢?

首先自己评论一下



然后  


点一下引用 然后抓下包 就能看到 我们发的这个评论的cid为7

然后构造一下参数 在index.php中 把viewcomments.php中包含进来



成功报错



可以看到如果查看的不是自己发的评论 就出错额。

因为是update 所以自己update自己的groupid 为1 即可直接提升自己为管理。

http://127.0.0.1/dan/supesite/space.php?uid=13

首先进一下我们的个人主页 可以看到uid为13

然后构造一下语句



没报错了 语句成功执行

这里语句成功执行后

$_SGLOBAL['db']->query('DELETE FROM '.tname('spacecomments').' WHERE cid=\''.$cid.'\'');

就会执行这delete了。 就会删除这评论了 不过权限已提升了



提升权限 成功进后台

_________________________________________________________________________________

0x02 insert注入

先来看看全局文件
if(!(get_magic_quotes_gpc())) {

        $_GET = saddslashes($_GET);

        $_POST = saddslashes($_POST);

    $_COOKIE = saddslashes($_COOKIE);

}
判断gpc 是否开启 如果没有开启 就对get post cookie 转义

这里没有对files转义。

在batch.upload.php中
elseif (!empty($_POST)) { //如果POST不为空

       

        //编辑标题

        if(!empty($_GET['editaid']) && $editaid = intval($_GET['editaid'])) {

                $editsubject = cutstr(trim(shtmlspecialchars($_POST['editsubject'])), 50);

                updatetable('attachments', array('subject'=>$editsubject), array('aid'=>$editaid));



                print <<<END

                <script language="javascript">

                var div = parent.document.getElementById("div_upload_" + $editaid);

                var pf = parent.document.getElementById("phpframe");

                pf.src = "about:blank";

                div.innerHTML = "$editsubject";

                </script>

END;

                exit;

        }

       

        //上传文件

        //上传模式

        $mode = intval(postget('mode'));

        if($mode>3) exit; //mode 直接让他为空



        $hash = trim(preg_replace("/[^a-z0-9\-\_]/i", '', trim($_POST['hash'])));

        if(strlen($hash) != 16) showresult($blang['unable_to_complete_this_craft']);//这里只判断hash的长度为不为16 没有进一步的验证 那么就让hash为1111111111111111

       

        //个数

        $filecount = 1;



        $query = $_SGLOBAL['db']->query('SELECT COUNT(*) FROM '.tname('attachments').' WHERE hash=\''.$hash.'\'');

        $count = $_SGLOBAL['db']->result($query, 0);

        $allowmax = intval($_POST['uploadallowmax']);

        if($allowmax > 0 && $count + $filecount > $allowmax) showresult($blang['the_number_has_reached_maximum']);



        //类型

        $allowtypearr = getallowtype(trim($_POST['uploadallowtype']));//取得上传的类型

       

        //空间

        $attachsize = 0;

        include_once(S_ROOT.'./function/upload.func.php');

        if(empty($mode)) { //让$mode为空即可



                //本地上传

                //检查

                $filearr = $_FILES['localfile'];//获取files

                if(empty($filearr['size']) || empty($filearr['tmp_name'])) showresult($blang['failure_to_obtain_upload_file_size']);

                $fileext = fileext($filearr['name']);//获取后缀

                if(!empty($allowtypearr)) {

                        if(empty($allowtypearr[$fileext])) showresult($blang['upload_not_allow_this_type_of_resources']." ($allowtype_ext)");

                        if($filearr['size'] > $allowtypearr[$fileext]['maxsize']) showresult($blang['file_size_exceeded_the_permissible_scope']);

                }

                //缩略图

                if(!empty($_POST['uploadthumb0']) && !empty($_SCONFIG['thumbarray'][$_POST['uploadthumb0']])) {

                        $thumbarr = $_SCONFIG['thumbarray'][$_POST['uploadthumb0']];

                } else {

                        $thumbarr = array($_POST['thumbwidth'], $_POST['thumbheight']);

                }

               

                //上传

                $newfilearr = savelocalfile($filearr, $thumbarr);

                if(empty($newfilearr['file'])) showresult($blang['uploading_files_failure']);



                //数据库

                if(empty($_POST['uploadsubject0'])) $_POST['uploadsubject0'] = cutstr(filemain($filearr['name']), 50);

//下面就带入到insert当中啦

                $insertsqlarr = array(

                        'uid' => $uid,

                        'dateline' => $_SGLOBAL['timestamp'],

                        'filename' => saddslashes($filearr['name']),//对文件的名字转义

                        'subject' => trim(shtmlspecialchars($_POST['uploadsubject0'])),

                        'attachtype' => $fileext,//这里没有对文件的后缀转义

                        'isimage' => (in_array($fileext, array('jpg','jpeg','gif','png'))?1:0),

                        'size' => $filearr['size'],

                        'filepath' => $newfilearr['file'],

                        'thumbpath' => $newfilearr['thumb'],

                        'hash' => $hash

                );

                inserttable('attachments', $insertsqlarr)//insert;
'filename' => saddslashes($filearr['name']) 在查询的时候名字被转义了

'attachtype' => $fileext 来看一下$fileext

$fileext = fileext($filearr['name']);
function fileext($filename) {

        return strtolower(trim(substr(strrchr($filename, '.'), 1)));

}
获取点以后的 没做转义 所以可以在后缀这进行注入了。



可以看到 名字被转义 后缀那成功引入单引号



这里uploadallowtype那里乱写一个

成功出数据。

_____________________________________________________________________________

0x03 delete注入

在cp.php中
$ac = empty($_GET['ac']) ? 'profile' : trim($_GET['ac']);



if(in_array($ac, array('index', 'news', 'profile', 'credit', 'models'))) {

        include_once(S_ROOT.'./source/cp_'.$ac.'.php');
包含进来

在source/cp_news.php中
if(empty($itemid)) { //这里让$itemid 不为空

               

                if(!empty($_SCONFIG['posttime']) && $_SGLOBAL['group']['groupid'] != 1) {

                        if($_SGLOBAL['timestamp'] - $_SGLOBAL['member']['lastposttime'] < $_SCONFIG['posttime']) {

                                showmessage('post_too_much');

                        }

                }

                $newsarr['uid'] = $_SGLOBAL['supe_uid'];

                $newsarr['username'] = $_SGLOBAL['supe_username'];

                $newsarr['dateline'] = $_SGLOBAL['timestamp'];

               

                if($_POST['fromtype'] == 'newspost') {

                        $newsarr['fromtype'] = 'newspost';

                        $newsarr['fromid'] = intval($_POST['id']);

                } else {

                        $newsarr['fromtype'] = 'userpost';

                }

                if(!checkperm('allowdirectpost')) {

                        $itemarr['itemid'] = inserttable('spaceitems', $newsarr, 1);

                        inserttable('spacenews', $itemarr);

                        getreward('postinfo');

                        postspacetag('add', $_POST['type'], $itemarr['itemid'], $tagarr,1);

                        $do = 'pass';

                } else {

                        $itemarr['itemid'] = inserttable('postitems', $newsarr, 1);

                        inserttable('postmessages', $itemarr);

                        postspacetag('add', $_POST['type'], $itemarr['itemid'], $tagarr,0);

                        $do = 'me';

                }



                //更新用户最新更新时间

                if($_SGLOBAL['supe_uid']) {

                        updatetable('members', array('updatetime'=>$_SGLOBAL['timestamp'], 'lastposttime'=>$_SGLOBAL['timestamp']), array('uid'=>$_SGLOBAL['supe_uid']));       

                }



        } else { //进入else

                if(empty($_SGLOBAL['supe_uid'])) showmessage('no_permission');

                updatetable('postitems', $newsarr, array('itemid'=>$itemid));

                updatetable('postmessages', $itemarr, array('itemid'=>$itemid));

                $itemid = empty($_POST['oitemid']) ? $itemid : $_POST['oitemid'];//没有intval

                postspacetag('update', $_POST['type'], $itemid, $tagarr, 0);//跟这里

        }
function postspacetag($op, $type, $itemid, $tagarr, $status) {

        global $_SGLOBAL;



        $deletetagidarr = $addtagidarr = $spacetagidarr = array();

        if($op == 'add') {        //已经存在的tag,执行加入操作

                if(!empty($tagarr['existsid'])) {

                        $addtagidarr = $tagarr['existsid'];

                        $_SGLOBAL['db']->query('UPDATE '.tname('tags').' SET spacenewsnum=spacenewsnum+1 WHERE tagid IN ('.simplode($tagarr['existsid']).')');

                }

        } else {

                $query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacetags').' WHERE itemid=\''.$itemid.'\' AND status=\''.$status.'\'');//查询

                while ($spacetag = $_SGLOBAL['db']->fetch_array($query)) {

                        if(!empty($tagarr['existsid']) && in_array($spacetag['tagid'], $tagarr['existsid'])) {

                                $spacetagidarr[] = $spacetag['tagid'];

                        } else {

                                $deletetagidarr[] = $spacetag['tagid'];//赋值

                        }

                }



                foreach ($tagarr['existsid'] as $etagid) {

                        if(!empty($spacetagidarr) && in_array($etagid, $spacetagidarr)) {

                        } else {

                                $addtagidarr[] = $etagid;

                        }

                }

                if(!empty($deletetagidarr)) {

//这里要$deletetagidarr不为空

那么也就是要让

$query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacetags').' WHERE itemid=\''.$itemid.'\' AND status=\''.$status.'\'')这个查询出来的有内容



                        $_SGLOBAL['db']->query('DELETE FROM '.tname('spacetags').' WHERE itemid='.$itemid.' AND tagid IN ('.simplode($deletetagidarr).') AND status=\''.$status.'\'');//这里delete查询 WHERE itemid='.$itemid.'  没有被单引号引住。。 并且没intval导致注入

                        $_SGLOBAL['db']->query('UPDATE '.tname('tags').' SET  spacenewsnum=spacenewsnum-1 WHERE tagid IN ('.simplode($deletetagidarr).')');

                }
这里主要是出来一个小的设计缺陷。

这里把 $query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacetags').' WHERE itemid=\''.$itemid.'\' AND status=\''.$status.'\'')
$itemid 首先带入到了查询当中 是被单引号了的。。 如果查询出来的有结果 才会带入到delete中 如果无结果 就不执行delete的语句了。
而在数据库中$itemid中 存储的是int类型 所以他这里本来是想要用户只能提交数字型才能查询出结果。
但是由于mysql的类型转换 因为他这里储存的是int类型   所以我们提交4xxxxx 跟我们提交4 是一样的

首先我们注册一个会员 然后投稿



投稿 这里tag 随便写一个


+--------+-------+------------+------+--------+

| itemid | tagid | dateline | type | status |

+--------+-------+------------+------+--------+

| 3 | 1 | 1412680532 | news | 0 |

| 4 | 2 | 1412680930 | news | 0 |


数据库里也就创建了。。

这里的itemid 在http://127.0.0.1/dan/supesite/cp.php?ac=news&op=view&itemid=4

地址中就能看到为4

然后在$query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacetags').' WHERE itemid=\''.$itemid.'\' AND status=\''.$status.'\'');

这里查询



这里查询 后面虽然跟了一些字符 提示warning 但是还是能查询出来。

$_SGLOBAL['db']->query('DELETE FROM '.tname('spacetags').' WHERE itemid='.$itemid.' AND tagid IN ('.simplode($deletetagidarr).') AND status=\''.$status.'\'');

然后就进来delete 里面没单引号 且无intval 导致注入。

投稿的时候抓包一下




成功出数据
______________________________________________________________________

0x04 select注入

batch.common.php中
$name = empty($_GET['name'])?'':trim($_GET['name']);

        $cid = empty($_GET['cid'])?0:intval($_GET['cid']);

        $html = false;

        if(!empty($name) && !empty($cid)) {

                $item = array();

                $query = $_SGLOBAL['db']->query('SELECT * FROM '.tname($name.'comments').' WHERE cid=\''.$cid.'\'');
像其他文件中的 例如 comment.php里面的 $_GET[name]都做正则了 而这个没有做正则。 导致了注入



成功出数据。

_______________________________________________________________

0x05 鸡肋的二次注入

在cp.php中
$ac = empty($_GET['ac']) ? 'profile' : trim($_GET['ac']);



if(in_array($ac, array('index', 'news', 'profile', 'credit', 'models'))) {

        include_once(S_ROOT.'./source/cp_'.$ac.'.php');
包含文件进来

在source/cp_news.php中
$newsarr = array('subject' => $_POST['subject'],

                                         'catid' => $_POST['catid'],

                                         'type' => $_POST['type'],

                                         'lastpost' => $_SGLOBAL['timestamp']);

        $itemarr = array('message' => $_POST['message'],

                                        'relativetags' => addslashes(serialize($tagnamearr)),                        //相关TAG

                                         'newsfrom' => $_POST['newsfrom'],

                                         'newsauthor' => $_POST['newsauthor'],

                                         'newsfromurl' => $_POST['newsfromurl'],

                                         'postip' => $_SGLOBAL['onlineip'],

                                         'includetags' => postgetincludetags($_POST['message'], $tagnamearr)

                                        );
这里对投稿时的处理。
$itemarr['itemid'] = inserttable('spaceitems', $newsarr, 1); //这里  

                        inserttable('spacenews', $itemarr);

                        getreward('postinfo');

                        postspacetag('add', $_POST['type'], $itemarr['itemid'], $tagarr,1);

                        $do = 'pass';

                } else {

                        $itemarr['itemid'] = inserttable('postitems', $newsarr, 1);
全局对_POST转义了 然后转义入库 转义符就没了。

找找出库的地方。

在viewcomment.php中
if($channels['menus'][$type]['type'] == 'model') {

        include_once(S_ROOT.'./function/model.func.php');

        $cacheinfo = getmodelinfoall('modelname', $type);

        if(empty($cacheinfo['models'])) {

                showmessage('visit_the_channel_does_not_exist', S_URL);

        }

        $modelsinfoarr = $cacheinfo['models'];

        $categories = $cacheinfo['categories'];

        $query = $_SGLOBAL['db']->query('SELECT i.*, ii.* FROM '.tname($type.'items').' i, '.tname($type.'message').' ii WHERE i.itemid = ii.itemid AND i.itemid=\''.$itemid.'\' AND i.allowreply=\'1\'');

        $ismodle = '1';

} else {

        $query = $_SGLOBAL['db']->query('SELECT i.*, ii.* FROM '.tname('spaceitems').' i, '.tname('spacenews').' ii WHERE i.itemid = ii.itemid AND i.itemid=\''.$itemid.'\' AND i.allowreply=\'1\'');//这里查询出来

        $ismodle = '0';

}

if(!$item = $_SGLOBAL['db']->fetch_array($query)) showmessage('not_found', S_URL)//出库;
$channel = $type = empty($item['type']) ? $type : $item['type'];

赋值的是查询出来的 就能引入单引号了。
$sql = "SELECT COUNT(*) FROM ".tname('spacecomments')." WHERE itemid='$itemid' AND status='1' AND `type`='$type' $wherestr ";

$listcount = $_SGLOBAL['db']->result($_SGLOBAL['db']->query($sql), 0);

$iarr = array();
再把出库的带入到了查询当中

造成了注入。

在viewnews.php中 也有出库的
if(!empty($_SCONFIG['viewspace_pernum']) && $listcount) {

        $repeatids = array();

        $j = 1;

        $sql = "SELECT c.* FROM ".tname('spacecomments')." c WHERE c.itemid='$news[itemid]' AND c.type='$news[type]' AND status='1' ORDER BY c.dateline ".($_SCONFIG['commorderby']?'DESC':'ASC')." LIMIT 0, $_SCONFIG[viewspace_pernum]";

        $query = $_SGLOBAL['db']->query($sql);
注册一个会员 然后发帖

入库





因为数据库存储的有长度限制 所以鸡肋。

关于作者

′雨。1篇文章1篇回复

评论16次

要评论?请先  登录  或  注册