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:
Nik Bougalis
2020-04-25 00:27:23 -07:00
parent 2827de4d63
commit 6c72d5cf7e
4 changed files with 23 additions and 38 deletions

View File

@@ -171,18 +171,11 @@ struct ValidatorToken
{
std::string manifest;
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 {
/// Manifest is valid
accepted = 0,

View File

@@ -240,52 +240,44 @@ Manifest::getMasterSignature() const
return st.getFieldVL(sfMasterSignature);
}
ValidatorToken::ValidatorToken(std::string const& m, SecretKey const& valSecret)
: manifest(m), validationSecret(valSecret)
{
}
boost::optional<ValidatorToken>
ValidatorToken::make_ValidatorToken(std::vector<std::string> const& tokenBlob)
loadValidatorToken(std::vector<std::string> const& blob)
{
try
{
std::string tokenStr;
tokenStr.reserve(std::accumulate(
tokenBlob.cbegin(),
tokenBlob.cend(),
blob.cbegin(),
blob.cend(),
std::size_t(0),
[](std::size_t init, std::string const& s) {
return init + s.size();
}));
for (auto const& line : tokenBlob)
for (auto const& line : blob)
tokenStr += beast::rfc2616::trim(line);
tokenStr = base64_decode(tokenStr);
Json::Reader r;
Json::Value token;
if (!r.parse(tokenStr, token))
return boost::none;
if (token.isMember("manifest") && token["manifest"].isString() &&
token.isMember("validation_secret_key") &&
token["validation_secret_key"].isString())
if (r.parse(tokenStr, token))
{
auto const ret =
strUnHex(token["validation_secret_key"].asString());
if (!ret || ret->empty())
return boost::none;
auto const m = token.get("manifest", Json::Value{});
auto const k = token.get("validation_secret_key", Json::Value{});
return ValidatorToken(
token["manifest"].asString(),
SecretKey(Slice{ret->data(), ret->size()}));
}
else
{
return boost::none;
if (m.isString() && k.isString())
{
auto const key = strUnHex(k.asString());
if (key && key->size() == 32)
return ValidatorToken{m.asString(), makeSlice(*key)};
}
}
return boost::none;
}
catch (std::exception const&)
{

View File

@@ -39,7 +39,7 @@ ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j)
if (config.exists(SECTION_VALIDATOR_TOKEN))
{
if (auto const token = ValidatorToken::make_ValidatorToken(
if (auto const token = loadValidatorToken(
config.section(SECTION_VALIDATOR_TOKEN).lines()))
{
auto const pk =

View File

@@ -534,14 +534,14 @@ public:
"r7C0kw"
"2AiTzSCjIzditQ8=";
auto const token = ValidatorToken::make_ValidatorToken(tokenBlob);
auto const token = loadValidatorToken(tokenBlob);
BEAST_EXPECT(token);
BEAST_EXPECT(token->validationSecret == *valSecret);
BEAST_EXPECT(token->manifest == manifest);
}
{
std::vector<std::string> const badToken = {"bad token"};
BEAST_EXPECT(!ValidatorToken::make_ValidatorToken(badToken));
BEAST_EXPECT(!loadValidatorToken(badToken));
}
}