PicoCTF - Java Code Analysis!?!

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有關

  1. 先用user/user登入觀察整個網站 發現書架上只有三本書,而且個別的權限都標註在上面(Free/Premium/Admin),看起來我們的目標是把自己的權限變成admin然後查看flag這本書
  2. JWT Token 用online tool查看的結果如下,首要目標是找到HS256的secret key

Exploit - JWT

  1. 找Secret key 隨便找找,發現在./src/main/java/io/github/nandandesai/pico/security/models/SecretGenerator.java的SecretGenerator class :::spoiler Source Code
     package 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是正確的

  2. Construct a Fake Token 根據hint的說明,我們應該只要改userId和role這兩個欄位如下,切記也要改token-payload如下,就可以更改自己的權限

Flag: picoCTF{w34k_jwt_n0t_g00d_6e5d7df5}

Reference

picoCTF 2023 Java Code Analysis?!?