记录一次Semcms外贸网站管理系统sql注入代码审计

欢迎各位师傅关注个人公众号: Gat4by

概述

Semcms外贸网站管理系统存在sql注入,攻击者可以通过该漏洞获取到敏感信息。

Semcms门户网站:http://www.sem-cms.com/

影响版本:<=V4.8的PHP版(目前最新)

影响插件: 后台管理界面->综合管理模块->用户管理处->编辑

FOFA空间测绘: app="SEMCMS"

代码审计过程:

在该项目源码的include目录下有一个contorl.php,文件中搜索inject_check_sql函数会发现其是一个全局sql查询字符串过滤函数。

这里使用正则进行匹配一系列sql语句中常用的字符preg_match('select|and|insert|=|%|<|between|update|\'|\*|union|into|load_file|outfile/i',$sql_str);

其所有sql查询语句字符串会先传参给$str变量后被verify_str()函数调用,verify_str()内层调用inject_check_sql()函数来进行检验,这相当于是一个全局sql语句校验器,select,and,insert,%,=,<,between,update,*,union,into,’等常见注入语句和构造闭合符号全被过滤。

接下来来到项目源码的Admin目录下有一个SEMCMS_User.php文件,对应的后台功能模块是用户管理。

当$type=”edit”时为编辑用户内容,这时候发现存在一个sql语句$row = mysqli_fetch_array($db_conn->query("SELECT * FROM sc_user WHERE ID=".$_GET["ID"])); 其sql语句直接从GET请求中获取到ID参数,并根据ID参数将改用的全部内容进行查询后取出结果。

阅读代码已知,将取出的数据按照字段名对表格内容进行填充渲染,因为sql语句只经过verify_str()调用inject_check_sql()进行黑名单过滤,sql语句未存在其他的sql防注入保护,并且无引号构造闭合,故存在sql注入可能性非常大,遗憾的是把select、union、and、=这几个字符进行过滤,导致无法从传统的sql验证角度来进行验证sql注入。

但是有一个新的思路可以帮助到我们:

我们已经知道其会返回已经存在用户的内容字段,且用户的内容字段受其参数ID影响,ID一定的时候,内容字段也不会进行更改。我们可以通过将ID这个参数进行固定,使之回显一个固定用户的内容,然后搭配着其他如if(),length()这些函数和正则匹配字符来对数据库长度和名称字符进行判断从而构成sql注入,以下为本地渗透验证过程

案例复现:

本地环境: gatsby.com(属于本地域名)

首先进入后台管理界面,综合管理模块的用户管理处,点击编辑后拦截抓包。


GET /semcms/admin/SEMCMS_User.php?type=edit&ID=4&page=1 HTTP/1.1
Host: gatsby.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Referer: http://gatsby.com/semcms/admin/SEMCMS_User.php
Cookie: scusername=%E6%80%BB%E8%B4%A6%E5%8F%B7; scuseradmin=Admin; scuserpass=21232f297a57a5a743894a0e4a801fc3
Upgrade-Insecure-Requests: 1

 

根据以下传入ID不同,回显的用户内容不同,存在与数据库交互传入且参数为数字型,验证我们的猜想

ID=4,返回sec用户的账号信息

ID=3,返回Admin用户的账号信息

接下来进行sql注入验证,已知该cms安装的默认数据库库名为mycms。

验证判断当前数据库长度为5,使得表达式的ID=4,回返的结果对应为ID=4的sec用户个人用户信息,使用Payload: ID=(length(database())-1)。

成功返回了用户ID=4的个人用户信息,那么在”=”被禁用的情况下我们可以判断(length(database())-1)=4 得到length(database())=5,数据库名称长度为5

接着可以判断数据库库名,使用正则匹配可以逐一判断出,使用Payload: ID=if(database()+RLIKE+"^m{1}",4,3)

当数据库名第一个字符为m时返回ID=4否则返回ID=3,ID=3和ID=4在上文我们对比过是不同的用户账号,ID=3为admin用户,ID=4为SEC用户,此时返回的为ID=4的sec用户内容,说明数据库名第一个字符为m。

同理判断数据库第二个字符,使用Payload:ID=if(database()+RLIKE+"^m[y]{1}",4,3)

这里用数据库名正则匹配以m开头,第二个字符为y的字符串,匹配成功返回ID=4,否则返回ID=3,当匹配成功返回ID=4的sec用户内容

更改payload,用数据库名匹配以m为开头,第二个字符为a的字符串时,匹配失败返回ID=3的Admin用户内容

代码审计过程和本地环境验证内容均已证明完毕。

总结:代码审计过程中,我们常用的"="被ban时,可以联系页面本身数据渲染的返回内容不同来充当这个"="的媒介以此来验证sql注入。

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值