

通过前期的 WEB 漏洞的学习,掌握了大部分的安全漏洞的原理及利用,但在各种脚本语言开发环境的差异下,会存在新的安全问题,其中脚本语言类型 PHP,Java,Python 等主流开发框架会有所差异。
Javaweb-SQL 注入攻击-预编译机制绕过
1. SQL注入的防御
---防御 sql 注入:1.session2.参数绑定存储过程
#利用 session 防御
---session 内容正常情况下是用户无法修改的
---select * from users where user = "'" +session.getAttribute("UserID") + "'";(session在服务器内)
#参数绑定方式,利用了 sql 的预编译技术
---常用Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。
---Statement 该对象用于执行静态的 SQL 语句,并且返回执行结果。 此处的SQL语句必须是完整的,有明确的数据指示。查的是哪条记录?改的是哪条记录?都要指示清楚。
---PreparedStatement ,SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。(这里是PreparedStatement不允许一个占位符(?)有多个值,注入的语句也就不会被执行)

---在使用参数化查询的情况下,数据库系统不会将参数的内容视为SQL指令的一部分来处理
---而是在数据库完成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 语句。(原理类似堆叠注入,一条语句出现多条命令)
#进入靶场

#数据包分析(发送的请求指向的是源代码中的server)

#源代码分析
---发现SQL语句,并且语句后面有order by(传递column参数),寻找传参column的地方


---抓包工具修改

---修改ip为1

---报错的时候存在order by,因此可以用case when语句

---case when原理:普通的按某一个字段或者多个字段排序没办法满足我们的需求时,可以通过case when来排序

---构造语句(说实话我看不懂这个语句,应该是):
select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by " + case when(select substr(ip,{0},1)='{1}' from servers where hostname='webgoat-prd')
---根据报错构造Python脚本(webgoat在虚拟机里,不能用Python脚本跑)
---设置请求数据的数据头,和cookie
---设置请求的代理,也就是先发送给抓包工具
---resp为request请求(目标URL,请求头(XML格式),cookie,代理)
---如果webgoat-acc字符串在返回的json数据的第一个元素的主机名,就认为是对的,就输出结果(emmmm感觉不太懂,只理解了如果是Java语句的SQL如果是预编译的的话,基本不能注入。除非存在order by,可以用order by case when 来构造查询语句(具体构造也不太会,突然感觉408和数据库的重要性),来进行数据库的查询。其实这个Python代码感觉挺有用的,但是代码看的似懂非懂)

Java的jwt令牌原理
#什么是JWT
---JSON Web Token(JSON Web 令牌)是一种跨域验证身份的方案。JWT 不加密传输的数据,但能够通过数字签名来验证数据未被篡改(但是做完下面的 WebGoat 练习后我对这一点表示怀疑)。
---JWT 分为三部分,头部(Header),声明(Claims),签名(Signature),三个部分以英文句号.隔开。
---JWT 的内容以 Base64URL 进行了编码。

#头部(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": "9bc92a44-0b1a-4c5e-be70-da52075b9a84",//JWT标识
"client_id": "my-client-with-secret"
}
#JWT 固定参数有:
---iss:发行人
---exp:到期时间
---sub:主题
---aud:用户
---nbf:在此之前不可用
---iat:发布时间
---jti:JWT ID 用于标识该 JWT
#签名(Signature)
---服务器有一个不会发送给客户端的密码(secret),用头部(header)中指定的算法对头部和声明的内容用此密码进行加密,生成的字符串就是 JWT 的签名。
下面是一个用 HS256 生成 JWT 的代码例子

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
Javaweb-身份验证攻击-JWT 修改伪造攻击
1. 进入靶场
---更改收到的令牌成为管理员用户,并且重置投票(管理员密码丢失)
---这里的操作和之前更改cookie的操作差不多,只是更改的数据是加密的数据

---点击Tom用户抓取数据包(传参用户和cookie,token为空白)

---点击重置投票(发现只有管理员才能重置),获取到一段cookie


#将cookie的acces_token数据解密:
---头部:”alg”:”HS512”(jwt使用算法的参数为HS512)
---声明:iat:发布时间(这里是时间戳形式);admin:是否是管理员,这里为布尔;user:用户名

---下面是签名,(网站只能识别前面的首部和声明,后面的签名需要输入密匙才行)

---将admin修改为Ture尝试(报错说签名不对,应为只改了声明,但是签名没有改,由于没有密匙,所以签名改变不了)

2. 修改首部和声明来绕过签名修改
#修改首部为None,声明为TRUE

---去除=添加到首部(注意由于首部为None,第三部分签名就为空,否则报错)
---注意:在HTTP传输中,base64编码中的=,+,/等等特殊符号通过URL解码容易产生歧义,因此产生了与URL兼容的base64 URL编码

---重置成功

3. 如果有密匙
---首部不需要更改
---更改admin为TRUE

---输入密匙

---修改数据包传输

Javaweb-身份验证攻击-jwt密匙爆破攻击
1. 进入靶场
---一旦找出密钥就就可以创建新令牌进行签名。因此,只要密钥足够强大,暴力破解字典就不可行
---通过以下令牌找出密钥,并将用户名改为WebGoat

---令牌解密(iat:开始时间,exp:失效时间)

2. Python脚本分析(注意小迪视屏的脚本是Python2,这个字典在提示里面可以下载,我的环境是Python3运行不了)
#脚本逻辑
---若签名直接校验成功(原文为失败,猜测为作者手误),则 key_ 为有效密钥;
---若因数据部分预定义字段错误(jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError,jwt.exceptions.InvalidIssuedAtError,jwt.exceptions.InvalidIssuedAtError,jwt.exceptions.ImmatureSignatureError)导致校验失败,说明并非密钥错误导致,则 key_ 也为有效密钥;(这不懂啊,总得来说就是通过比对字典的密匙加密后的签名,来获取密匙)
---若因密钥错误(jwt.exceptions.InvalidSignatureError)导致校验失败,则 key_ 为无效密钥;
---若为其他原因(如,JWT 字符串格式错误)导致校验失败,根本无法验证当前 key_ 是否有效
---得出答案:victory

#更改结束时间exp

#修改jwt
---exp和username

---输入密匙

---输入字典爆破的签名(爆破成功,爆破的前提条件:1.可用的字典2.获得完整的令牌的格式)

Javaweb-身份验证攻击-jwt修改伪造冒充
1. 进入靶场
---通过伪造让Tom进行支付

---查看日志进行分析(这里发现一个token传参使用的JWT令牌)

---解析jwt令牌(发现为Tom的数据包)

---修改exp,并且将首部改为None,去掉签名部分构造JWT

2. 点击checkout抓包(查找与token匹配的数据包)
---在授权这里写入jwt(有些疑惑为什么不加上前面的参数token)

---返回成功(这里没有检测签名和失效时间的条件下)

Javaweb-身份验证攻击-jwt安全结合SQL注入
1. 进入靶场
#杰瑞相删去汤姆的账户,但是他只有自己的令牌

---点击汤姆的删除抓包分析

---将token传的参数解密(发现是杰瑞的JWT)

2. 源代码分析
---这里执行了一条SQL语句,传递的参数是kid
---这个函数传递的参数是token,如果token不为空,就创建一个令牌的对象,并且将令牌解密
--- .Jwts.parser().setSigningKeyResolver(自定义方法获取签名KEY).parseClaimsJws(token);//通过自定义方法获取签名key然后对token进行JWT解析
---kid为令牌的首部里面的kid(也就是说,这里没有预编译函数,所以存在注入点)
---利用sql inject,控制查询语句的查询值来控制JWT的密钥,从而伪造JWT,完成任务。
#数据库查询语句(说明jwt_keys表中有一个id的值是:“webgoat_key”):SELECT key FROM jwt_keys WHERE id = 'webgoat_key'

3. 构造注入语句
SELECT key FROM jwt_keys WHERE id = ‘y' and 1=2 union select id from jwt_keys where id ='webgoat_key"
---查询id为webgoat_key中的所有信息(主要是查看签名信息的密钥)
CTF-Node.js-前端JWT登录安全-伪造admin实现getflag
1. 进入靶场
#发现一个登录界面

---登录注册的用户123456抓包分析

---发现post传输的数据的格式为jwt令牌格式

---登录之后获取flag发现没有权限(应该是获取管理员,才能查看)

2. 查看nodejs框架
---nodejs简介(猜测是一个前端框架)

---通过/controllers/api.js查看框架信息(这里发现管理员帐号:admin,而且他的JWT验证在前端)

3. 修改JWT
---修改首部alg为none

---修改username为admin,密匙id的secreted改为空[]

---修改令牌和用户名

---发现返回成功

---放出数据包发现已经管理员登陆

---获取flag
