复现条件环境:windows7 phpstudy2018 php5.4.45 apache 程序框架:damicms 2014条件:需要登录特点:属于GET型注入,且存在防御脚本,防御方法复现漏洞我们先注册个账号。账号test0 密码test0登陆进行场景复现, 访问链接:http://localhost/test0/index.php?s=/api/aj
复现条件
环境:windows7 phpstudy2018 php5.4.45 apache
程序框架:damicms 2014
条件:需要登录
特点:属于GET型注入,且存在防御脚本,防御方法
复现漏洞
我们先注册个账号。账号test0 密码test0
登陆进行场景复现, 访问链接:http://localhost/test0/index.php?s=/api/ajax_arclist/model/article/field/username,userpwd from dami_member# (注:要写#,别写#)
如图 1所示
图 1
我们可以看到账号密码已经爆出,证明漏洞存在。
接下来我们进行漏洞利用代码剖析。不过在剖析之前,我们先要了解一下此程序的URL路由,便于url链接构造,之前我们已经有过介绍了。
url链接构造
首先我们在注册的时候登陆,进入个人资料的的时候 我们可以看到注册,登陆,个人资料的链接
注册:http://localhost/test0/index.php?s=/Member/register.html
登陆:http://localhost/test0/index.php?s=/Member/login.html
个人资料:http://localhost/test0/index.php?s=/Member/main.html
通过 三个链接
我们可以得知为单一入口文件访问模式,URL路由的映射采用的写法是:网站域名/index.php?s=/控制器名/方法名.html 。看到html后缀 ,我们基本可以得知采用的是伪静态规则,去掉后缀,链接可用。
猜测带参数的链接构成:网站域名/index.php?s=/控制器/方法/参数名/参数值.html 或 网站域名/index.php?s=/控制器/方法/参数名/参数值
好,我们现在已经大概知道了链接构造。
接下来我们查看目录结构,如图2所示,感觉目录命名结构,有点像使用的thinkphp框架,打开/Core/Core.php,看下注释,得知是ThinkPHP框架,(注:一般能知道什么框架,或者你审计的用的是什么cms,能查到该框架的开发手册,直接查看手册如何设置的URL路由映射,进行URL链接构造就可以了。)这里我们假设不知这套程序不知道用的是什么框架,没有对应开发手册,我们来进行分析。我们基本可以猜测到哪个目录有什么作用功能。
Admin 后台功能目录 后台的相关类方法,配置文件基本都在此。
Core 核心目录
install 安装程序的目录
Public 一般一些css,js文件,图片文件,编辑器插件,字体等都会放在这里面公用。
Trade 查看该目录下的文件名,随便点开看看文件里的注释,得知为这是接口文件目录
Web前台程序功能目录
Runtime 缓存目录 一般缓存的东东都会生成在这里面
伪静态文件 程序做伪静态的配置
图2
前台的控制器就在/Web/Lib/Action/控制器名 Action.class,php。后台控制器同上,只是,"Web"改成了"Admin",也就是/Admin/Lib/Action/控制器名 Action.class,php。这样,我们就可以通过构造URL找到
路由映射的代码位置了。
下面我们根据漏洞复现的场景链接寻找出现漏洞的代码进行复现剖析。
漏洞利用代码剖析
查看入口文件是否引入了防御脚本
我们先大体看一下网站源码index.php,看一下是否有如图-3所示,看到h13 (注:h代表行数,此处指第13行)引入了php_safe.php。打开此脚本, 我们看到php_safe.php图4的h2 是//Code By Safe3
推测是360的防御脚本 或者改造了的防御脚本,h24-h33(注:h代表行数,此处指第24行到第33行)我们看到 不管是GET POST 还是COOKIE方式传送的要进行过滤。
图3
图4
通过漏洞连接定位的漏洞位置
通过上面分析,根据漏洞链接我们可以定位到漏洞位置在WebLibActionApiAction.class.php的 ajax_arclist方法中 如图5所示,
图5
分析漏洞源码
看到这个方法的入口处,很多$_REQUEST来接收参数,感觉琳琅满目,不要因此而迷失了双眼。我们先找到有SQL语句的地方。在h60,h64,h70。
看到三个sql语句中,可控的参数,where order num field 分别在h46->h48,h54被inject_check函数处理。我们按住ctrl,光标移动至inject_check上点击鼠标左键,选择/Core/Common/functions.php定位到h988的inject_check方法如图6所示,我们看到eregi()方法 被中线划掉,说明该方法弃用。php5.3x不再支持eregi。这里我们选择忽略或不忽略,为什么可以这样选择呢?因为我们之前在进行查看网站源码index.php的时候知道了发现本程序调用了防御脚本,GET方式传参的值都会被检测,另一个理由是看你运行该程序用的php版本是多少的。此时,我们回到三个SQL语句上。
看到参数被分别带入了 where(), order(), field(), limit() 方法中。由于本程序是用的thinkphp框架,这四个方法的使用,我们直接看thinkphp的手册就可以了。由于thinkphp 版本很多,我们先打印一下thinkphp的版本,在ajax_arclist方法开始处输入 代码: echo THINK_VERSION; die; 可以得知看到 2.1的版本。
图6
然后我们去查一下thinkphp 2.1的手册。这里我查看的是3.2的手册 因为这些地方版本改动不大。
代码语言:javascript复制where()
$User = M("User"); // 实例化User对象
$User->where('type=1 AND status=1')->select();
对应的原生sql语句:SELECT * FROM think_user WHERE type=1 AND status=1
代码语言:javascript复制order()
$User->where('status=1')->order('id desc')->limit(5)->select();
对应的原生sql语句:SELECT * FROM think_user WHERE status=1 order by id desc limit 5
代码语言:javascript复制field()
$Model->field('id,title,content')->select();
对应的原生sql语句:SELECT id,title,content FROM table
代码语言:javascript复制limit()
$User->where('status=1')->field('id,name')->limit(10)->select();
对应的原生sql语句:SELECT id,name FROM think_user limit 10
我们可以构造一个 四个函数都用到的写法
代码语言:javascript复制$User->where('status=1')->field('id,name')->order('id desc')->limit(5)->select();
生成的sql语句:SELECT id,name FROM think_user WHERE status=1 order by id desc limit 5
我们分析
在where 位置 limit位置 order 位置 如果构造语句的话都需要触及到php_safe.php中被黑名单的危险关键词。这里我们不去研究如何绕过这个防御脚本。而是在现有的漏洞环境中分析漏洞的产生。
但是,在field 位置 我们无需使用到被黑名单的危险关键词,就可以直接构造出想要查询其他表中字段的语句。好了,我们现在已经确定了 field参数符合SQL注入产生的条件。
我们回到ajax_arclist的开头往下走。看如何能执行h71的sql语句。
在h35看到了exit() 终止语句不往下继续执行的意思。我们要绕过,所以给变量model 随便赋值一个存在白名单的就可以绕过继续执行下面的代码,这里给model赋值“article”。继续往下走在h37判断是否有传递的表名前缀,如果有就与表名拼接,没有就算了。然后继续往下走,在h58判断如果传参page值就走h64,不传参
Payload构造思路
我们想要爆出账号密码就要查询dami_member中的username,userpwd两个字段。想要执行SELECT username,userpwd from dami_member,这样的语句就给field参数赋值username,userpwd from dami_member#,构造链接访问http://localhost/test0/index.php?s=/api/ajax_arclist/model/article/field/username,userpwd from dami_member# 他其实执行的语句就成了SELECT username,userpwd from dami_member# FROM `dami_article`,我们注入的payload被拼接闭合在了原来的sql语句中,导致爆出了账号密码的输出,证明了sql注入漏洞的存在
文由微信公众号:226安全团队