PicoCTF - Java Code Analysis!?!
Background
JWT
Source code
Too Much to list
Hint
- Maybe try to find the JWT Signing Key (“secret key”) in the source code? Maybe it’s hardcoded somewhere? Or maybe try to crack it?
- The ‘role’ and ‘userId’ fields in the JWT can be of interest to you!
- The ‘controllers’, ‘services’ and ‘security’ java packages in the given source code might need your attention. We’ve provided a README.md file that contains some documentation.
- Upgrade your ‘role’ with the new (cracked) JWT. And re-login for the new role to get reflected in browser’s localStorage.
Recon
這一題在AIS3 pre-exam的時候也有看到,但當時根本沒想法,只要題目看起來一複雜我就沒辦法分析了,所以還是看了Martin大的WP才知道解法,但有時候真的很考驗耐心,先看hint發現應該是考跟JWT有關
- 先用user/user登入觀察整個網站
發現書架上只有三本書,而且個別的權限都標註在上面(Free/Premium/Admin),看起來我們的目標是把自己的權限變成admin然後查看flag這本書
- JWT Token
用online tool查看的結果如下,首要目標是找到HS256的secret key
Exploit - JWT
- 找Secret key
隨便找找,發現在
./src/main/java/io/github/nandandesai/pico/security/models/SecretGenerator.java
的SecretGenerator class :::spoiler Source Codepackage io.github.nandandesai.pico.security; import io.github.nandandesai.pico.configs.UserDataPaths; import io.github.nandandesai.pico.utils.FileOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.nio.charset.Charset; @Service class SecretGenerator { private Logger logger = LoggerFactory.getLogger(SecretGenerator.class); private static final String SERVER_SECRET_FILENAME = "server_secret.txt"; @Autowired private UserDataPaths userDataPaths; private String generateRandomString(int len) { // not so random return "1234"; } String getServerSecret() { try { String secret = new String(FileOperation.readFile(userDataPaths.getCurrentJarPath(), SERVER_SECRET_FILENAME), Charset.defaultCharset()); logger.info("Server secret successfully read from the filesystem. Using the same for this runtime."); return secret; }catch (IOException e){ logger.info(SERVER_SECRET_FILENAME+" file doesn't exists or something went wrong in reading that file. Generating a new secret for the server."); String newSecret = generateRandomString(32); try { FileOperation.writeFile(userDataPaths.getCurrentJarPath(), SERVER_SECRET_FILENAME, newSecret.getBytes()); } catch (IOException ex) { ex.printStackTrace(); } logger.info("Newly generated secret is now written to the filesystem for persistence."); return newSecret; } } }
::: 可以發現作者的註解說not so random,secret key是1234,把key拿到jwt online decoder做驗證,發現signature是正確的
- Construct a Fake Token
根據hint的說明,我們應該只要改userId和role這兩個欄位如下,切記也要改token-payload如下,就可以更改自己的權限
Flag: picoCTF{w34k_jwt_n0t_g00d_6e5d7df5}