ozzi- / jwt4b Goto Github PK
View Code? Open in Web Editor NEWJWT Support for Burp
License: GNU General Public License v3.0
JWT Support for Burp
License: GNU General Public License v3.0
Any plans for JWT4B to support SAMLRaider like attacks on JWS? E.g. https://nvd.nist.gov/vuln/detail/CVE-2018-0114
The Suite Tab does not have a scrollbar yet.
Azure sends JWT tokens in a POST parameter id_token. Implementation of a https://github.com/mvetsch/JWT4B/blob/master/src/app/tokenposition/ITokenPosition.java class should be sufficient to support this.
Visualize Feedback concerning JWT Decoding (valid / invalid)
I had the case, where i found the right key of an JWT-Token. I wanted to verify it with this plugin. But since my system time was before the iat, the token was shown as followed:
It would be helpfull to visualize when a signature was correctly formed/tested. Since other users would get a similar effect when verifying against an expired token. The information of an unmet claim is helpful, but not as important as being able to build correct signatures. From a user point of view it is unclear if the information beneath the red "warning" is extra information or the reason for the red warning. I suggest either to do the coloring only on the Signature/Key part and without the claim testing (Since claims are shown in the bottom corner) or color it like a traffic light and use yellow when a claim is missing but the signature could be verified.
I have a latest plugin installed, and "auth-token" in Cookie is not being detected.
Would it be possible to implement something like "custom token name" or something similar, in case we face an application that uses a custom token name?
Cookies can be used to transfer jwt's too:
https://de.wikipedia.org/wiki/JSON_Web_Token#.C3.9Cbertragung_mit_HTTP
Featue: add cookie support
Nice to have: check for secure and httponly flags too
See https://github.com/ozzi-/JWT4B/pull/48
When forwarding, GZIP header should be either stripped or content re-zipped.
It's not necessary that you commit the built JAR files into the Git repository, which will get bigger and bigger with every new binary file. GitHub has a extra release feature, where you can upload the built JAR file. You can find it in the release tab: https://github.com/mvetsch/JWT4B/releases
Best wishes,
Mänu ;-)
Hey Ozzi
I have a feature request:
It should be possible to support requests with multiple JWTs, when there is for example a JWT in an Auth header and another in a cookie or multiple ones in cookies.
I know, a pull request would be better for you, but I'll just leave it here as-is...
Best,
Mänu 😄
Hi! Thank you for the work on this plugin!
Unfortunately, it seems like the plugin no longer works in v2021.2 - if I send a JWT to the JSON Web Token extension, it correctly decodes the JWT and I can see the fields. However, it is not possible to modify the JWT in the text area. I can click the text area, move the cursor around, select text and the text area even automatically detects pairs of parantheses. But it is not possible to add new text or modify the existing parameters. Furthermore, the text area itself is very small, which would make editing (if it would work) quite uncomfortable as well.
Is this a general problem with v2021.2 or is my installation broken? Thank you! :)
In the interception view, when changes are made but the tab is not JWT4B when one clicks "Forward", the original message is sent.
Hi Ozzi :)
We discovered an issue while using your extension.
Issue
The timestamps are modified by the extension even if the content is not changed.
Steps to reproduce
Access a website that uses JWT tokens, e.g. https://www.compass-demo.com/jwt_demo/.
Received JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoidXNlciIsImV4cCI6MTU5ODM1ODU1NC4zNzQ2MjM1fQ.katJDBB-Yqkdx9u_ua-6OMW1-lNxqHnEiIiRh43cAFQ
Intercept a request containing a JWT and open the "JSON Web Tokens" tab. Forward the JWT without modifying.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoidXNlciIsImV4cCI6MS41OTgzNTg1NTQzNzQ2MjM1RTl9.katJDBB-Yqkdx9u_ua-6OMW1-lNxqHnEiIiRh43cAFQ
The token is not accepted, because the signature is not valid anymore.
Decoded original token:
{"role":"user","exp":1598358554.3746235}
Decoded token sent by the extension:
{"role":"user","exp":1.5983585543746235E9}
So, the extension modifies the timestamp and makes the token invalid, even if it was not modified.
Best,
Mänu
Hi ozzi-
I really like this extension and use it a lot but just had some issues while creating signatures with a secret that contains linebreaks.
This is e.g. important in the algorithm confusion attack where you sign your RS256 token using the public key but using the HS265 algorithm.
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE2MDU3OTk4MTd9.Spvq4AvnNNd8RFTcZJr2r0re7hSxWi1XBvLSEdpBY2k
Decoded:
Headers = {
"alg": "HS256",
"typ": "JWT"
}
Payload = {
"foo": "bar",
"iat": 1605799817
}
Signature = "Spvq4AvnNNd8RFTcZJr2r0re7hSxWi1XBvLSEdpBY2k"
I get the expected result i previous versions of the extension.
I want to sign it using the following multi line secret (incl. the last linebreak!):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33TqqLR3eeUmDtHS89qF
3p4MP7Wfqt2Zjj3lZjLjjCGDvwr9cJNlNDiuKboODgUiT4ZdPWbOiMAfDcDzlOxA
04DDnEFGAf+kDQiNSe2ZtqC7bnIc8+KSG/qOGQIVaay4Ucr6ovDkykO5Hxn7OU7s
Jp9TP9H0JH8zMQA6YzijYH9LsupTerrY3U6zyihVEDXXOv08vBHk50BMFJbE9iwF
wnxCsU5+UZUZYw87Uu0n4LPFS9BT8tUIvAfnRXIEWCha3KbFWmdZQZlyrFw0buUE
f0YN3/Q0auBkdbDR/ES2PbgKTJdkjc/rEeM0TxvOUf7HuUNOhrtAVEN1D5uuxE1W
SwIDAQAB
-----END PUBLIC KEY-----
Plugin output on stdout:
15:41:16.377 | JWT4B says hi!
15:41:34.097 | Recalculating Signature with Secret - 'a
b
'
15:53:36.827 | Recalculating Signature with Secret - '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33TqqLR3eeUmDtHS89qF
3p4MP7Wfqt2Zjj3lZjLjjCGDvwr9cJNlNDiuKboODgUiT4ZdPWbOiMAfDcDzlOxA
04DDnEFGAf+kDQiNSe2ZtqC7bnIc8+KSG/qOGQIVaay4Ucr6ovDkykO5Hxn7OU7s
Jp9TP9H0JH8zMQA6YzijYH9LsupTerrY3U6zyihVEDXXOv08vBHk50BMFJbE9iwF
wnxCsU5+UZUZYw87Uu0n4LPFS9BT8tUIvAfnRXIEWCha3KbFWmdZQZlyrFw0buUE
f0YN3/Q0auBkdbDR/ES2PbgKTJdkjc/rEeM0TxvOUf7HuUNOhrtAVEN1D5uuxE1W
SwIDAQAB
-----END PUBLIC KEY-----
'
This works as expected.
Also CyberChef confirms that this is the correct behavior:
In the latest release, the attacks did not work anymore :(.
Performing the same steps as already described.
Plugin output on stdout:
15:55:18.704 | JWT4B says hi!
15:55:56.423 | Recalculating Signature with Secret - '-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33TqqLR3eeUmDtHS89qF3p4MP7Wfqt2Zjj3lZjLjjCGDvwr9cJNlNDiuKboODgUiT4ZdPWbOiMAfDcDzlOxA04DDnEFGAf+kDQiNSe2ZtqC7bnIc8+KSG/qOGQIVaay4Ucr6ovDkykO5Hxn7OU7sJp9TP9H0JH8zMQA6YzijYH9LsupTerrY3U6zyihVEDXXOv08vBHk50BMFJbE9iwFwnxCsU5+UZUZYw87Uu0n4LPFS9BT8tUIvAfnRXIEWCha3KbFWmdZQZlyrFw0buUEf0YN3/Q0auBkdbDR/ES2PbgKTJdkjc/rEeM0TxvOUf7HuUNOhrtAVEN1D5uuxE1WSwIDAQAB-----END PUBLIC KEY-----'
All linebreaks from the secret input are removed.
This results in a non-working attack :(.
Can you fix this?
Thanks & LG
Mänu
in burp 2020.1 you can no longer edit the JWT token.
Hi @mvetsch
i submitted your awesome plugin to Bapp Store. It is live now.
Burp Suite Team said the following. Please respond to them at support at portswigger.net if you wish.
Please check everything is ok and let me know of any problems. I wondered, do you really need the main tab. Your extension seems most useful as a Message Editor. People with many extensions installed suffer from tab clutter so if it’s not necessary you could remove.
When using the send to suite tab on a message that was edited, the edited text will always be used, even if the original tab is selected.
Whenever you send something to Repeater and change the payload, it would be great to adjust the dta
in the Payload.
Hello,
During a recent pentest, the jwt token was being sent via a HTTP header named jwt. As such the extension did not recognize it and I was not able to test it. It would be better for users to be able to choose the jwt input sources rather than hardcoing the values in the source. JOSEPH has a feature like that and it works pretty well.
I am looking forward to see this in JWT4B.
Since on REST APIs all requests contain auth-tokens usually this leads to a wall of blue entries in burp:
@ozzi- What do you think? Would it make sense to only mark requests with the token in the response? So the plugin just marks the token issuing, instead of every request it is used.
JWT headers are decoded into an object, and each key-value pair is displayed on a single line. However, typically x5c
(certificate chain) in the header contains several elements, so instead of a long
{
"x5c" : [ "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" ]
}
we can do
{
"x5c" : [
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
]
}
``
Hi !
In the repeater tab I have the JWT4B tab. 👍
After playing in the tab (recalculate for ex), and then going to RAW the tab will disappear.
This seems to be crashing, when I check Extender/extensions/JWT4B errror tab it shows:
15:53:50.626 | [Ljava.lang.StackTraceElement;@f6c3b3e
Also, after sending the request the tab disappear, and again the error tab show stacktraces.
Thanks and keep the great work!
pd: in Bapp store the extension seems outdated
addLogHeadersToRequest is potentially executed multiple times on one message.
This leads to the header being added multiple times.
Steps to reproduce:
I think that JWT4B needs supporting for burp SessionHandling. (ex: it would be sessionhandling controller or some else)..
On other words, we set signing algorithm an signing key and use JWT4B as SessionHandling extension to re-sign every JWT that correspond our session rules (for example: every JWT in packets to login.microsoftonline.com).
With this feature we can automatically fuzz fields inside JWT with Burp.
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJhZG1pbiI6ZmFsc2V9.i8bDiqGHk5xcNyzSgQgF4u_VoCrWecMmgXR7TLIpcQFgF8SLWm-_QKUp1tshc0qkufftvTeu88TD9EcG23K1uoq2qWGHQqKNGhVbFUFQrkRDbYL4LU9wiPP5IwzqcjvvYPclJbPDJLrfpdpXAAkJdBfIykVvVs93tT7gyk0Vd82iUGJEorN0fZmRZD4YUuf1BGYLKovF2YzWGP7ucFiXEqJWtxoLfLxH5uMjODV6n9S0P-6eGb43xZl2v-w9nDW6Kb4bbTUP8qzmFjehUno8BCwwHtEe1Kx1Xb7plzx4TwPOwCmn1vP2gekuTcgjUvDeIOLnzMt7uDR-8oA80HJl6g
java.lang.NullPointerException: Cannot invoke "String.length()" because "key" is null at app.algorithm.AlgorithmLinker.generatePublicKeyFromString(AlgorithmLinker.java:56) at app.algorithm.AlgorithmLinker.getKeyInstance(AlgorithmLinker.java:176) at app.algorithm.AlgorithmLinker$2.getPublicKeyById(AlgorithmLinker.java:147) at app.algorithm.AlgorithmLinker$2.getPublicKeyById(AlgorithmLinker.java:143) at com.auth0.jwt.algorithms.RSAAlgorithm.verify(RSAAlgorithm.java:45) at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:287) at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:271) at app.controllers.JWTSuiteTabController.contextActionKey(JWTSuiteTabController.java:89) at app.controllers.JWTSuiteTabController.contextActionSendJWTtoSuiteTab(JWTSuiteTabController.java:77) at app.controllers.JWTSuiteTabController$1.insertUpdate(JWTSuiteTabController.java:139)
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJFUzI1NmluT1RBIiwibmFtZSI6IkpvaG4gRG9lIn0.MEQCICRphRrc0GWowZgJAy0gL6At628Kw8YPE22iD-aKIi4PAiA0JWU-qFNL8I0tP0ws3Bbmg0FfVMn4_yk2lGGquAGOXA
Hi,
I just faced a case in which the signing key contained newlines, which are stripped during paste in the field. That may also be useful in case people want to test the RS256 -> HS256 switch public key as secret.
Thanks!
Implement Registered Claims:
http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName
when using "alg:none" exploit, the signature should be deleted and that's indeed what JWT4B does. but for the next requests, JWT4B can't recognize the jwt token because of the validations in the TokenCheck.java file.
I think validating the jwt token with this regex will solve the problem:
([A-Za-z0-9+/=_-]+\.){2,2}([A-Za-z0-9+/=_-]+)?$
this validates the entire token at once and also considers tokens with no signature as valid.
thanks ozzi 👍
Token goes in as ey...(rest of token)
Intercepter then returns it as ew..(rest of token)
While the resulting token is valid, it might be confusing for the users.
Some kind of UTF / ASCII issue?
Currently if header has Authorization: Bearer
it would say "JWT detected" (I believe the logic is here), but RFC 6750 doesn't require Bearer Token to be JWT (for example some Google API doesn't use JWT as Bearer Token). It might be better to label the request as "JWT detected" only when Bearer Token is valid JWT.
After the latest update, the JWT4B attack interface is no longer available in Repeater or Intercept.
Hey !
Thanks for this great extension 😄
I was wondering what are the "automated tests" that the ext provide (i see none on my version which seems to be the latest) ?
Is there a way to disable the automated tests ?
is there a button to click to activate only the alorithm to None or the CVE-2018-0114 attack ?
It would be super nice to have a button for each attack that recreate & print the malicious jwt.
Then we simply copy paste it into repeater or our app. 🚀
Plugin loaded normally
I see the decoded message but there is no way to edit the contents to perform a replay attack.
Im a missing something here?
-> getselectedata override
Thank you for the work, guys.
But currently, the plugin is unusable. Why do you make editing JWT so difficult? Only adding characters work. DELETE, BACKSPACE or COPY/PASTE does not work at all. In the end, I need to do that manually by editing BASE64 :(
In response below JSON Web Tokens detected that "No secure flag set" and "No HttpOnly flag set".
HTTP/1.1 303 See Other
...
Content-Length: 0
Connection: close
Set-Cookie: SECRET_SESSION=eyJhbGciOiJIUzI1NiJ9.ey[VALID_PAYLOAD].[VALID_SIGNATURE]; SameSite=Lax; Path=/; Secure; HTTPOnly
Location: /
...
Expected result: No alert, because flags are set.
JWT4B seems to be automatically applying an unicode encoding on some characters as soon as it parses the JWT.
I noticed this on the JWT header. I think it doesn't happen on other parts of the token.
Here's an example. This is how the original header decodes to:
{
"typ": "JWT",
"kid": "Z4osLouitTFO+A+xOZ/YcdtlW04=",
"alg": "RS256"
}
This is what JWT4B decodes it to as soon as I switch on the extension on Burp's Repeater:
{
"typ": "JWT",
"kid": "Z4osLouitTFO+A+xOZ/YcdtlW04\u003d",
"alg": "RS256"
}
So by simply by switching on the extension, it corrupts the token and makes the request invalid.
The response with the (shortened) JWT that was not detected is
{
"found": true,
"data": {
"trace": [],
"errorType": "string",
"errorMessage": "{"error":"Incorrect xxx","source":"xxxx","key":"BAD_REQUEST"}"
},
"log": "xxxx',\n method: 'get',\n params: [Object],\n headers: [Object],\n transformRequest: [Array],\n transformResponse: [Array],\n timeout: 0,\n adapter: [Function],\n xsrfCookieName: 'XSRF-TOKEN',\n xsrfHeaderName: 'X-XSRF-TOKEN',\n maxContentLength: -1,\n validateStatus: [Function: validateStatus],\n data: undefined\n },\n request: ClientRequest {\n _events: [Object: null prototype],\n _eventsCount: 6,\n _maxListeners: undefined,\n outputData: [],\n outputSize: 0,\n writable: true,\n _last: true,\n chunkedEncoding: false,\n shouldKeepAlive: false,\n useChunkedEncodingByDefault: false,\n sendDate: false,\n _removedConnection: false,\n _removedContLen: false,\n _removedTE: false,\n _contentLength: 0,\n _hasBody: true,\n _trailer: '',\n finished: true,\n _headerSent: true,\n socket: [TLSSocket],\n connection: [TLSSocket],\n _header: 'GET xxxxxx?xxxxxx HTTP/1.1\r\n' +\n 'Accept: application/json\r\n' +\n 'xxxxx: 2e05f7f8-a91f-43a1-b2df-fcde7d142805\r\n' +\n 'Authorization: Bearer eyJraWQiO...lYzsTKpibD3Ek7g\r\n' +\n 'User-Agent: xxxxx\r\n' +\n 'Host: xxxxx\r\n' +\n 'Connection: close\r\n' +\n '\r\n',\n _onPendingData: [Function: noopPendingOutput],\n agent: [Agent],\n socketPath: undefined,\n method: 'GET',\n insecureHTTPParser: undefined,\n path: 'xxxx?xxxx',\n _ended: true,\n res: [IncomingMessage],\n aborted: false,\n timeoutCb: null,\n upgradeOrConnect: false,\n parser: null,\n maxHeadersCount: null,\n reusedSocket: false,\n _redirectable: [Writable],\n [Symbol(kCapture)]: false,\n [Symbol(kNeedDrain)]: false,\n [Symbol(corked)]: 0,\n [Symbol(kOutHeaders)]: [Object: null prototype]\n },\n data: {\n httpCode: '400',\n httpMessage: 'Bad Request',\n moreInformation: 'Incorrect xxxxx'\n }\n },\n isAxiosError: true,\n toJSON: [Function]\n}\n2020-04-09T01:50:37.366Z\te1a71ea4-44d8-40cc-9c1c-eddd53dc84ae\tERROR\tInvoke Error \t{"errorType":"Error","errorMessage":"{\"error\":\"Incorrect xxxxx\",\"source\":\"xxxxx\",\"key\":\"BAD_REQUEST\"}","stack":["Error: {\"error\":\"Incorrect xxxxx\",\"source\":\"xxxxx\",\"key\":\"BAD_REQUEST\"}"," at _homogeneousError (/var/runtime/CallbackContext.js:13:12)"," at postError (/var/runtime/CallbackContext.js:30:54)"," at callback (/var/runtime/CallbackContext.js:42:7)"," at /var/runtime/CallbackContext.js:105:16"," at /var/task/bb_index.js:63:9"," at Object.module.exports [as client_search] (/var/task/client_search.js:116:5)"," at processTicksAndRejections (internal/process/task_queues.js:97:5)"]}\nEND RequestId: e1a71ea4-44d8-40cc-9c1c-eddd53dc84ae\nREPORT RequestId: e1a71ea4-44d8-40cc-9c1c-eddd53dc84ae\tDuration: 116.83 ms\tBilled Duration: 200 ms\tMemory Size: 128 MB\tMax Memory Used: 95 MB\t\n",
"error": "Unhandled",
"status": 200
}
In "src/app/controllers/ContextMenuController.java" you reference an ongoing issue where you can receive the incorrect request/response pair if the original request was edited. This should be fixed in our upcoming release of 2021.12. I also noticed that you made reference to the Extender API version of 1.7.22 - we do have some more recent Extender API versions that can be found here: https://mvnrepository.com/artifact/net.portswigger.burp.extender/burp-extender-api
Additionally, in some other places I noticed that you appear to be using HTML within Swing components. Just so that you are aware, we're planning on disabling HTML rendering within Swing components in a later release of Burp.
I noticed this in a few places in your update:
Thanks for this tool. The tool does not honor whitespaces, though. I know, you probably thought nobody would ever do that, but believe me, they do. So simply put, when I chose "do not automatically modify signature" and the header of the original JWT token starts with:
{"alg":"HS256","typ" : "JWT"
[...]
Then your tool will automatically decode and recreate the JWT token with the following header:
{"alg":"HS256","typ":"JWT"
[...]
Please note how the spaces before and after the colon are now missing. Obviously, this breaks the signature of the JWT token and makes tests hard.
I'd recommend implementing checks in the tool, that allows recreating a part of the JWT (such as the header) and then compare the base64 generated value with the original value. If they are not the same, then your tool is not recreating the JWT correctly.
Please be also aware that the above example is real life. They managed to have no spaces before and after the colon of the alg
parameter, but they do have spaces for the typ
parameter...
Problem description:
Request 1, type in JWT secret
Go to request 2, same secret is in the input field
Only the JWT token is replaced
Solution:
Save the GUI state&content per request / response and automatically save & restore on change.
In some cases HMAC key for signing JWT is non-ascii hex string. So we have to support it with JWT4B.
For example U can add in KeyHelper class ( in cleankey or some else method) condition: if key begins from 0x... then key string is been interpreted as hex string.
Observers are deprecated - rewrite the code.
Use MVC for EditableTab Controller and View
The following final constant is assigned incorrectly:
public static final String publicKeyEnd = "-----BEGIN PUBLIC KEY-----";
This should be:
"-----END PUBLIC KEY-----", naturally.
Also, several certs export with the format "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----"
Thanks for the great extension, BTW.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.