Testing for windows service
This commit is contained in:
327
ctrlsrv.py
Executable file
327
ctrlsrv.py
Executable file
@@ -0,0 +1,327 @@
|
||||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyvncs
|
||||
from lib import log
|
||||
from lib import common
|
||||
from argparse import ArgumentParser
|
||||
from threading import Thread
|
||||
import time
|
||||
import sys
|
||||
import socket
|
||||
import signal
|
||||
import readline
|
||||
import traceback
|
||||
|
||||
#_debug = log.debug
|
||||
_debug = print
|
||||
|
||||
if common.isWindows():
|
||||
_debug("Wintendo...")
|
||||
import win32ts
|
||||
import win32security
|
||||
import win32con
|
||||
import win32api
|
||||
import ntsecuritycon
|
||||
import win32process
|
||||
import win32event
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
_debug("Exiting on signal %s..." % signal)
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
config = {
|
||||
}
|
||||
|
||||
class ControlThread(Thread):
|
||||
def __init__(self, threads):
|
||||
Thread.__init__(self)
|
||||
self.threads = threads
|
||||
self.setDaemon(True)
|
||||
|
||||
def run(self):
|
||||
# elimina los threads muertos
|
||||
while True:
|
||||
time.sleep(1)
|
||||
for t in threads:
|
||||
if not t.isAlive():
|
||||
_debug("ControlThread removing dead", t)
|
||||
threads.remove(t)
|
||||
|
||||
class VNCThread(Thread):
|
||||
def __init__(self, port, password):
|
||||
Thread.__init__(self)
|
||||
self.ip = None
|
||||
self.port = port
|
||||
self.sock = None
|
||||
self.password = password
|
||||
self.setDaemon(True)
|
||||
|
||||
def __del__(self):
|
||||
_debug("VNCThread died")
|
||||
|
||||
|
||||
def run(self):
|
||||
|
||||
TCP_IP = '0.0.0.0'
|
||||
_debug("[+] Listen...")
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.sock.bind((TCP_IP, int(self.port)))
|
||||
self.sock.listen(4)
|
||||
(conn, (ip,port)) = self.sock.accept()
|
||||
|
||||
_debug("[+] New server socket started for " + ip + ":" + str(port))
|
||||
#_debug("Thread", self)
|
||||
server = pyvncs.server.VncServer(conn, self.password)
|
||||
#server.CONFIG._8bitdither = CONFIG._8bitdither
|
||||
status = server.init()
|
||||
|
||||
if not status:
|
||||
_debug("Error negotiating client init")
|
||||
return False
|
||||
server.protocol()
|
||||
|
||||
|
||||
class ClientThread(Thread):
|
||||
def __init__(self, sock, ip, port, config):
|
||||
Thread.__init__(self)
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
self.sock = sock
|
||||
self.setDaemon(True)
|
||||
self.config = config
|
||||
|
||||
def __del__(self):
|
||||
_debug("ClientThread died")
|
||||
|
||||
def run(self):
|
||||
#_debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
|
||||
#_debug("Thread", self)
|
||||
f = self.sock.makefile('rw')
|
||||
|
||||
f.write("AUTH:>")
|
||||
f.flush()
|
||||
passwd = f.readline().strip("\n")
|
||||
if passwd != config["PASSWORD"]:
|
||||
time.sleep(1)
|
||||
f.write("!NO AUTH")
|
||||
f.flush()
|
||||
_debug("NO AUTH '%s' != '%s'" % (passwd, config["PASSWORD"]))
|
||||
self.sock.close()
|
||||
return
|
||||
|
||||
while True:
|
||||
f.write("OK:>")
|
||||
f.flush()
|
||||
try:
|
||||
data = f.readline()
|
||||
cmd = data.strip()
|
||||
if not data: break
|
||||
|
||||
if cmd == "_DEBUG":
|
||||
sys.stdout = sys.stderr = f
|
||||
f.write("OK\n")
|
||||
|
||||
elif cmd == "PING":
|
||||
f.write("PONG\n")
|
||||
|
||||
elif cmd == "QUIT":
|
||||
f.write("BYE\n")
|
||||
self.sock.close()
|
||||
return
|
||||
|
||||
elif cmd.startswith("STARTVNC"):
|
||||
params = cmd.split()
|
||||
if len(params) != 3:
|
||||
f.write("!NOT_PARAMS\n")
|
||||
f.flush()
|
||||
continue
|
||||
_debug("START VNC !!!")
|
||||
newthread = VNCThread(params[1], params[2])
|
||||
newthread.setDaemon(True)
|
||||
newthread.start()
|
||||
|
||||
elif cmd == "_WINSESSIONS" and common.isWindows():
|
||||
winsessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
|
||||
print(winsessions, file=f)
|
||||
|
||||
elif cmd == "_WINCONSOLE" and common.isWindows():
|
||||
winsessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
|
||||
print(winsessions, file=f)
|
||||
active = win32ts.WTSGetActiveConsoleSessionId()
|
||||
print(active, file=f)
|
||||
token = win32ts.WTSQueryUserToken(active)
|
||||
print(token, file=f)
|
||||
duplicated = win32security.DuplicateTokenEx(token, win32con.MAXIMUM_ALLOWED, win32con.NULL, win32security.TokenPrimary, win32security.SECURITY_ATTRIBUTES())
|
||||
print("duplicated", token, file=f)
|
||||
|
||||
elif cmd == "_TEST" and common.isWindows():
|
||||
winsessions = win32ts.WTSEnumerateSessions(win32ts.WTS_CURRENT_SERVER_HANDLE)
|
||||
print(winsessions, file=f)
|
||||
active = win32ts.WTSGetActiveConsoleSessionId()
|
||||
print(active, file=f)
|
||||
token = win32ts.WTSQueryUserToken(active)
|
||||
print("token", token, file=f)
|
||||
ntoken = win32security.DuplicateTokenEx(token, 3 , win32con.MAXIMUM_ALLOWED , win32security.TokenPrimary , win32security.SECURITY_ATTRIBUTES() )
|
||||
print("ntoken", ntoken, file=f)
|
||||
#th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32con.MAXIMUM_ALLOWED)
|
||||
#print("th", th, file=f)
|
||||
shell_as2(ntoken, True, "cmd")
|
||||
|
||||
elif cmd == "_EVAL":
|
||||
while True:
|
||||
f.write("EV:>")
|
||||
f.flush()
|
||||
data = f.readline()
|
||||
cmd = data.strip()
|
||||
if cmd == "": continue
|
||||
if cmd == "_QUIT": break
|
||||
if not data: break
|
||||
|
||||
try:
|
||||
eval(data)
|
||||
except:
|
||||
print("ERROR:", sys.exc_info()[0], file=f)
|
||||
print(traceback.format_exc(), file=f)
|
||||
f.flush()
|
||||
|
||||
_debug("eval:", cmd.strip())
|
||||
f.flush()
|
||||
|
||||
elif cmd == "_ERROR":
|
||||
a = 1/0
|
||||
|
||||
else:
|
||||
f.write("!NO_CMD %s\n" % cmd)
|
||||
|
||||
_debug("command:", cmd.strip())
|
||||
f.flush()
|
||||
except:
|
||||
print("ERROR:", sys.exc_info()[0], file=f)
|
||||
print(traceback.format_exc(), file=f)
|
||||
f.flush()
|
||||
|
||||
def get_all_privs(th):
|
||||
# Try to give ourselves some extra privs (only works if we're admin):
|
||||
# SeBackupPrivilege - so we can read anything
|
||||
# SeDebugPrivilege - so we can find out about other processes (otherwise OpenProcess will fail for some)
|
||||
# SeSecurityPrivilege - ??? what does this do?
|
||||
|
||||
# Problem: Vista+ support "Protected" processes, e.g. audiodg.exe. We can't see info about these.
|
||||
# Interesting post on why Protected Process aren't really secure anyway: http://www.alex-ionescu.com/?p=34
|
||||
|
||||
privs = win32security.GetTokenInformation(th, ntsecuritycon.TokenPrivileges)
|
||||
for privtuple in privs:
|
||||
privs2 = win32security.GetTokenInformation(th, ntsecuritycon.TokenPrivileges)
|
||||
newprivs = []
|
||||
for privtuple2 in privs2:
|
||||
if privtuple2[0] == privtuple[0]:
|
||||
newprivs.append((privtuple2[0], 2)) # SE_PRIVILEGE_ENABLED
|
||||
else:
|
||||
newprivs.append((privtuple2[0], privtuple2[1]))
|
||||
|
||||
# Adjust privs
|
||||
privs3 = tuple(newprivs)
|
||||
win32security.AdjustTokenPrivileges(th, False, privs3)
|
||||
def shell_as(th, enable_privs = 0):
|
||||
#t = thread(th)
|
||||
#print(t.as_text())
|
||||
new_tokenh = win32security.DuplicateTokenEx(th, 3 , win32con.MAXIMUM_ALLOWED , win32security.TokenPrimary , win32security.SECURITY_ATTRIBUTES() )
|
||||
print("new_tokenh: %s" % new_tokenh)
|
||||
print("Impersonating...")
|
||||
if enable_privs:
|
||||
get_all_privs(new_tokenh)
|
||||
commandLine = "cmd"
|
||||
si = win32process.STARTUPINFO()
|
||||
print("pysecdump: Starting shell with required privileges...")
|
||||
(hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcessAsUser(
|
||||
new_tokenh,
|
||||
None, # AppName
|
||||
commandLine, # Command line
|
||||
None, # Process Security
|
||||
None, # ThreadSecurity
|
||||
1, # Inherit Handles?
|
||||
win32process.NORMAL_PRIORITY_CLASS,
|
||||
None, # New environment
|
||||
None, # Current directory
|
||||
si) # startup info.
|
||||
win32event.WaitForSingleObject( hProcess, win32event.INFINITE );
|
||||
print("pysecdump: Quitting")
|
||||
|
||||
def shell_as2(new_tokenh, enable_privs = 0, commandLine = "cmd"):
|
||||
print("new_tokenh: %s" % new_tokenh)
|
||||
print("Impersonating...")
|
||||
if enable_privs:
|
||||
get_all_privs(new_tokenh)
|
||||
si = win32process.STARTUPINFO()
|
||||
print("pysecdump: Starting shell with required privileges...")
|
||||
(hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcessAsUser(
|
||||
new_tokenh,
|
||||
None, # AppName
|
||||
commandLine, # Command line
|
||||
None, # Process Security
|
||||
None, # ThreadSecurity
|
||||
1, # Inherit Handles?
|
||||
win32process.NORMAL_PRIORITY_CLASS,
|
||||
None, # New environment
|
||||
None, # Current directory
|
||||
si) # startup info.
|
||||
win32event.WaitForSingleObject( hProcess, win32event.INFINITE )
|
||||
print("pysecdump: Quitting")
|
||||
|
||||
def main(argv):
|
||||
global threads, config
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-l", "--listen-address", dest="TCP_IP",
|
||||
help="Listen in this address, default: %s" % ("0.0.0.0"), required=False, default='0.0.0.0')
|
||||
parser.add_argument("-p", "--port", dest="TCP_PORT",
|
||||
help="Listen in this port, default: %s" % ("5899"), type=int, required=False, default='5899')
|
||||
parser.add_argument("-P", "--password", help="Sets password", required=True, dest="PASSWORD")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
config["PASSWORD"] = args.PASSWORD
|
||||
config["PORT"] = args.TCP_PORT
|
||||
|
||||
sockServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sockServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sockServer.bind((args.TCP_IP, args.TCP_PORT))
|
||||
|
||||
controlthread = ControlThread(threads)
|
||||
controlthread.start()
|
||||
threads.append(controlthread)
|
||||
|
||||
#_debug("Multithreaded Python server : Waiting for connections from TCP clients...")
|
||||
_debug("Runing on:", sys.platform)
|
||||
while True:
|
||||
sockServer.listen(4)
|
||||
(conn, (ip,port)) = sockServer.accept()
|
||||
newthread = ClientThread(conn, ip, port, config)
|
||||
newthread.setDaemon(True)
|
||||
newthread.start()
|
||||
threads.append(newthread)
|
||||
#print(threads)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
threads = []
|
||||
main(sys.argv)
|
||||
68
lib/common.py
Normal file
68
lib/common.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
from multiprocessing import Process, Value
|
||||
import subprocess
|
||||
import os
|
||||
import time
|
||||
import mmap
|
||||
import psutil
|
||||
|
||||
def isWindows():
|
||||
return sys.platform.startswith("win")
|
||||
|
||||
def isOSX():
|
||||
return sys.platform.startswith("darwin")
|
||||
|
||||
def isLinux():
|
||||
return sys.platform.startswith("linux")
|
||||
|
||||
class proc:
|
||||
def __init__(self):
|
||||
self.pid = Value('i', 0)
|
||||
self._process = None
|
||||
|
||||
def __del__(self):
|
||||
pass
|
||||
|
||||
def _setpid(self, pid):
|
||||
self.pid.value = pid
|
||||
|
||||
def getpid(self):
|
||||
return self.pid.value
|
||||
|
||||
def _newproc(self, cmd):
|
||||
pr = subprocess.Popen(cmd)
|
||||
#print("Launched forkproc Process ID:", str(pr.pid))
|
||||
self._setpid(pr.pid)
|
||||
|
||||
def run(self, *cmd):
|
||||
self._process = Process(target=self._newproc, args=(cmd))
|
||||
self._process.start()
|
||||
self._process.join()
|
||||
return self.pid.value
|
||||
|
||||
def terminate(self):
|
||||
if psutil.pid_exists(self.pid.value):
|
||||
p = psutil.Process(self.pid.value)
|
||||
p.terminate()
|
||||
self._process.terminate()
|
||||
|
||||
def waitproc(self):
|
||||
while psutil.pid_exists(self.pid):
|
||||
time.sleep(.25)
|
||||
29
lib/const.py
Normal file
29
lib/const.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
|
||||
# constants workaround
|
||||
class _const:
|
||||
class ConstError(TypeError): pass
|
||||
def __setattr__(self, name, value):
|
||||
if name in self.__dict__.keys():
|
||||
raise (self.ConstError, "Can't rebind const(%s)" % name)
|
||||
self.__dict__[name]=value
|
||||
|
||||
sys.modules[__name__]=_const()
|
||||
|
||||
19
lib/encodings/common.py
Normal file
19
lib/encodings/common.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class ENCODINGS:
|
||||
pass
|
||||
20
lib/encodings/cursor.py
Normal file
20
lib/encodings/cursor.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from . import common
|
||||
|
||||
common.ENCODINGS.cursor = -239
|
||||
32
lib/encodings/raw.py
Normal file
32
lib/encodings/raw.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from . import common
|
||||
from struct import *
|
||||
|
||||
def send_image(x, y, w, h, image):
|
||||
_buff = bytearray()
|
||||
rectangles = 1
|
||||
_buff.extend(pack("!BxH", 0, rectangles))
|
||||
_buff.extend(pack("!HHHH", x, y, w, h))
|
||||
_buff.extend(pack(">i", common.ENCODINGS.raw))
|
||||
_buff.extend( image.tobytes() )
|
||||
|
||||
return _buff
|
||||
|
||||
common.ENCODINGS.raw = 0
|
||||
common.ENCODINGS.raw_send_image = send_image
|
||||
28
lib/log.py
Normal file
28
lib/log.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# coding=utf-8
|
||||
# pyvncs
|
||||
# Copyright (C) 2017-2018 Matias Fernandez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG, format='[%(threadName)s] %(message)s')
|
||||
logger = logging.getLogger('pyvncs')
|
||||
|
||||
|
||||
def debug(*args):
|
||||
str = ""
|
||||
for s in args:
|
||||
str = "%s %s" % (str, s)
|
||||
str = str.strip()
|
||||
logger.debug(str)
|
||||
Binary file not shown.
101
pyvncs/server.py
101
pyvncs/server.py
@@ -29,6 +29,7 @@ import zlib
|
||||
import numpy as np
|
||||
|
||||
from lib.encodings import *
|
||||
from lib import log
|
||||
|
||||
def hexdump(data):
|
||||
str = ""
|
||||
@@ -182,7 +183,7 @@ class VncServer():
|
||||
|
||||
|
||||
def __del__(self):
|
||||
print("VncServer died")
|
||||
log.debug("VncServer died")
|
||||
|
||||
def encrypt(self, key, data):
|
||||
k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
|
||||
@@ -221,7 +222,7 @@ class VncServer():
|
||||
data = sock.recv(1024)
|
||||
except socket.timeout:
|
||||
data = None
|
||||
print("getbuff() timeout")
|
||||
log.debug("getbuff() timeout")
|
||||
|
||||
return data
|
||||
|
||||
@@ -232,15 +233,15 @@ class VncServer():
|
||||
# RFB version handshake
|
||||
data = self.getbuff(30)
|
||||
|
||||
print("init received: '%s'" % data)
|
||||
log.debug("init received: '%s'" % data)
|
||||
server_version = float(self.RFB_VERSION)
|
||||
try:
|
||||
client_version = float(data[4:11])
|
||||
except:
|
||||
print("Error parsing client version")
|
||||
log.debug("Error parsing client version")
|
||||
return False
|
||||
|
||||
print("client, server:", client_version, server_version)
|
||||
log.debug("client, server:", client_version, server_version)
|
||||
|
||||
# security types handshake
|
||||
sendbuff = pack("B", len(self.sectypes)) # number of security types
|
||||
@@ -254,13 +255,13 @@ class VncServer():
|
||||
sectype = None
|
||||
|
||||
if sectype not in self.sectypes:
|
||||
print("Incompatible security type: %s" % data)
|
||||
log.debug("Incompatible security type: %s" % data)
|
||||
sock.send(pack("B", 1)) # failed handshake
|
||||
self.sendmessage("Incompatible security type")
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
print("sec type data: %s" % data)
|
||||
log.debug("sec type data: %s" % data)
|
||||
|
||||
# VNC Auth
|
||||
if sectype == 2:
|
||||
@@ -278,9 +279,9 @@ class VncServer():
|
||||
if data == crypted:
|
||||
# Handshake successful
|
||||
sock.send(pack("I", 0))
|
||||
print("Auth OK")
|
||||
log.debug("Auth OK")
|
||||
else:
|
||||
print("Invalid auth")
|
||||
log.debug("Invalid auth")
|
||||
return False
|
||||
|
||||
#unsupported VNC auth type
|
||||
@@ -289,7 +290,7 @@ class VncServer():
|
||||
|
||||
# get ClientInit
|
||||
data = self.getbuff(30)
|
||||
print("Clientinit (shared flag)", repr(data))
|
||||
log.debug("Clientinit (shared flag)", repr(data))
|
||||
|
||||
self.ServerInit()
|
||||
|
||||
@@ -300,9 +301,9 @@ class VncServer():
|
||||
|
||||
sock = self.socket
|
||||
screen = ImageGrab.grab()
|
||||
print("screen", repr(screen))
|
||||
log.debug("screen", repr(screen))
|
||||
size = screen.size
|
||||
print("size", repr(size))
|
||||
log.debug("size", repr(size))
|
||||
del screen
|
||||
|
||||
width = size[0]
|
||||
@@ -339,8 +340,8 @@ class VncServer():
|
||||
sendbuff += pack("!I", desktop_name_len)
|
||||
sendbuff += desktop_name.encode()
|
||||
|
||||
print("width", repr(width))
|
||||
print("height", repr(height))
|
||||
log.debug("width", repr(width))
|
||||
log.debug("height", repr(height))
|
||||
|
||||
sock.send(sendbuff)
|
||||
|
||||
@@ -437,7 +438,7 @@ class VncServer():
|
||||
kbdmap[0xffe2] = keyboard.Key.shift
|
||||
|
||||
while True:
|
||||
#print(".", end='', flush=True)
|
||||
#log.debug(".", end='', flush=True)
|
||||
r,_,_ = select.select([self.socket],[],[],0)
|
||||
if r == []:
|
||||
#no data
|
||||
@@ -448,10 +449,10 @@ class VncServer():
|
||||
try:
|
||||
data = sock.recv(1) # read first byte
|
||||
except socket.timeout:
|
||||
#print("timeout")
|
||||
#log.debug("timeout")
|
||||
continue
|
||||
except Exception as e:
|
||||
print("exception '%s'" % e)
|
||||
log.debug("exception '%s'" % e)
|
||||
sock.close()
|
||||
break
|
||||
|
||||
@@ -462,40 +463,40 @@ class VncServer():
|
||||
|
||||
if data[0] == 0: # client SetPixelFormat
|
||||
data2 = sock.recv(19, socket.MSG_WAITALL)
|
||||
print("Client Message Type: Set Pixel Format (0)")
|
||||
log.debug("Client Message Type: Set Pixel Format (0)")
|
||||
(self.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum,
|
||||
self.green_maximum, self.blue_maximum,
|
||||
self.red_shift, self.green_shift, self.blue_shift
|
||||
) = unpack("!xxxBBBBHHHBBBxxx", data2)
|
||||
print("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor)
|
||||
print("SHIFTS", self.red_shift, self.green_shift, self.blue_shift)
|
||||
print("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum)
|
||||
log.debug("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor)
|
||||
log.debug("SHIFTS", self.red_shift, self.green_shift, self.blue_shift)
|
||||
log.debug("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum)
|
||||
|
||||
if self.red_shift > self.blue_shift:
|
||||
self.primaryOrder = "rgb"
|
||||
else:
|
||||
self.primaryOrder = "bgr"
|
||||
print("Using order: ", self.primaryOrder)
|
||||
log.debug("Using order: ", self.primaryOrder)
|
||||
|
||||
continue
|
||||
|
||||
if data[0] == 2: # SetEncoding
|
||||
data2 = sock.recv(3)
|
||||
print("Client Message Type: SetEncoding (2)")
|
||||
log.debug("Client Message Type: SetEncoding (2)")
|
||||
(nencodings,) = unpack("!xH", data2)
|
||||
print("SetEncoding: total encodings", repr(nencodings))
|
||||
log.debug("SetEncoding: total encodings", repr(nencodings))
|
||||
data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL)
|
||||
#print("len", len(data2))
|
||||
#log.debug("len", len(data2))
|
||||
self.client_encodings = unpack("!%si" % nencodings, data2)
|
||||
#print("data", repr(self.client_encodings), len(self.client_encodings))
|
||||
#log.debug("data", repr(self.client_encodings), len(self.client_encodings))
|
||||
|
||||
if hasattr(enc.ENCODINGS, "cursor") and enc.ENCODINGS.cursor in self.client_encodings:
|
||||
print("Remote cursor encoding present")
|
||||
log.debug("Remote cursor encoding present")
|
||||
self.remotecursor = True
|
||||
self.cursorchanged = True
|
||||
|
||||
if hasattr(enc.ENCODINGS, "zlib") and enc.ENCODINGS.zlib in self.client_encodings:
|
||||
print("Using zlib encoding")
|
||||
log.debug("Using zlib encoding")
|
||||
self.encoding = enc.ENCODINGS.zlib
|
||||
|
||||
continue
|
||||
@@ -503,10 +504,10 @@ class VncServer():
|
||||
|
||||
if data[0] == 3: # FBUpdateRequest
|
||||
data2 = sock.recv(9, socket.MSG_WAITALL)
|
||||
#print("Client Message Type: FBUpdateRequest (3)")
|
||||
#log.debug("Client Message Type: FBUpdateRequest (3)")
|
||||
#print(len(data2))
|
||||
(incremental, x, y, w, h) = unpack("!BHHHH", data2)
|
||||
#print("RFBU:", incremental, x, y, w, h)
|
||||
#log.debug("RFBU:", incremental, x, y, w, h)
|
||||
self.SendRectangles(sock, x, y, w, h, incremental)
|
||||
|
||||
if self.remotecursor and self.cursorchanged:
|
||||
@@ -519,7 +520,7 @@ class VncServer():
|
||||
data2 = sock.recv(7)
|
||||
# B = U8, L = U32
|
||||
(downflag, key) = unpack("!BxxL", data2)
|
||||
print("KeyEvent", downflag, hex(key))
|
||||
log.debug("KeyEvent", downflag, hex(key))
|
||||
|
||||
# special key
|
||||
if key in kbdmap:
|
||||
@@ -531,9 +532,9 @@ class VncServer():
|
||||
kbdkey = None
|
||||
|
||||
try:
|
||||
print("KEY:", kbdkey)
|
||||
log.debug("KEY:", kbdkey)
|
||||
except:
|
||||
print("KEY: (unprintable)")
|
||||
log.debug("KEY: (unprintable)")
|
||||
|
||||
try:
|
||||
if downflag:
|
||||
@@ -541,7 +542,7 @@ class VncServer():
|
||||
else:
|
||||
keyboard.Controller().release(kbdkey)
|
||||
except:
|
||||
print("Error sending key")
|
||||
log.debug("Error sending key")
|
||||
|
||||
continue
|
||||
|
||||
@@ -557,46 +558,46 @@ class VncServer():
|
||||
mouse.Controller().position = (x, y)
|
||||
|
||||
if buttons[0] and not left_pressed:
|
||||
print("LEFT PRESSED")
|
||||
log.debug("LEFT PRESSED")
|
||||
mouse.Controller().press(mouse.Button.left)
|
||||
left_pressed = 1
|
||||
elif not buttons[0] and left_pressed:
|
||||
print("LEFT RELEASED")
|
||||
log.debug("LEFT RELEASED")
|
||||
mouse.Controller().release(mouse.Button.left)
|
||||
left_pressed = 0
|
||||
|
||||
if buttons[1] and not middle_pressed:
|
||||
print("MIDDLE PRESSED")
|
||||
log.debug("MIDDLE PRESSED")
|
||||
mouse.Controller().press(mouse.Button.middle)
|
||||
middle_pressed = 1
|
||||
elif not buttons[1] and middle_pressed:
|
||||
print("MIDDLE RELEASED")
|
||||
log.debug("MIDDLE RELEASED")
|
||||
mouse.Controller().release(mouse.Button.middle)
|
||||
middle_pressed = 0
|
||||
|
||||
if buttons[2] and not right_pressed:
|
||||
print("RIGHT PRESSED")
|
||||
log.debug("RIGHT PRESSED")
|
||||
mouse.Controller().press(mouse.Button.right)
|
||||
right_pressed = 1
|
||||
elif not buttons[2] and right_pressed:
|
||||
print("RIGHT RELEASED")
|
||||
log.debug("RIGHT RELEASED")
|
||||
mouse.Controller().release(mouse.Button.right)
|
||||
right_pressed = 0
|
||||
|
||||
if buttons[3]:
|
||||
print("SCROLLUP PRESSED")
|
||||
log.debug("SCROLLUP PRESSED")
|
||||
mouse.Controller().scroll(0, 2)
|
||||
|
||||
if buttons[4]:
|
||||
print("SCROLLDOWN PRESSED")
|
||||
log.debug("SCROLLDOWN PRESSED")
|
||||
mouse.Controller().scroll(0, -2)
|
||||
|
||||
#print("PointerEvent", buttonmask, x, y)
|
||||
#log.debug("PointerEvent", buttonmask, x, y)
|
||||
continue
|
||||
|
||||
else:
|
||||
data2 = sock.recv(4096)
|
||||
print("RAW Server received data:", repr(data[0]) , data+data2)
|
||||
log.debug("RAW Server received data:", repr(data[0]) , data+data2)
|
||||
|
||||
|
||||
def GetRectangle(self, x, y, w, h):
|
||||
@@ -621,7 +622,7 @@ class VncServer():
|
||||
def SendRectangles(self, sock, x, y, w, h, incremental=0):
|
||||
# send FramebufferUpdate to client
|
||||
|
||||
#print("start SendRectangles")
|
||||
#log.debug("start SendRectangles")
|
||||
rectangle = self.GetRectangle(x, y, w, h)
|
||||
if not rectangle:
|
||||
rectangle = Image.new("RGB", [w, h], (0,0,0))
|
||||
@@ -650,7 +651,7 @@ class VncServer():
|
||||
(x, y, _, _) = diff.getbbox()
|
||||
w = rectangle.width
|
||||
h = rectangle.height
|
||||
#print("XYWH:", x,y,w,h, "diff", repr(diff.getbbox()))
|
||||
#log.debug("XYWH:", x,y,w,h, "diff", repr(diff.getbbox()))
|
||||
|
||||
stimeout = sock.gettimeout()
|
||||
sock.settimeout(None)
|
||||
@@ -677,7 +678,7 @@ class VncServer():
|
||||
#redMask = ((1 << redBits) - 1) << self.red_shift
|
||||
#greenMask = ((1 << greenBits) - 1) << self.green_shift
|
||||
#blueMask = ((1 << blueBits) - 1) << self.blue_shift
|
||||
#print("redMask", redMask, greenMask, blueMask)
|
||||
#log.debug("redMask", redMask, greenMask, blueMask)
|
||||
|
||||
if self.primaryOrder == "bgr":
|
||||
self.blue_shift = 0
|
||||
@@ -757,7 +758,7 @@ class VncServer():
|
||||
sendbuff.extend(pack("!HHHH", x, y, w, h))
|
||||
sendbuff.extend(pack(">i", self.encoding))
|
||||
|
||||
print("Compressing...")
|
||||
log.debug("Compressing...")
|
||||
zlibdata = compress.compress( image.tobytes() )
|
||||
zlibdata += compress.flush()
|
||||
l = pack("!I", len(zlibdata) )
|
||||
@@ -769,7 +770,7 @@ class VncServer():
|
||||
# send with RAW encoding
|
||||
sendbuff.extend(enc.ENCODINGS.raw_send_image(x, y, w, h, image))
|
||||
else:
|
||||
print("[!] Unsupported BPP: %s" % self.bpp)
|
||||
log.debug("[!] Unsupported BPP: %s" % self.bpp)
|
||||
|
||||
self.framebuffer = lastshot
|
||||
try:
|
||||
@@ -778,4 +779,4 @@ class VncServer():
|
||||
# connection closed?
|
||||
return False
|
||||
sock.settimeout(stimeout)
|
||||
#print("end SendRectangles")
|
||||
#log.debug("end SendRectangles")
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
pyuserinput
|
||||
pydes
|
||||
pynput
|
||||
numpy
|
||||
|
||||
|
||||
40
server.py
40
server.py
@@ -5,9 +5,19 @@ import pyvncs
|
||||
from argparse import ArgumentParser
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import signal
|
||||
from lib import log
|
||||
|
||||
#_debug = log.debug
|
||||
_debug = print
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
_debug("Exiting on %s signal..." % signal)
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
|
||||
class ControlThread(Thread):
|
||||
@@ -22,7 +32,7 @@ class ControlThread(Thread):
|
||||
sleep(1)
|
||||
for t in threads:
|
||||
if not t.isAlive():
|
||||
print("ControlThread removing dead", t)
|
||||
_debug("ControlThread removing dead", t)
|
||||
threads.remove(t)
|
||||
|
||||
class ClientThread(Thread):
|
||||
@@ -34,17 +44,17 @@ class ClientThread(Thread):
|
||||
self.setDaemon(True)
|
||||
|
||||
def __del__(self):
|
||||
print("ClientThread died")
|
||||
_debug("ClientThread died")
|
||||
|
||||
def run(self):
|
||||
print("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
|
||||
#print("Thread", self)
|
||||
_debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
|
||||
#_debug("Thread", self)
|
||||
server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD)
|
||||
server.CONFIG._8bitdither = CONFIG._8bitdither
|
||||
status = server.init()
|
||||
|
||||
if not status:
|
||||
print("Error negotiating client init")
|
||||
_debug("Error negotiating client init")
|
||||
return False
|
||||
server.protocol()
|
||||
|
||||
@@ -61,11 +71,17 @@ def main(argv):
|
||||
help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901')
|
||||
parser.add_argument("-P", "--password", help="Sets password", required=True, dest="VNC_PASSWORD")
|
||||
parser.add_argument("-8", "--8bitdither", help="Enable 8 bit dithering", required=False, action='store_true', dest="dither")
|
||||
parser.add_argument("-O", "--output-file", help="Redirects all debug output to file", required=False, dest="OUTFILE")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
if args.OUTFILE is not None:
|
||||
fsock = open(args.OUTFILE, 'w')
|
||||
sys.stdout = sys.stderr = fsock
|
||||
|
||||
# Multithreaded Python server
|
||||
TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP
|
||||
TCP_PORT = '0.0.0.0' if not hasattr(args,"TCP_PORT") else args.TCP_PORT
|
||||
TCP_PORT = '5901' if not hasattr(args,"TCP_PORT") else args.TCP_PORT
|
||||
VNC_PASSWORD = args.VNC_PASSWORD
|
||||
CONFIG._8bitdither = args.dither
|
||||
|
||||
@@ -77,8 +93,8 @@ def main(argv):
|
||||
controlthread.start()
|
||||
threads.append(controlthread)
|
||||
|
||||
print("Multithreaded Python server : Waiting for connections from TCP clients...")
|
||||
print("Runing on:", sys.platform)
|
||||
_debug("Multithreaded Python server : Waiting for connections from TCP clients...")
|
||||
_debug("Runing on:", sys.platform)
|
||||
while True:
|
||||
sockServer.listen(4)
|
||||
(conn, (ip,port)) = sockServer.accept()
|
||||
@@ -95,8 +111,8 @@ if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
except KeyboardInterrupt:
|
||||
# quit
|
||||
print("Exiting on ctrl+c...")
|
||||
_debug("Exiting on ctrl+c...")
|
||||
#for t in threads:
|
||||
# print("Killing", t)
|
||||
# _debug("Killing", t)
|
||||
sys.exit()
|
||||
|
||||
16
test.py
Normal file
16
test.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from lib import common
|
||||
import time
|
||||
|
||||
if __name__ == '__main__':
|
||||
#c = ["/bin/ls", "-alh"]
|
||||
#c = ["/bin/sleep", "5"]
|
||||
c = ["./test.sh"]
|
||||
r = common.proc()
|
||||
r.run(c)
|
||||
print("PID", r.getpid())
|
||||
#print("Waiting...")
|
||||
#r.waitproc()
|
||||
time.sleep(1)
|
||||
r.terminate()
|
||||
del r
|
||||
print("DONE")
|
||||
6
test.sh
Executable file
6
test.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
for a in $(seq 1 5); do
|
||||
echo "$a $$"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
79
winservice.py
Normal file
79
winservice.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import win32service
|
||||
import win32serviceutil
|
||||
import win32api
|
||||
import win32con
|
||||
import win32event
|
||||
import win32evtlogutil
|
||||
import servicemanager
|
||||
import os
|
||||
import sys
|
||||
from lib import const
|
||||
from lib import common
|
||||
from win32api import OutputDebugString as ODS
|
||||
import traceback
|
||||
|
||||
|
||||
const.SERVICENAME = "Test Service"
|
||||
const.SERVICEDNAME = "Test Service"
|
||||
const.SERVICEDESC = "Test Service Description"
|
||||
|
||||
const.CHILD = [
|
||||
"C:\\Program Files\\Python36\\python.exe",
|
||||
"C:\\pyvncs\\ctrlsrv.py",
|
||||
"-P",
|
||||
"kaka80"
|
||||
]
|
||||
|
||||
class service(win32serviceutil.ServiceFramework):
|
||||
|
||||
_svc_name_ = const.SERVICENAME
|
||||
_svc_display_name_ = const.SERVICEDNAME
|
||||
_svc_description_ = const.SERVICEDESC
|
||||
|
||||
def __init__(self, args):
|
||||
win32serviceutil.ServiceFramework.__init__(self, args)
|
||||
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
|
||||
|
||||
def SvcStop(self):
|
||||
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||
win32event.SetEvent(self.hWaitStop)
|
||||
|
||||
def SvcDoRun(self):
|
||||
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
|
||||
self.timeout = 3000
|
||||
|
||||
servicemanager.LogInfoMsg("%s - is running 1" % const.SERVICENAME)
|
||||
r = common.proc()
|
||||
try:
|
||||
r.run(const.CHILD)
|
||||
except:
|
||||
servicemanager.LogInfoMsg("ERROR: %s" % sys.exc_info()[0])
|
||||
servicemanager.LogInfoMsg(traceback.format_exc())
|
||||
sys.exit(1)
|
||||
|
||||
newpid = r.getpid()
|
||||
servicemanager.LogInfoMsg("%s - started child with pid %s" % (const.SERVICENAME, newpid))
|
||||
|
||||
while True:
|
||||
# Wait for service stop signal, if I timeout, loop again
|
||||
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
|
||||
# Check to see if self.hWaitStop happened
|
||||
if rc == win32event.WAIT_OBJECT_0:
|
||||
# Stop signal encountered
|
||||
servicemanager.LogInfoMsg("%s - STOPPED" % const.SERVICENAME)
|
||||
r.terminate()
|
||||
break
|
||||
#else:
|
||||
# servicemanager.LogInfoMsg("%s - still running" % const.SERVICENAME)
|
||||
|
||||
|
||||
def ctrlHandler(ctrlType):
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
ODS("__main__\n")
|
||||
servicemanager.LogInfoMsg("TEST")
|
||||
appdir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
os.chdir(appdir)
|
||||
win32api.SetConsoleCtrlHandler(ctrlHandler, True)
|
||||
win32serviceutil.HandleCommandLine(service)
|
||||
Reference in New Issue
Block a user