14 Commits
0.1 ... 0.2.1

Author SHA1 Message Date
ae3043b1de Structure 2018-02-06 00:01:53 +01:00
b17e6c9353 Beware of the shell history! 2018-02-05 23:58:30 +01:00
aef87bed4a Readability 2018-02-02 12:18:32 +01:00
4a09411676 ' 2018-02-01 22:14:32 +01:00
0822b9407c Removing test IP addresses 2018-02-01 14:21:12 +01:00
032b2facaf Windows configs, and readme. 2018-02-01 14:09:35 +01:00
b02757dae0 Merge pull request #1 from Sir-Boops/master
Update readme.md readability
2018-02-01 03:14:34 +01:00
47483e641a Update readme.md readability 2018-01-31 19:10:46 -07:00
0f73da0295 Additional info 2018-02-01 01:42:05 +01:00
93a88fc322 Optional password function added 2018-02-01 01:36:25 +01:00
f5aa131048 global errorcode fix 2017-12-27 13:40:17 +01:00
03635184ae Now speaks IPv6, if config contains a ":" in host 2017-10-03 00:05:23 +02:00
43bac5ed2c Link to raw image 2017-10-02 13:47:12 +02:00
b6e8815bbc Added a screenshot 2017-10-02 13:31:14 +02:00
7 changed files with 198 additions and 40 deletions

View File

@ -1,23 +1,53 @@
# ding
## What is ding?
ding is a client-server thing written in python. Its aim is to execute a set of commands remotely which can be set in the server's config file.
ding is a client-server thing written in python3. Its aim is to execute a set of commands remotely. The commands can be set in the server's config file.
## How does it work?
The server awaits commands sent by the client. A command must be defined in the server's config file, else the server won't do anything.
The server will wait for a command to be sent by a client. If the command is present within the server's config file it will then execute the command, else nothing will happen.
## What about ding's security?
The authentication is done by an SSL Client Certificate signed by an (own generated) Certificate Authority. The scripts for generating a CA and signing a Server/Client Certificate are also in here to make it (relatively) easy. [ You need only to press enter in the most cases, type in some certificate information and entering a previously defined CA password. ]
The authentication is done via a SSL Client Certificate signed by an (self generated) Certificate Authority. The scripts for generating a CA and signing the Server/Client Certificates are also included to make it (relatively) easy. [ This involves typing in a few certificate details and entering a previously defined CA password. ]
## Pic or didn't happen
![Screenshot of ding](/img/dingScreenshot.png)
[Can't read a thing?](https://raw.githubusercontent.com/Bandie/ding/master/img/dingScreenshot.png)
## Requirements
* Install python3 on your target computers.
## Installation
In all steps please read carefully what the certification generate scripts want from you. The certificate information needn't to be true at all and can be random. They only need to be different from each other.
At every step please read carefully what the generate certificates scripts want from you. The information on the certificates doesn't need to be true and can be totally random. They only need to be different from one another.
Step 1 to 3 can only be run on UNIX or GNU/Linux.
1. Run `./1_generateCA.sh` to generate a CA.
2. Run `./2_generateServCert.sh` to generate a signed Server Certificate.
3. Run `./3_generateClientCert.sh` to generate a signed Client Certificate.
4. Move `ding_client`, `ding_client.cfg`, `ding_client.crt`, `ding_client.key` and `CA.crt` to the computer which should be able to send commands to the server.
5. Do some configuration on the server and client (ding\_server.cfg, ding\_client.cfg).
6. Start the server using `./ding_server`. You may want to put this in a tmux session ([Ctrl+B, D] ;) ).
7. Try out the client using `./ding_client <command>`.
* UNIX or GNU/Linux: Also move `ding_client.cfg` to that computer.
* Windows: Also move `ding_client.win.cfg` to that computer.
5. Do some configuration on the server and client (`ding_server.cfg`, `ding_client.cfg` or `ding_server.win.cfg`, `ding_client.win.cfg` on Windows).
6. Start the server using `./ding_server` or `python .\ding_server` on Windows. (You may want to put this in a tmux session. [Ctrl+B, D] ;) ).
7. Try out the client using `./ding_client <command>` òr `python .\ding_client <command>` on Windows.
## Optional: Cleartext password with timeout
If you want to be sure that this power won't be abused by bad people using your computer, you may want to add a password (saved in cleartext).
The password will be sent inside the TLS connection.
### Warning! Beware of the shell history!
You might want to do something like `$ history -c` after sending the password via the client or play around with bash's HISTCONTROL variable.
### How to enable the password
1. Open your `ding_server.cfg` or `ding_server.win.cfg`.
2. Set `pw_on=true`.
3. Set a password, like `password=abc def`.
4. Set a password timeout: `pwtimeout=10` for 10 seconds.
If you have a password with special characters as in spaces and the like, you may want to use quotation marks around your password. `./ding_client "abc def"` or `python .\ding_client "abc def"` on Windows.

