CTFHub-Web进阶-JWT练习

15 篇文章 2 订阅
8 篇文章 1 订阅

JWT的含义

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519)。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT的结构

JWT由三部分组成,它们之间用圆点.连接。这三部分分别是:

Header     -->头部
Payload    -->负载
Signature  -->签名

这三部分拼接在一起就组成了JWT

Header.Payload.Signature

在这里插入图片描述

例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

使用在线工具,进行JWT解密

在这里插入图片描述

Header(头部)
Header的参数为alg和typ

alg: ALGORITHM   即算法名称
typ: TOKEN TYPE  即token的类型

例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

数据所包含的信息为:token的类型是JWT,算法名称为HS256

Payload(有效载荷)

Payload用来存放实际需要传递的数据。

数据包含三个部分

1.Registered claims (标准中注册的声明) 
JWT 规定了7个官方字段,这些是一组预定义的claims,非强制性的,供选用。
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

2.Public claims (公共的声明)
可以随意定义。自定义claims,注意不要和JWT注册表中属性冲突,这里可以查看JWT注册表。

3.Private claims (私有的声明)
这些是自定义的claims,用于在同意使用这些claims的各方之间共享信息,它们既不是Registered claims,也不是Public claims。 

例如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

数据中所包含的信息为:主题为1234567890,自定义的私有字段名字为John Do,签发时间为1516239022

Signature(签名)

Signature对前两部分的签名,防止数据篡改
将上面的HeaderPayloadbase64编码后的字符串用.连接在一起
提供一个密钥(secret)用Header中所规定的算法加密,就可以形成一个新的字符串。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
)

将上面的三部分base64编码后,用 .拼接在一起,就形成了一个完整的JWT格式

JWT的特点

1.JWT 默认是不加密,但也是可以加密的。
2JWT 不加密的情况下,不能将秘密数据写入 JWT。
3.JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
4.JWT 签发了,在到期之前就会始终有效,因为服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或更改 token 的权限。
5.JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。
6.JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

CTFHub-Web-JWT

敏感信息泄露

题目描述:JWT的头部和有效载荷这两部分的数据是以明文形式传输的,如果其中包含了敏感信息的话,就会发生敏感信息泄露。试着找出FLAG。格式为 flag{}

访问题目地址
在这里插入图片描述
尝试管理员账号登陆成功,但是没有flag
在这里插入图片描述

抓包一下,在Cookie里面发现了
在这里插入图片描述

token的值为

eyJBRyI6Ijg3ZWQ4ZjBjNmY3ZGNkNX0iLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJGTCI6ImN0Zmh1YntiYmI0MDQxMmUifQ.raHL5NAWYrXTeVHp9ptaU1gVh0k55ZW0TjkxwthfrDc

jwt解密,在JWT的HEADER和PAYLOAD部分可以得到flag

在这里插入图片描述

无签名

题目描述: 一些JWT库也支持none算法,即不使用签名算法。当alg字段为空时,后端将不执行签名验证。尝试找到 flag。

访问靶机地址
在这里插入图片描述
管理员弱密码登陆
在这里插入图片描述
抓包,在Cookie处发现JWT信息

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJyb2xlIjoiZ3Vlc3QifQ.MaphZVk25q4stXxAmEgXmKCW7aUo3jDJtgv9DwahLwc

在这里插入图片描述

JWT解密
在这里插入图片描述
将Header里面的alg置为空,即使用none算法
在这里插入图片描述
Payload里面的guest改为admin
在这里插入图片描述
由于使用无签名算法,所以Signature为空。然后使用.将Header、Payload和Signature拼接起来,得到新的JWT。

token=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0=.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJyb2xlIjoiYWRtaW4ifQ==. 

得到flag
在这里插入图片描述

弱密钥

题目描述:如果JWT采用对称加密算法,并且密钥的强度较弱的话,攻击者可以直接通过蛮力攻击方式来破解密钥。尝试获取flag

抓包
在这里插入图片描述
token为

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJyb2xlIjoiZ3Vlc3QifQ.0cny5aIZ4dDg7zcdMYCwzRPst82Z-bl5w-7bEH_dlC4

Base64解码

{"typ":"JWT","alg":"HS256"}{"username":"admin","password":"123456","role":"guest"}	YT%қ㹐d?Қ|~^2k
N3$

密钥不知道,使用JWT cracker工具爆破密钥,爆破得到密钥是cgpo

