HTB Academy broken API:s challange #3
HTB Academy broken API:s challange #3: Work through a simple REST‑style API that exposes table/row paths and supports CRUD over HTTP. Use curl + jq to read, create, update, and delete entries — and finish by renaming a city to flag and retrieving the flag. • HTB Academy • crud, curl
🎯 Objective
Work through a simple REST‑style API that exposes table/row paths and supports CRUD over HTTP. Use curl + jq to read, create, update, and delete entries — and finish by renaming a city to flag and retrieving the flag.
🧩 Quick refresher — APIs & CRUD
Some APIs map database entities directly into URL paths, e.g. /<table>/<row-id>, and rely on HTTP methods to choose the operation.
Example endpoint pattern
/api.php/<table>/<row>CRUD mapping
| Operation | Method | What it does |
|---|---|---|
| Create | POST | Adds a new row |
| Read | GET | Fetches rows |
| Update | PUT | Replaces a row (full update) |
| (Partial) | PATCH | Modifies fields (partial update) |
| Delete | DELETE | Removes a row |
Not all APIs behave exactly the same (authZ rules, PATCH vs PUT semantics, etc.). Many require cookies or an
Authorizationheader (e.g., JWT) to write.
🔎 Read
Fetch a single city by key (nice‑print with jq):
curl -s http://<SERVER_IP>:<PORT>/api.php/city/london | jq
# [
# { "city_name": "London", "country_name": "(UK)" }
# ]Prefix search (returns all matches):
curl -s http://<SERVER_IP>:<PORT>/api.php/city/le | jq
# [
# { "city_name": "Leeds", "country_name": "(UK)" },
# { "city_name": "Dudley", "country_name": "(UK)" },
# { "city_name": "Leicester", "country_name": "(UK)" },
# ...
# ]List all entries (empty tail element after city/):
curl -s http://<SERVER_IP>:<PORT>/api.php/city/ | jq
# [ { "city_name": "London", ... }, ... ]➕ Create
POST JSON and set content type:
curl -X POST http://<SERVER_IP>:<PORT>/api.php/city/ -d '{"city_name":"HTB_City","country_name":"HTB"}' -H 'Content-Type: application/json'Verify:
curl -s http://<SERVER_IP>:<PORT>/api.php/city/HTB_City | jq
# [
# { "city_name": "HTB_City", "country_name": "HTB" }
# ]✏️ Update
Full replacement with PUT (specify target row in the URL):
curl -X PUT http://<SERVER_IP>:<PORT>/api.php/city/london -d '{"city_name":"New_HTB_City","country_name":"HTB"}' -H 'Content-Type: application/json'Confirm old vs new:
curl -s http://<SERVER_IP>:<PORT>/api.php/city/london | jq
curl -s http://<SERVER_IP>:<PORT>/api.php/city/New_HTB_City | jq
# [ { "city_name": "New_HTB_City", "country_name": "HTB" } ]Some APIs “upsert” on PUT (create if missing). In this lab, updating a non‑existing key returns empty/no-op — try it and observe.
🗑️ Delete
Delete by key:
curl -X DELETE http://<SERVER_IP>:<PORT>/api.php/city/New_HTB_City
curl -s http://<SERVER_IP>:<PORT>/api.php/city/New_HTB_City | jq # => []Tip – include status code in output
curl -sw '%{http_code}
' -X DELETE http://<SERVER_IP>:<PORT>/api.php/city/boston
curl -sw '%{http_code}
' -X DELETE http://<SERVER_IP>:<PORT>/api.php/city/london
curl -sw '%{http_code}
' -X DELETE http://<SERVER_IP>:<PORT>/api.php/city/baltimoreScreenshots (my run):

🏁 Challenge — rename to flag and find it
- Update a city’s name to
flag(I used “Boston”):curl -X PUT http://134.209.21.176:32526/api.php/city/boston -d '{"city_name":"flag","country_name":"HTB"}' -H 'Content-Type: application/json' - Delete a couple cities (optional cleanup):
curl -sw '%{http_code} ' -X DELETE http://134.209.21.176:32526/api.php/city/boston curl -sw '%{http_code} ' -X DELETE http://134.209.21.176:32526/api.php/city/london curl -sw '%{http_code} ' -X DELETE http://134.209.21.176:32526/api.php/city/baltimore - Search for
flag:curl -s http://134.209.21.176:32526/api.php/city/flag | jq
🧪 Troubleshooting
- Empty array? Key doesn’t exist; check path/case; try listing all and grep.
- 415/400 errors? Wrong/missing
Content-Type: application/jsonor malformed JSON. - 401/403? API requires auth (cookie/JWT). Re-run with
-H 'Authorization: Bearer <jwt>'or-b 'session=<cookie>'. - PUT vs PATCH: Server may accept only one; use
OPTIONSor check docs. - Order of fields: JSON is unordered — server shouldn’t care.
📎 Handy one‑liners
# Pretty-print JSON and fail on HTTP errors
curl -fsS http://host/api.php/city/ | jq
# Show only HTTP code
curl -o /dev/null -s -w '%{http_code}
' http://host/api.php/city/london
# Create, then immediately read back
curl -sS -X POST http://host/api.php/city/ -H 'Content-Type: application/json' -d '{"city_name":"TMP","country_name":"XX"}' && curl -sS http://host/api.php/city/TMP | jq✅ Result
I exercised the full CRUD path with curl + jq, verified status codes, and completed the task by renaming a city to flag and retrieving it.
Comments
Comments
Loading comments…