View File

@ -3,12 +3,20 @@
# Author: Bandie Canis
# License: 2-Clause BSD License
import sys, ssl, socket
import sys, ssl, socket, os
import configparser
CONFIG = "ding_client.cfg"
global exitcode
exitcode = 1
def readConfig():
if(os.name == 'nt'):
CONFIG = "ding_client.win.cfg"
else:
CONFIG = "ding_client.cfg"
cfg = configparser.SafeConfigParser()
try:
cfg.read(CONFIG)
@ -28,8 +36,6 @@ def readConfig():
def send(conn, cmd):
global exitcode
conn.connect((host, port))
buf = conn.recv(1024)
if(buf == b"OK 1337\n"):
@ -38,11 +44,17 @@ def send(conn, cmd):
if(buf == b"OK CMD"):
exitcode = 0
elif(buf == b"ERR NO_CMD"):
print("Error. Server said: The command doesn't exist/isn't set.", file=sys.stderr)
print("Error. Server said: The command isn't set on the server.", file=sys.stderr)
exitcode = 1
elif(buf == b"ERR CMD_ERR"):
print("Error. Server said: The command doesn't work because the file doesn't exist on the server.")
exitcode = 2
elif(buf == b"ERR PW"):
print("Error. Password required. The password was wrong.")
exitcode = 4
elif(b"OK PW" in buf):
bufr=str(buf.decode('utf-8'))
print("Password accepted. Timeout:", bufr.replace("OK PW ",""), "seconds.")
else:
conn.sendall(b"NO.")
@ -63,7 +75,10 @@ def main():
print("Please check your paths in the config file. (Have you forgotten to generate the Certificates?)", sep="", file=sys.stderr)
quit(2)
conn = context.wrap_socket(socket.socket())
if(":" in host):
conn = context.wrap_socket(socket.socket(family=socket.AF_INET6))
else:
conn = context.wrap_socket(socket.socket(family=socket.AF_INET))
try:

10
ding_client.win.cfg Normal file
View File

@ -0,0 +1,10 @@
[Client]
host=localhost
port=13573
cafile=CA.crt
#Client Certificate/key signed by the CA above
certfile=ding_client.crt
keyfile=ding_client.key

View File

