Testing for windows service

This commit is contained in:
Matias Fernandez
2019-04-09 20:34:12 -04:00
parent 4add215ecd
commit 57623a6933
14 changed files with 706 additions and 63 deletions

327
ctrlsrv.py Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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)

View File

@@ -29,6 +29,7 @@ import zlib
import numpy as np import numpy as np
from lib.encodings import * from lib.encodings import *
from lib import log
def hexdump(data): def hexdump(data):
str = "" str = ""
@@ -182,7 +183,7 @@ class VncServer():
def __del__(self): def __del__(self):
print("VncServer died") log.debug("VncServer died")
def encrypt(self, key, data): def encrypt(self, key, data):
k = des(key, ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) 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) data = sock.recv(1024)
except socket.timeout: except socket.timeout:
data = None data = None
print("getbuff() timeout") log.debug("getbuff() timeout")
return data return data
@@ -232,15 +233,15 @@ class VncServer():
# RFB version handshake # RFB version handshake
data = self.getbuff(30) data = self.getbuff(30)
print("init received: '%s'" % data) log.debug("init received: '%s'" % data)
server_version = float(self.RFB_VERSION) server_version = float(self.RFB_VERSION)
try: try:
client_version = float(data[4:11]) client_version = float(data[4:11])
except: except:
print("Error parsing client version") log.debug("Error parsing client version")
return False return False
print("client, server:", client_version, server_version) log.debug("client, server:", client_version, server_version)
# security types handshake # security types handshake
sendbuff = pack("B", len(self.sectypes)) # number of security types sendbuff = pack("B", len(self.sectypes)) # number of security types
@@ -254,13 +255,13 @@ class VncServer():
sectype = None sectype = None
if sectype not in self.sectypes: 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 sock.send(pack("B", 1)) # failed handshake
self.sendmessage("Incompatible security type") self.sendmessage("Incompatible security type")
sock.close() sock.close()
return False return False
print("sec type data: %s" % data) log.debug("sec type data: %s" % data)
# VNC Auth # VNC Auth
if sectype == 2: if sectype == 2:
@@ -278,9 +279,9 @@ class VncServer():
if data == crypted: if data == crypted:
# Handshake successful # Handshake successful
sock.send(pack("I", 0)) sock.send(pack("I", 0))
print("Auth OK") log.debug("Auth OK")
else: else:
print("Invalid auth") log.debug("Invalid auth")
return False return False
#unsupported VNC auth type #unsupported VNC auth type
@@ -289,7 +290,7 @@ class VncServer():
# get ClientInit # get ClientInit
data = self.getbuff(30) data = self.getbuff(30)
print("Clientinit (shared flag)", repr(data)) log.debug("Clientinit (shared flag)", repr(data))
self.ServerInit() self.ServerInit()
@@ -300,9 +301,9 @@ class VncServer():
sock = self.socket sock = self.socket
screen = ImageGrab.grab() screen = ImageGrab.grab()
print("screen", repr(screen)) log.debug("screen", repr(screen))
size = screen.size size = screen.size
print("size", repr(size)) log.debug("size", repr(size))
del screen del screen
width = size[0] width = size[0]
@@ -339,8 +340,8 @@ class VncServer():
sendbuff += pack("!I", desktop_name_len) sendbuff += pack("!I", desktop_name_len)
sendbuff += desktop_name.encode() sendbuff += desktop_name.encode()
print("width", repr(width)) log.debug("width", repr(width))
print("height", repr(height)) log.debug("height", repr(height))
sock.send(sendbuff) sock.send(sendbuff)
@@ -437,7 +438,7 @@ class VncServer():
kbdmap[0xffe2] = keyboard.Key.shift kbdmap[0xffe2] = keyboard.Key.shift
while True: while True:
#print(".", end='', flush=True) #log.debug(".", end='', flush=True)
r,_,_ = select.select([self.socket],[],[],0) r,_,_ = select.select([self.socket],[],[],0)
if r == []: if r == []:
#no data #no data
@@ -448,10 +449,10 @@ class VncServer():
try: try:
data = sock.recv(1) # read first byte data = sock.recv(1) # read first byte
except socket.timeout: except socket.timeout:
#print("timeout") #log.debug("timeout")
continue continue
except Exception as e: except Exception as e:
print("exception '%s'" % e) log.debug("exception '%s'" % e)
sock.close() sock.close()
break break
@@ -462,40 +463,40 @@ class VncServer():
if data[0] == 0: # client SetPixelFormat if data[0] == 0: # client SetPixelFormat
data2 = sock.recv(19, socket.MSG_WAITALL) 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.bpp, self.depth, self.bigendian, self.truecolor, self.red_maximum,
self.green_maximum, self.blue_maximum, self.green_maximum, self.blue_maximum,
self.red_shift, self.green_shift, self.blue_shift self.red_shift, self.green_shift, self.blue_shift
) = unpack("!xxxBBBBHHHBBBxxx", data2) ) = unpack("!xxxBBBBHHHBBBxxx", data2)
print("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor) log.debug("IMG bpp, depth, endian, truecolor", self.bpp, self.depth, self.bigendian, self.truecolor)
print("SHIFTS", self.red_shift, self.green_shift, self.blue_shift) log.debug("SHIFTS", self.red_shift, self.green_shift, self.blue_shift)
print("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum) log.debug("MAXS", self.red_maximum, self.green_maximum, self.blue_maximum)
if self.red_shift > self.blue_shift: if self.red_shift > self.blue_shift:
self.primaryOrder = "rgb" self.primaryOrder = "rgb"
else: else:
self.primaryOrder = "bgr" self.primaryOrder = "bgr"
print("Using order: ", self.primaryOrder) log.debug("Using order: ", self.primaryOrder)
continue continue
if data[0] == 2: # SetEncoding if data[0] == 2: # SetEncoding
data2 = sock.recv(3) data2 = sock.recv(3)
print("Client Message Type: SetEncoding (2)") log.debug("Client Message Type: SetEncoding (2)")
(nencodings,) = unpack("!xH", data2) (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) data2 = sock.recv(4 * nencodings, socket.MSG_WAITALL)
#print("len", len(data2)) #log.debug("len", len(data2))
self.client_encodings = unpack("!%si" % nencodings, 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: 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.remotecursor = True
self.cursorchanged = True self.cursorchanged = True
if hasattr(enc.ENCODINGS, "zlib") and enc.ENCODINGS.zlib in self.client_encodings: 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 self.encoding = enc.ENCODINGS.zlib
continue continue
@@ -503,10 +504,10 @@ class VncServer():
if data[0] == 3: # FBUpdateRequest if data[0] == 3: # FBUpdateRequest
data2 = sock.recv(9, socket.MSG_WAITALL) data2 = sock.recv(9, socket.MSG_WAITALL)
#print("Client Message Type: FBUpdateRequest (3)") #log.debug("Client Message Type: FBUpdateRequest (3)")
#print(len(data2)) #print(len(data2))
(incremental, x, y, w, h) = unpack("!BHHHH", 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) self.SendRectangles(sock, x, y, w, h, incremental)
if self.remotecursor and self.cursorchanged: if self.remotecursor and self.cursorchanged:
@@ -519,7 +520,7 @@ class VncServer():
data2 = sock.recv(7) data2 = sock.recv(7)
# B = U8, L = U32 # B = U8, L = U32
(downflag, key) = unpack("!BxxL", data2) (downflag, key) = unpack("!BxxL", data2)
print("KeyEvent", downflag, hex(key)) log.debug("KeyEvent", downflag, hex(key))
# special key # special key
if key in kbdmap: if key in kbdmap:
@@ -531,9 +532,9 @@ class VncServer():
kbdkey = None kbdkey = None
try: try:
print("KEY:", kbdkey) log.debug("KEY:", kbdkey)
except: except:
print("KEY: (unprintable)") log.debug("KEY: (unprintable)")
try: try:
if downflag: if downflag:
@@ -541,7 +542,7 @@ class VncServer():
else: else:
keyboard.Controller().release(kbdkey) keyboard.Controller().release(kbdkey)
except: except:
print("Error sending key") log.debug("Error sending key")
continue continue
@@ -557,46 +558,46 @@ class VncServer():
mouse.Controller().position = (x, y) mouse.Controller().position = (x, y)
if buttons[0] and not left_pressed: if buttons[0] and not left_pressed:
print("LEFT PRESSED") log.debug("LEFT PRESSED")
mouse.Controller().press(mouse.Button.left) mouse.Controller().press(mouse.Button.left)
left_pressed = 1 left_pressed = 1
elif not buttons[0] and left_pressed: elif not buttons[0] and left_pressed:
print("LEFT RELEASED") log.debug("LEFT RELEASED")
mouse.Controller().release(mouse.Button.left) mouse.Controller().release(mouse.Button.left)
left_pressed = 0 left_pressed = 0
if buttons[1] and not middle_pressed: if buttons[1] and not middle_pressed:
print("MIDDLE PRESSED") log.debug("MIDDLE PRESSED")
mouse.Controller().press(mouse.Button.middle) mouse.Controller().press(mouse.Button.middle)
middle_pressed = 1 middle_pressed = 1
elif not buttons[1] and middle_pressed: elif not buttons[1] and middle_pressed:
print("MIDDLE RELEASED") log.debug("MIDDLE RELEASED")
mouse.Controller().release(mouse.Button.middle) mouse.Controller().release(mouse.Button.middle)
middle_pressed = 0 middle_pressed = 0
if buttons[2] and not right_pressed: if buttons[2] and not right_pressed:
print("RIGHT PRESSED") log.debug("RIGHT PRESSED")
mouse.Controller().press(mouse.Button.right) mouse.Controller().press(mouse.Button.right)
right_pressed = 1 right_pressed = 1
elif not buttons[2] and right_pressed: elif not buttons[2] and right_pressed:
print("RIGHT RELEASED") log.debug("RIGHT RELEASED")
mouse.Controller().release(mouse.Button.right) mouse.Controller().release(mouse.Button.right)
right_pressed = 0 right_pressed = 0
if buttons[3]: if buttons[3]:
print("SCROLLUP PRESSED") log.debug("SCROLLUP PRESSED")
mouse.Controller().scroll(0, 2) mouse.Controller().scroll(0, 2)
if buttons[4]: if buttons[4]:
print("SCROLLDOWN PRESSED") log.debug("SCROLLDOWN PRESSED")
mouse.Controller().scroll(0, -2) mouse.Controller().scroll(0, -2)
#print("PointerEvent", buttonmask, x, y) #log.debug("PointerEvent", buttonmask, x, y)
continue continue
else: else:
data2 = sock.recv(4096) 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): def GetRectangle(self, x, y, w, h):
@@ -621,7 +622,7 @@ class VncServer():
def SendRectangles(self, sock, x, y, w, h, incremental=0): def SendRectangles(self, sock, x, y, w, h, incremental=0):
# send FramebufferUpdate to client # send FramebufferUpdate to client
#print("start SendRectangles") #log.debug("start SendRectangles")
rectangle = self.GetRectangle(x, y, w, h) rectangle = self.GetRectangle(x, y, w, h)
if not rectangle: if not rectangle:
rectangle = Image.new("RGB", [w, h], (0,0,0)) rectangle = Image.new("RGB", [w, h], (0,0,0))
@@ -650,7 +651,7 @@ class VncServer():
(x, y, _, _) = diff.getbbox() (x, y, _, _) = diff.getbbox()
w = rectangle.width w = rectangle.width
h = rectangle.height 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() stimeout = sock.gettimeout()
sock.settimeout(None) sock.settimeout(None)
@@ -677,7 +678,7 @@ class VncServer():
#redMask = ((1 << redBits) - 1) << self.red_shift #redMask = ((1 << redBits) - 1) << self.red_shift
#greenMask = ((1 << greenBits) - 1) << self.green_shift #greenMask = ((1 << greenBits) - 1) << self.green_shift
#blueMask = ((1 << blueBits) - 1) << self.blue_shift #blueMask = ((1 << blueBits) - 1) << self.blue_shift
#print("redMask", redMask, greenMask, blueMask) #log.debug("redMask", redMask, greenMask, blueMask)
if self.primaryOrder == "bgr": if self.primaryOrder == "bgr":
self.blue_shift = 0 self.blue_shift = 0
@@ -757,7 +758,7 @@ class VncServer():
sendbuff.extend(pack("!HHHH", x, y, w, h)) sendbuff.extend(pack("!HHHH", x, y, w, h))
sendbuff.extend(pack(">i", self.encoding)) sendbuff.extend(pack(">i", self.encoding))
print("Compressing...") log.debug("Compressing...")
zlibdata = compress.compress( image.tobytes() ) zlibdata = compress.compress( image.tobytes() )
zlibdata += compress.flush() zlibdata += compress.flush()
l = pack("!I", len(zlibdata) ) l = pack("!I", len(zlibdata) )
@@ -769,7 +770,7 @@ class VncServer():
# send with RAW encoding # send with RAW encoding
sendbuff.extend(enc.ENCODINGS.raw_send_image(x, y, w, h, image)) sendbuff.extend(enc.ENCODINGS.raw_send_image(x, y, w, h, image))
else: else:
print("[!] Unsupported BPP: %s" % self.bpp) log.debug("[!] Unsupported BPP: %s" % self.bpp)
self.framebuffer = lastshot self.framebuffer = lastshot
try: try:
@@ -778,4 +779,4 @@ class VncServer():
# connection closed? # connection closed?
return False return False
sock.settimeout(stimeout) sock.settimeout(stimeout)
#print("end SendRectangles") #log.debug("end SendRectangles")

View File

@@ -1,2 +1,4 @@
pyuserinput pydes
pynput
numpy

View File

@@ -5,9 +5,19 @@ import pyvncs
from argparse import ArgumentParser from argparse import ArgumentParser
from threading import Thread from threading import Thread
from time import sleep from time import sleep
import sys import sys
import socket 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): class ControlThread(Thread):
@@ -22,7 +32,7 @@ class ControlThread(Thread):
sleep(1) sleep(1)
for t in threads: for t in threads:
if not t.isAlive(): if not t.isAlive():
print("ControlThread removing dead", t) _debug("ControlThread removing dead", t)
threads.remove(t) threads.remove(t)
class ClientThread(Thread): class ClientThread(Thread):
@@ -34,17 +44,17 @@ class ClientThread(Thread):
self.setDaemon(True) self.setDaemon(True)
def __del__(self): def __del__(self):
print("ClientThread died") _debug("ClientThread died")
def run(self): def run(self):
print("[+] New server socket thread started for " + self.ip + ":" + str(self.port)) _debug("[+] New server socket thread started for " + self.ip + ":" + str(self.port))
#print("Thread", self) #_debug("Thread", self)
server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD) server = pyvncs.server.VncServer(self.sock, VNC_PASSWORD)
server.CONFIG._8bitdither = CONFIG._8bitdither server.CONFIG._8bitdither = CONFIG._8bitdither
status = server.init() status = server.init()
if not status: if not status:
print("Error negotiating client init") _debug("Error negotiating client init")
return False return False
server.protocol() server.protocol()
@@ -61,11 +71,17 @@ def main(argv):
help="Listen in this port, default: %s" % ("5901"), type=int, required=False, default='5901') 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("-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("-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() args = parser.parse_args()
if args.OUTFILE is not None:
fsock = open(args.OUTFILE, 'w')
sys.stdout = sys.stderr = fsock
# Multithreaded Python server # Multithreaded Python server
TCP_IP = '0.0.0.0' if not hasattr(args,"TCP_IP") else args.TCP_IP 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 VNC_PASSWORD = args.VNC_PASSWORD
CONFIG._8bitdither = args.dither CONFIG._8bitdither = args.dither
@@ -77,8 +93,8 @@ def main(argv):
controlthread.start() controlthread.start()
threads.append(controlthread) threads.append(controlthread)
print("Multithreaded Python server : Waiting for connections from TCP clients...") _debug("Multithreaded Python server : Waiting for connections from TCP clients...")
print("Runing on:", sys.platform) _debug("Runing on:", sys.platform)
while True: while True:
sockServer.listen(4) sockServer.listen(4)
(conn, (ip,port)) = sockServer.accept() (conn, (ip,port)) = sockServer.accept()
@@ -95,8 +111,8 @@ if __name__ == "__main__":
main(sys.argv) main(sys.argv)
except KeyboardInterrupt: except KeyboardInterrupt:
# quit # quit
print("Exiting on ctrl+c...") _debug("Exiting on ctrl+c...")
#for t in threads: #for t in threads:
# print("Killing", t) # _debug("Killing", t)
sys.exit() sys.exit()

16
test.py Normal file
View 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
View File

@@ -0,0 +1,6 @@
#!/bin/bash
for a in $(seq 1 5); do
echo "$a $$"
sleep 1
done

79
winservice.py Normal file
View 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)