-
Notifications
You must be signed in to change notification settings - Fork 263
/
Copy pathrefClient.py
151 lines (122 loc) · 4.06 KB
/
refClient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# REQUIRED: PyCrypto 2.6.1
# To install: pip install pycrypto
# Homepage: https://www.dlitz.net/software/pycrypto/
import argparse
import sys
import socket
from Crypto.Hash import SHA256
def readNullTerminatedString(f):
buf = b''
while True:
if len(buf) > 1 << 20:
raise Exception("Overly long input")
c = f.read(1)
if len(c) == 0:
raise Exception("End of stream reached")
if ord(c) == 0: # Indicates NULL termination of a UTF-8 string.
break
buf += c
return unicode(buf, encoding="utf-8", errors="strict")
def toNullTerminatedUtf8(s):
return unicode(s).encode("utf-8") + "\x00"
class Client:
nonceLengthInBytes = 8
def __init__(self, host, port, username, password):
self.username = username
self.password = password
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.setblocking(1)
self._socket.connect((host, port))
self._f = self._socket.makefile("rw")
self._authenticate()
def close():
self._f.close()
self._socket.close()
def execute(self, command):
self._sendMessage_Command(command)
return self._expectMessage_CommandResult()
def _authenticate(self):
self._sendMessage_LogonRequest()
(nonce, challengeCookie) = self._expectMessage_LogonChallenge()
r = self._computeChallengeResponse(nonce)
self._sendMessage_LogonResponse(r, challengeCookie)
self.ticket = self._expectMessage_LogonSuccess()
def _sendMessage_LogonRequest(self):
self._f.write("\x01")
self._f.write(toNullTerminatedUtf8(self.username))
self._f.flush()
def _expectMessage_LogonChallenge(self):
self._expectMessageType(0x02)
nonce = self._readBytes(self.nonceLengthInBytes)
challengeCookie = self._expectString()
return (nonce, challengeCookie)
def _computeChallengeResponse(self, nonce):
return SHA256.new(nonce + self.password).digest()
def _sendMessage_LogonResponse(self, r, challengeCookie):
self._f.write("\x03")
self._f.write(r)
self._f.write(toNullTerminatedUtf8(challengeCookie))
self._f.flush()
def _expectMessage_LogonSuccess(self):
messageType = self._readMessageType()
if messageType == 0x04:
ticket = self._expectString()
return ticket
elif messageType == 0x05:
return None
else:
raise Exception("Unexpected message type: 0x%02x" % messageType)
def _sendMessage_Command(self, command):
self._f.write("\x06")
self._f.write(toNullTerminatedUtf8(self.ticket))
self._f.write(toNullTerminatedUtf8(command))
self._f.flush()
def _expectMessage_CommandResult(self):
messageType = self._readMessageType()
if messageType == 0x07:
result = self._expectString()
return result
elif messageType == 0x05:
sys.stderr.write("Unauthorized\n")
exit(1)
else:
raise Exception("Unexpected message type: 0x%02x" % messageType)
def _readMessageType(self):
messageTypeByte = self._readBytes(1)
if (len(messageTypeByte) == 0):
raise Exception("Server has disconnected")
return ord(messageTypeByte)
def _expectMessageType(self, expectedMessageType):
messageType = self._readMessageType()
if messageType != expectedMessageType:
raise Exception("Unexpected message type: 0x%02x" % messageType)
def _readBytes(self, nBytes):
result = self._f.read(nBytes)
if len(result) != nBytes:
raise Exception("Connection was closed")
return result
def _expectString(self):
buf = b''
while True:
if len(buf) > 1 << 20:
raise Exception("Overly long input")
c = self._f.read(1)
if len(c) == 0:
raise Exception("End of stream reached")
if ord(c[0]) == 0: # Indicates NULL termination of a UTF-8 string.
break
buf += c
return unicode(buf, encoding="utf-8", errors="strict")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("host")
parser.add_argument("port", type=int)
parser.add_argument("username")
parser.add_argument("password")
parser.add_argument("command")
args = parser.parse_args()
client = Client(args.host, args.port, args.username, args.password)
if not client.ticket:
sys.stderr.write("Failed to authenticate\n")
exit(1)
print client.execute(args.command)