┌──(kali㉿kali)-[~/c-jwt-cracker]
└─$ make        
gcc -I /usr/include/openssl -g -std=gnu99 -O3   -c -o main.o main.c
gcc -I /usr/include/openssl -g -std=gnu99 -O3   -c -o base64.o base64.c
gcc -o jwtcrack main.o base64.o -lssl -lcrypto -lpthread
                                                                                                                                                                         
                                                                                                                                                                       
┌──(kali㉿kali)-[~/c-jwt-cracker]
└─$ ./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJyb2xlIjoiZ3Vlc3QifQ.0cny5aIZ4dDg7zcdMYCwzRPst82Z-bl5w-7bEH_dlC4
Secret is "cgpo"

把密钥cgpo填进去,然后把role:guest改成role:admin。
在这里插入图片描述
新生成的jwt

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJyb2xlIjoiYWRtaW4ifQ.G9FbZliNHqIX0wWyMh721jIbOIntXLydQCbLyebt32w

使用该jwt访问首页得到flag
在这里插入图片描述

修改签名算法*

题目描述:有些JWT库支持多种密码算法进行签名、验签。若目标使用非对称密码算法时,有时攻击者可以获取到公钥,此时可通过修改JWT头部的签名算法,将非对称密码算法改为对称密码算法,从而达到攻击者目的。

源码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <title>CTFHub JWTDemo</title>
        <link rel="stylesheet" href="/static/style.css" />
    </head>
    <body>
        <main id="content">
            <header>Web Login</header>
            <form id="login-form" method="POST">
                <input type="text" name="username" placeholder="Username" />
                <input type="password" name="password" placeholder="Password" />
                <input type="submit" name="action" value="Login" />
            </form>
            <a href="/publickey.pem">publickey.pem</a>
        </main>
        <?php echo $_COOKIE['token'];?>
        <hr/>
    </body>
</html>

<?php
require __DIR__ . '/vendor/autoload.php';
use \Firebase\JWT\JWT;

class JWTHelper {
  public static function encode($payload=array(), $key='', $alg='HS256') {
    return JWT::encode($payload, $key, $alg);
  }
  public static function decode($token, $key, $alg='HS256') {
    try{
            $header = JWTHelper::getHeader($token);
            $algs = array_merge(array($header->alg, $alg));
      return JWT::decode($token, $key, $algs);
    } catch(Exception $e){
      return false;
    }
    }
    public static function getHeader($jwt) {
        $tks = explode('.', $jwt);
        list($headb64, $bodyb64, $cryptob64) = $tks;
        $header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64));
        return $header;
    }
}

$FLAG = getenv("FLAG");
$PRIVATE_KEY = file_get_contents("/privatekey.pem");
$PUBLIC_KEY = file_get_contents("./publickey.pem");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!empty($_POST['username']) && !empty($_POST['password'])) {
        $token = "";
        if($_POST['username'] === 'admin' && $_POST['password'] === $FLAG){
            $jwt_payload = array(
                'username' => $_POST['username'],
                'role'=> 'admin',
            );
            $token = JWTHelper::encode($jwt_payload, $PRIVATE_KEY, 'RS256');
        } else {
            $jwt_payload = array(
                'username' => $_POST['username'],
                'role'=> 'guest',
            );
            $token = JWTHelper::encode($jwt_payload, $PRIVATE_KEY, 'RS256');
        }
        @setcookie("token", $token, time()+1800);
        header("Location: /index.php");
        exit();
    } else {
        @setcookie("token", "");
        header("Location: /index.php");
        exit();
    }
} else {
    if(!empty($_COOKIE['token']) && JWTHelper::decode($_COOKIE['token'], $PUBLIC_KEY) != false) {
        $obj = JWTHelper::decode($_COOKIE['token'], $PUBLIC_KEY);
        if ($obj->role === 'admin') {
            echo $FLAG;
        }
    } else {
        show_source(__FILE__);
    }
}
?>

publickey.pem

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuR4Ux+xr+5aFBfkU6sr3
KHChl9/R69s2bIjSHiZFtkWIwUpf9dQ5hTRICibphgehg8958xaGhuJA+5cMLEy9
LCR+0twWcSg7fPBe/Gbbo958MMjQbCPDBQOvOeeKYw++isq1r6AM1K0w+P69Yk33
Rd5iAux5mYp1cu550W3iiA5L+gsBr5iGeSnVBYoE0NETygExSh9tn1YEjK7+Si4L
GWlhspuQ1c3ZCFiiFyf4vyZjVS2YJa1awaabzQUU/l8qoaD4vacc8gO9HURSMPy6
QK6tR8Wn7S9FE+NfzDuj/W/2bZqJfg6C3+m27cmNt7TUka//eGcwbVTCKzSkvNDz
UQIDAQAB
-----END PUBLIC KEY-----


参考文章:JWT基础知识

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Atkxor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值