@ -3,38 +3,45 @@
# Author: Bandie Canis
# License: 2-Clause BSD license
import ssl, socket, subprocess, time
import ssl, socket, subprocess, time, os
import configparser
CONFIG = "ding_server.cfg"
def getTimestamp():
t = "[" + time.strftime("%Y-%m-%d %H:%M:%S") + "]"
return t
def execFromConfig(option):
def execFromConfig(option, pw=False):
cfg = configparser.SafeConfigParser()
cfg.read(CONFIG)
try:
cmd = cfg.get("Commands", option).replace("\"", "").replace("\'", "")
cmd = cmd.split(" ")
if(pw):
if(option == password):
return 4
else:
return 5
else:
try:
subprocess.Popen(cmd)
return 0
cmd = cfg.get("Commands", option).replace("\"", "").replace("\'", "")
cmd = cmd.split(" ")
try:
subprocess.Popen(cmd)
return 0
except FileNotFoundError:
print(getTimestamp(), "Can't execute", cmd, ". File not found.")
return 2
except FileNotFoundError:
print(getTimestamp(), "Can't execute", cmd, ". File not found.")
return 2
except configparser.NoOptionError:
print(getTimestamp(), "No execution set:", option)
return 1
except configparser.NoOptionError:
print(getTimestamp(), "No execution set:", option)
return 1
def main():
while True:
newsocket, fromaddr = bindsocket.accept()
try:
@ -44,10 +51,16 @@ def main():
con_loop = True
while con_loop:
global tmppw_on, pw_on, pwtimeout
if('timeout' in locals() and timeout<time.time()):
del timeout
tmppw_on=pw_on
print(getTimestamp(), "Locked.")
try:
buf = connstream.recv(1024)
if not buf: break
buf = buf.decode("utf-8").upper()
buf = buf.decode("utf-8")
except ssl.SSLEOFError:
print(getTimestamp(), "SSL-EOF-Error.")
con_loop = False
@ -55,15 +68,29 @@ def main():
print(getTimestamp(), "Connection reset.")
serve()
print(getTimestamp(), " ", fromaddr[0], ": ", buf, sep="")
retval = execFromConfig(buf)
if(retval == 0):
connstream.send(b"OK CMD")
elif(retval == 1):
connstream.send(b"ERR NO_CMD")
elif(retval == 2):
connstream.send(b"ERR CMD_ERR")
if(tmppw_on):
retval = execFromConfig(buf, True)
if(retval == 5):
print(getTimestamp(), " ", fromaddr[0], ": Wrong Password.", sep="")
connstream.send(b"ERR PW")
if(retval == 4):
print(getTimestamp(), " ", fromaddr[0], ": Unlocked for ", pwtimeout, "sec.", sep="")
pwokstr = "OK PW " + str(pwtimeout)
connstream.send(bytes(pwokstr, "utf-8"))
timeout=time.time() + pwtimeout
tmppw_on = False
else:
print(getTimestamp(), " ", fromaddr[0], ": ", buf, sep="")
retval = execFromConfig(buf)
if(retval == 0):
connstream.send(b"OK CMD")
elif(retval == 1):
connstream.send(b"ERR NO_CMD")
elif(retval == 2):
connstream.send(b"ERR CMD_ERR")
except ssl.SSLError as e:
@ -74,8 +101,13 @@ def main():
def init():
global host, port, cafile, certfile, keyfile, context, bindsocket
global CONFIG, host, port, cafile, certfile, keyfile, pw_on, password, pwtimeout, tmppw_on, context, bindsocket
if(os.name == 'nt'):
CONFIG = "ding_server.win.cfg"
else:
CONFIG = "ding_server.cfg"
cfg = configparser.SafeConfigParser()
cfg.read(CONFIG)
@ -85,6 +117,14 @@ def init():
cafile=cfg.get("Security", "cafile").replace("\"","").replace("\'","")
certfile=cfg.get("Security", "certfile").replace("\"","").replace("\'","")
keyfile=cfg.get("Security", "keyfile").replace("\"","").replace("\'","")
pw_on=cfg.get("Security", "pw_on").replace("\"","").replace("\'","")
password=cfg.get("Security", "password").replace("\"","").replace("\'","")
pwtimeout=int(cfg.get("Security", "pwtimeout").replace("\"","").replace("\'",""))
if(pw_on.upper() == "TRUE"):
pw_on = True
else:
pw_on = False
tmppw_on=pw_on
except configparser.NoOptionError as e:
print("Error in configuration file:", e)
quit(1)
@ -102,7 +142,10 @@ def init():
quit(2)
try:
bindsocket = socket.socket()
if(":" in host):
bindsocket = socket.socket(family=socket.AF_INET6)
else:
bindsocket = socket.socket(family=socket.AF_INET)
bindsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
bindsocket.bind((host, port))
bindsocket.listen(5)
@ -114,12 +157,16 @@ def init():
quit(1)
print("Running ding server on ", host, ":", port,
"\nConfig: ", CONFIG,
"\nCAFile: ", cafile,
"\nCertfile: ", certfile,
"\nKeyfile: ", keyfile,
"\nPassword lock: ", pw_on,
"\nPassword timeout: ", pwtimeout,
"\n===========",
sep="")
if(__name__ == "__main__"):

View File

@ -12,6 +12,21 @@ certfile=ding_server.crt
# Server's private key
keyfile=ding_server.key
## Optional cleartext password
# To unlock the commands you need to send the password before sending the command.
# Example:
# $ ./ding_client "My password"
# $ ./ding_client lock
# Password on? (true/false)
pw_on=false
# Password (if you use spaces or other stuff you need to embrace the password in quotation marks, like ./ding_client "abc def"
password=abc def
# Password timeout in seconds
pwtimeout=10
[Commands]
# Syntax:

41
ding_server.win.cfg Normal file
View File

@ -0,0 +1,41 @@
[Server]
host=localhost
port=13573
[Security]
# Certificate of the OWN CA
cafile=CA.crt
# Server's certificate [signed by the CA above]
certfile=ding_server.crt
# Server's private key
keyfile=ding_server.key
## Optional cleartext password
# To unlock the commands you need to send the password before sending the command.
# Example:
# python .\ding_client "My password"
# python .\ding_client lock
# Password on? (true/false)
pw_on=false
# The password.
# If you have a password with special characters as in spaces and the like, you may want to use quotation marks around your password: python .\ding_client "abc def"
password=abc def
# Password timeout in seconds
pwtimeout=10
[Commands]
# Syntax:
# SERVER_COMMAND: Command --which --should_be --executed
#
# For cmd.exe:
# a_cmd_command: C:\Windows\System32\cmd.exe /C <Your cmd commands here>
#
# For powershell:
# a_ps_command: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe <Powershell commands here>
lock: C:\Windows\System32\rundll32.exe user32.dll,LockWorkStation

BIN
img/dingScreenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB