随笔 | 案例 | 知识 | 声音 | 其他 |
编者按
学海无涯,时间长了肚子里沉淀的技术也不多了,便趁着这波“长假”来学习和充实自己。在这个学习的过程中遇到了不少问题,这里挑其中一个有趣的问题,由此展开了一番探索,分享给大家。
本文作者:小名鼎鼎的先森。学习枯燥,分享更不易,欢迎点赞。
由于新冠病毒的肆虐导致相关地区疫情严重,牵动着全国人民的心。作为普通人,我们或许无法直接去支援他们,但是我们仍然可以给社会尽一份力:注意卫生防护不聚集,疑似患病即隔离,不信谣不传谣等。先森不懂医学也无法去支援疫情地区,只能祈祷一切安好、呆在家不给国家添乱。在这似乎遥遥无期、基本绝缘的日子里,看新闻联播、学习和发呆,这也让我深深地体会到拥抱自由、遵守法律的重要意义……
引子:钻研技术,发现问题
ThinkPHP框架是国内著名的PHP开源框架,因其灵活和功能强大拥有众多用户。 俗话说树大招风,前几年修复了若干严重的漏洞,如远程代码执行(RCE)、本地文件包含(LFI)和SQL注入等等。 先森一直在ThinkPHP框架的门口观望,没有系统地学习过,于是打算这些天好好补补这方面。 这不正好学到SQL操作的章节,借此可以好好研究TP框架的SQL注入与防御。 于是写了一个简单的SQL语句,尝试调试查看TP底层最终处理后的语句,当然TP框架也内置了功能,如在\tp\config\app.php里开启”app_debug”和”app_trace”选项实现应用调试及追踪、在\tp\config\database.php里开启” debug”选项实现记录SQL操作等。 光这些还不够,为了更简便操作,至少还要配合MySQL语句监控工具等。 这里我习惯使用“Seay代码审计系统”的“Mysql监控”插件,它可以记录MySQL上用户执行的所有SQL操作,该工具原理是基于数据库中的general_log功能,将监控到的SQL语句转存到mysql.general_log表中然后再按需筛选出来。 这里我写了一个非常简单的demo,该脚本的功能是通过查询指定id来返回用户的所有信息,TP底层最终执行的语句应该是”select * from think_user where id = xxx”。 在浏览器里按TP框架的访问方式,依次填入指定的模块、控制器、方法和参数访问后,浏览器按预定想法回显了我们数据,框架内置的调试器也显示执行了两条查询,但是我的“神器”却无任何有意义的回显。 于是我诧异地跑到MySQL的管理工具里执行这个查询操作,这次确实可以监控到执行的SQL语句,所以排除了该工具存在故障的可能性。 这就有些颠覆了我对MySQL数据库和ThinkPHP框架的认知,要知道MySQL中general_log功能的作用就是记录用户的所有操作,堂堂一个Oracle公司不可能出这种问题吧? ! 于是找到几位搞技术的朋友请教一下这个情况,他们对此也感到奇怪。但忙于工作和其他事情,无暇研究这个问题…俗话说自己动手丰衣足食,加之对逆向工程越来越有浓厚兴趣了( 后面会有对工具的逆向过程 ),便开始了这场刨根问底的行动。 索性将TP框架中的增删改查的方法都试了一遍,连朋友提到的TP两种的原生执行SQL的方法也是这样,发现真的都不行。 我简单的追溯了下TP底层是如何处理数据库操作。 从query函数出发->经由核心功能think\Query.php中的query方法->经由核心功能think\Collection.php中的query方法,发现最终是被PDO的prepare方法处理,简而言之就是经由SQL预处理了。 所以问题是不是可能出在预处理上了? 为了更好的验证这个猜测,我写了一个mysqli下的预处理查询脚本,功能是查询think_user表中id为3的用户信息。 通过浏览器的回显可以认定这三种查询方式是完全没问题的,但是Mysql监控工具的回显结果却不尽人意。 所以综上,我们可以推测出是 SQL编译预处理环节的问题。 未完待续……