CVE: CVE-2021-0218
Tested Versions:
- Junos OS 20.1R1.11
Product URL(s):
Description of the vulnerability
license-check
is a daemon to manage license in Juniper device. By default, this daemon is running as root. There is a command injection vulnerability in license-check
daemon that allows an attacker with low privilege to execute a command with root privilege.
The command injection exists in the license update feature. To update license, user run command request system license update
in cli console. First, when run this command, the mgd_update_license()
function in /usr/lib/dd/libjunos-actions-impl.so
is called.
int __cdecl mgd_update_license(int a1)
{
v1 = *(_DWORD *)(*(_DWORD *)(a1 + 52) + 61688);
if ( !(unsigned __int8)license_is_nextgen_infra_active() )
{
v11 = v1;
v2 = ddl_get_value_length(a1, "trial", 0);
v13 = ddl_get_value_string(a1, (int)"trial", 0, ((unsigned int)&v10 - ((v2 + 3) & 0xFFFFFFFC)) & 0xFFFFFFF0, v2);
v3 = ddl_get_value_length(a1, "url", 0);
v12 = (const char *)ddl_get_value_string(
a1,
(int)"url",
0,
((unsigned int)&v10 - ((v3 + 3) & 0xFFFFFFFC)) & 0xFFFFFFF0,
v3);
v4 = fopen("/tmp/.autoupdate", "w");
if ( v4 )
{
if ( v12 )
fputs(v12, v4);
else
fwrite("https://ae1.juniper.net/junos/key_retrieval", 0x2Bu, 1u, v4);
fclose(v4);
}
if ( v13 )
daemon_request_signal((int)"license-check", 31, 0, 0, 0, 1);
else
daemon_request_signal((int)"license-check", 30, 0, 0, 0, 1);
If value of "url"
is specified, function write this value to file "/tmp/.autoupdate"
. If not, "https://ae1.juniper.net/junos/key_retrieval"
is written. Then, function send signal to license-check
daemon. When receive signal, lc_fetch_license_keys()
function in license-check
is called.
int lc_fetch_license_keys()
{
memset(&s, 0, 0x400u);
v0 = fopen("/tmp/.autoupdate", "r");
if ( v0 )
{
memset(&command, 0, 0x400u);
fgets(&command, 1024, v0);
v1 = strlen(&command);
if ( v1 > 0 )
{
v2 = v1 + 1;
do
{
v3 = *((_BYTE *)&v6 + v2 + 3);
if ( v3 != '\r' && v3 != '\n' )
break;
*((_BYTE *)&v6 + v2-- + 3) = 0;
}
while ( v2 > 1 );
}
strlcpy(&s, &command, 1024);
fclose(v0);
memset(&command, 0, 0x400u);
v6 = "/tmp/.autoupdate";
snprintf(&command, 0x400u, "/bin/rm -f %s", "/tmp/.autoupdate");
system(&command);
if ( s )
return sub_8358ED0((int)&s);
The above function reads content from "/tmp/.autoupdate"
to buffer s
, then removes file "/tmp/.autoupdate"
. Next, buffer s
is passed to sub_8358ED0()
function:
__pid_t __fastcall sub_8358ED0(int a1) {
v28 = a1;
...
v21 = &command[strlen(command)];
if ( v20 == 2 )
snprintf(
v21,
0x400u,
"/usr/sbin/license_fetch -o /tmp/license.keys.%d '%s?serial=%s&version=%s&trial=1' 2> %s",
v27,
v28,
v3,
&s,
&filename);
else
snprintf(
v21,
0x400u,
"/usr/sbin/license_fetch -o /tmp/license.keys.%d '%s?serial=%s&version=%s' 2> %s",
v27,
v28,
v3,
&s,
&filename);
system(command);
The system() function is called with the command which is built from buffer s
. Because there is no validate function is called to sanitise buffer s
, so it could lead to a command injection vulnerability if an attacker could control data in buffer s
(read from "/tmp/.autoupdate"
file).
The exploitation
- Control content in
"/tmp/.autoupdate"
The "/tmp/.autoupdate"
is created and written in mgd_update_license()
function. An attacker can control the content of this file through the "url"
parameter in the command request system license update. Alternatively, if an attacker only has a lower privilege user, he could directly create "/tmp/.autoupdate"
in "/tmp"
directory because any user can create file in "/tmp"
directory. Next, when update license, mgd_update_license()
function writes content to file just create. We can invoke the function in the license-check daemon by sending a signal, it takes a certain amount of time from the time the file was written until the lc_fetch_license_keys()
function is called, and during that period of time, content in this file could be overwritten.
-
To summarise, in order to exploit this vulnerability, there are two scenarios:
-
An attacker has a user with privilege at least “maintenance” (to run request system license update command).
-
An attacker only has a user with
"shell"
privilege (only permission to start shell). However, it requires that the automatic license update feature is enabled in the system if this feature is enabled, the system will autorunrequest system license update
command after a period.For ease of visualisation, PoC simulates an automatic update license in the system by running the
request system license update
command. The while loop is used to constantly create and write to"/tmp/.autoupdate"
file, purpose to overwrite to content which is written bymgd_update_license()
function in this file.
-
timeline
- 2020-06-12 Reported to Vendor, Vendor acknowledged on same day
- 2021-01-12 Vendor patched the vulnerability