mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-20 10:35:50 +00:00
Improve loading of validator tokens (RIPD-1687):
A deliberately malformed token can cause the server to crash during
startup. This is not remotely exploitable and would require someone
with access to the configuration file of the server to make changes
and then restart the server.
Acknowledgements:
Guido Vranken for responsibly disclosing this issue.
Bug Bounties and Responsible Disclosures:
We welcome reviews of the rippled code and urge researchers to
responsibly disclose any issues they may find.
Ripple is generously sponsoring a bug bounty program for the
rippled project. For more information please visit:
https://ripple.com/bug-bounty
This commit is contained in:
@@ -171,18 +171,11 @@ struct ValidatorToken
|
|||||||
{
|
{
|
||||||
std::string manifest;
|
std::string manifest;
|
||||||
SecretKey validationSecret;
|
SecretKey validationSecret;
|
||||||
|
|
||||||
private:
|
|
||||||
ValidatorToken(std::string const& m, SecretKey const& valSecret);
|
|
||||||
|
|
||||||
public:
|
|
||||||
ValidatorToken(ValidatorToken const&) = delete;
|
|
||||||
ValidatorToken(ValidatorToken&& other) = default;
|
|
||||||
|
|
||||||
static boost::optional<ValidatorToken>
|
|
||||||
make_ValidatorToken(std::vector<std::string> const& tokenBlob);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
boost::optional<ValidatorToken>
|
||||||
|
loadValidatorToken(std::vector<std::string> const& blob);
|
||||||
|
|
||||||
enum class ManifestDisposition {
|
enum class ManifestDisposition {
|
||||||
/// Manifest is valid
|
/// Manifest is valid
|
||||||
accepted = 0,
|
accepted = 0,
|
||||||
|
|||||||
@@ -240,52 +240,44 @@ Manifest::getMasterSignature() const
|
|||||||
return st.getFieldVL(sfMasterSignature);
|
return st.getFieldVL(sfMasterSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidatorToken::ValidatorToken(std::string const& m, SecretKey const& valSecret)
|
|
||||||
: manifest(m), validationSecret(valSecret)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<ValidatorToken>
|
boost::optional<ValidatorToken>
|
||||||
ValidatorToken::make_ValidatorToken(std::vector<std::string> const& tokenBlob)
|
loadValidatorToken(std::vector<std::string> const& blob)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::string tokenStr;
|
std::string tokenStr;
|
||||||
|
|
||||||
tokenStr.reserve(std::accumulate(
|
tokenStr.reserve(std::accumulate(
|
||||||
tokenBlob.cbegin(),
|
blob.cbegin(),
|
||||||
tokenBlob.cend(),
|
blob.cend(),
|
||||||
std::size_t(0),
|
std::size_t(0),
|
||||||
[](std::size_t init, std::string const& s) {
|
[](std::size_t init, std::string const& s) {
|
||||||
return init + s.size();
|
return init + s.size();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (auto const& line : tokenBlob)
|
for (auto const& line : blob)
|
||||||
tokenStr += beast::rfc2616::trim(line);
|
tokenStr += beast::rfc2616::trim(line);
|
||||||
|
|
||||||
tokenStr = base64_decode(tokenStr);
|
tokenStr = base64_decode(tokenStr);
|
||||||
|
|
||||||
Json::Reader r;
|
Json::Reader r;
|
||||||
Json::Value token;
|
Json::Value token;
|
||||||
if (!r.parse(tokenStr, token))
|
|
||||||
return boost::none;
|
|
||||||
|
|
||||||
if (token.isMember("manifest") && token["manifest"].isString() &&
|
if (r.parse(tokenStr, token))
|
||||||
token.isMember("validation_secret_key") &&
|
|
||||||
token["validation_secret_key"].isString())
|
|
||||||
{
|
{
|
||||||
auto const ret =
|
auto const m = token.get("manifest", Json::Value{});
|
||||||
strUnHex(token["validation_secret_key"].asString());
|
auto const k = token.get("validation_secret_key", Json::Value{});
|
||||||
if (!ret || ret->empty())
|
|
||||||
return boost::none;
|
|
||||||
|
|
||||||
return ValidatorToken(
|
if (m.isString() && k.isString())
|
||||||
token["manifest"].asString(),
|
{
|
||||||
SecretKey(Slice{ret->data(), ret->size()}));
|
auto const key = strUnHex(k.asString());
|
||||||
}
|
|
||||||
else
|
if (key && key->size() == 32)
|
||||||
{
|
return ValidatorToken{m.asString(), makeSlice(*key)};
|
||||||
return boost::none;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j)
|
|||||||
|
|
||||||
if (config.exists(SECTION_VALIDATOR_TOKEN))
|
if (config.exists(SECTION_VALIDATOR_TOKEN))
|
||||||
{
|
{
|
||||||
if (auto const token = ValidatorToken::make_ValidatorToken(
|
if (auto const token = loadValidatorToken(
|
||||||
config.section(SECTION_VALIDATOR_TOKEN).lines()))
|
config.section(SECTION_VALIDATOR_TOKEN).lines()))
|
||||||
{
|
{
|
||||||
auto const pk =
|
auto const pk =
|
||||||
|
|||||||
@@ -534,14 +534,14 @@ public:
|
|||||||
"r7C0kw"
|
"r7C0kw"
|
||||||
"2AiTzSCjIzditQ8=";
|
"2AiTzSCjIzditQ8=";
|
||||||
|
|
||||||
auto const token = ValidatorToken::make_ValidatorToken(tokenBlob);
|
auto const token = loadValidatorToken(tokenBlob);
|
||||||
BEAST_EXPECT(token);
|
BEAST_EXPECT(token);
|
||||||
BEAST_EXPECT(token->validationSecret == *valSecret);
|
BEAST_EXPECT(token->validationSecret == *valSecret);
|
||||||
BEAST_EXPECT(token->manifest == manifest);
|
BEAST_EXPECT(token->manifest == manifest);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::vector<std::string> const badToken = {"bad token"};
|
std::vector<std::string> const badToken = {"bad token"};
|
||||||
BEAST_EXPECT(!ValidatorToken::make_ValidatorToken(badToken));
|
BEAST_EXPECT(!loadValidatorToken(badToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user