初衷
既然学完了WebGoat系列教程,下面来综合实战演练一下,同时也是检测一下自己的学习成果如何。
找了这样的一个网站,try2hack,这是一个专门用来做网络攻击练习的网站,虽然比较老了,但用来做练习还是可以的。该网站一共有13道关卡,难度是逐步递增的,下面我们逐一开始挑战。
实战攻击
这是该网站开始的页面:
Level 1
这是第一关,网址:http://www.try2hack.nl/levels/
上图要求我们输入密码然后通过。我试着随便输入了两次密码,均弹出如下提示:
点击确定之后就跳转到了迪斯尼的网站。此时burpsuit才拦截到浏览器发给服务器的包。也就是说验证过程是在拦截到包之前发生的。
由此推断这是一个客户端的验证程序,并且是用JS验证密码的。我们知道所有在客户端进行的验证程序都是不安全的。果然,当查看该页面的源代码,看到了如下JS的代码片段:
1 | <script type="text/javascript"> |
由IF判断语句可以看出密码为h4x0r,于是输入密码:h4x0r,然后提交:
第一关就轻松通过了。
总结:这一关主要考查Html的页面源代码和JS。
Level 2
网址:http://www.try2hack.nl/levels/level2-xfdgnh.xhtml
第二关的页面如下:
可以看出是需要我们输入用户名和密码,然后提交。但有一个问题就是当我们输入用户名和密码之后,点击下面第三个提交的按钮却没有反应。
于是我们打开burpsuit抓包试试,点击下面第三个按钮,burpsuit抓不到任何数据,也就是说这个按钮没有提交任何数据给服务器。那么我们需要看看该按钮所对应的function是什么了。结果在该页面单击鼠标右键希望查看该页面源代码的时候,页面却弹出了这样一个提示:
也就是说在该页面鼠标右键是禁止点击的。观察到页面弹出提示的同时,输入用户名和密码的部分也消失了,同时burpsuit捕获到了数据包。不要紧,我们还有firebug,按F12打开firebug,可以看到如下代码,并且发现整个页面都处于JS的function中,原来如此!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<script type="text/javascript">
<!--
passwd="ItIsSoEasy";
function disable_right_click(e) {
var browser = navigator.appName.substring ( 0, 9 );
var event_number = 0;
if (browser=="Microsoft")
event_number = event.button;
else
event_number = e.which;
if ( event_number==2 || event_number==3 || event_number==4) {
alert ("Right/middle mousebutton is disabled");
return (false);
}
return (true);
}
function check_mousekey () {
var mouse_key = 93;
var keycode = event.keyCode;
if ( keycode == mouse_key )
alert ( "Mouse Key Is Disabled" );
}
function trap_page_mouse_key_events () {
var browser = navigator.appName.substring ( 0, 9 );
document.onmousedown = disable_right_click;
if ( browser == "Microsoft" )
document.onkeydown = check_mousekey;
else
document.captureEvents( Event.MOUSEDOWN );
}
window.onload = trap_page_mouse_key_events;
//-->
</script>
以上这段JS的目的是定义我们不能使用鼠标右键,这个问题可以很容易的解决:我们只需用burpsuit拦截服务器的响应,修改响应代码并去掉该JS中的第一段Function代码,然后让在浏览器端正常加载就可以了。可是这样做了之后,虽然可以正常查看页面源代码了,可是通过查看页面源代码好像无所收获。然后我们继续通过burpsuit观察:
以上是加载该页面时拦截到的两个请求,可看到该页面是分两步加载的。第二部分是一个flash文件,而这个flash文件正是我们输入用户名和密码的地方。现在单独分析该flash文件,根据URL把该flash文件下载到本地,用记事本打开发现是乱码。于是考虑可能需要反编译该flash文件,看看它对应的源码是什么。接着然后我们找了一个能提供在线反编译的网站,在该网站中将我们flash的URL输入进去,出现如下反编译后的结果:
可以看到该函数是一个判断语句,当用户名为:try2hack,密码为:irtehh4x0r! 时通过,于是输入之后,第二关就过了。
总结:这一关主要考查网页flash文件的反编译。
Level 3
网址:http://www.try2hack.nl/levels/level3-.xhtml
刚刚进入第三关,展现在眼前的就是这样一个页面:
尝试随便输入几个密码,输入错误之后,又进入了迪斯尼的页面。。。
并且发现从第二关跳到第三关的过程中burpsuit居然拦截不到任何请求,因此估计这又是一个客户端的JS验证。观察到第二关通过时所跳转的URL为:
发现用浏览器打开该URL后,右键居然看不到源代码。好吧,我把你用迅雷下载下来再用记事本打开总看的到源代码吧,果然,源代码是这样的:
1 | <script type="text/javascript"> |
输入密码:AbCdE,居然显示不对?!然后我就很疑惑了,其值是不是在程序运行过程中有修改呢?于是我在这段脚本里面设断点,希望能够通过firebug调试观察password的值,可是设好断点,点击之后,根本不在断点处停下来,这是怎么回事?于是我猜想,这说明我们点击确定的代码根本没有运行到这里就被判断了。然后再看看firebug里面的脚本:
居然有两个脚本,点开另外一个脚本,显示如下内容:
我感觉我被欺骗了,也就是说,真正运行的是后面这段脚本!输入密码:try2hackrawks,果然顺利通过。
但这里有一个疑问,后面这一段应该称不上脚本,也就是说最终的判断还是在level3-.xhtml中实现的,那这里JavaScript里面的密码是如何被赋值到level3-.xhtml中的呢?我猜想JavaScript中应该是一个预先的预定义值,相当于初始化变量,然后其实后面的语句其实是对password变量值的修改,也就是说程序时通过第一次的值进行验证的。
为了检验我的猜想,再次设断点,运行,停下来了,原来之前停不下来是因为断点位置没有设好,那么下图则看的很清晰了:
总结:这一关主要考查获取页面源代码和JS运行原理和流程。
Level 4
网址:http://www.try2hack.nl/levels/level4-kdnvxs.xhtml
来到第四关,展现在眼前的居然是一片白板!?纳尼?
查看页面源代码显示如下:
以上代码绿色部分表示除IE外其他浏览器都能识别,详细说明见这里。从该代码可以看出这是一个Java Applet的小程序,并且该小程序的URL地址为:http://try2hack.nl/levels/PasswdLevel4.class 。而页面之所以不显示出来,是因为我们没有装Java runtime environment。但是后来即使装了,也是这样的报错:
为了解决这个错误,我把谷歌百度翻了个底朝天,并且至少试了四种不同的浏览器,最后依然没有解决。但总体上该报错应该是版本问题,现在很少有浏览器支持Applet了,还有一个可能性是需要小程序有正式的签名,不得而知。把该.class文件下载下来,反编译后得到源码如下: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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202import java.applet.Applet;
import java.applet.AppletContext;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.EventObject;
public class PasswdLevel4 extends Applet
implements ActionListener
{
private URL finalurl;
String infile;
String inuser[];
int totno;
InputStream countConn;
BufferedReader countData;
URL inURL;
TextField txtlogin;
Label label1;
Label label2;
Label label3;
TextField txtpass;
Label lblstatus;
Button ButOk;
Button ButReset;
Label lbltitle;
public PasswdLevel4()
{
inuser = new String[22];
totno = 0;
countConn = null;
countData = null;
inURL = null;
txtlogin = new TextField();
label1 = new Label();
label2 = new Label();
label3 = new Label();
txtpass = new TextField();
lblstatus = new Label();
ButOk = new Button();
ButReset = new Button();
lbltitle = new Label();
}
void ButOk_ActionPerformed(ActionEvent actionevent)
{
boolean flag = false;
for(int i = 1; i <= totno / 2; i++)
{
if(txtlogin.getText().trim().toUpperCase().intern() == inuser[2 * (i - 1) + 2].trim().toUpperCase().intern() && txtpass.getText().trim().toUpperCase().intern() == inuser[2 * (i - 1) + 3].trim().toUpperCase().intern())
{
lblstatus.setText("Login Success, Loading..");
flag = true;
String s = inuser[1].trim().intern();
String s1 = getParameter("targetframe");
if(s1 == null)
{
s1 = "_self";
}
try
{
finalurl = new URL(getCodeBase(), s);
}
catch(MalformedURLException _ex)
{
lblstatus.setText("Bad URL");
}
getAppletContext().showDocument(finalurl, s1);
}
}
if(!flag)
{
lblstatus.setText("Invaild Login or Password");
}
}
void ButReset_ActionPerformed(ActionEvent actionevent)
{
txtlogin.setText("");
txtpass.setText("");
}
public void actionPerformed(ActionEvent actionevent)
{
Object obj = actionevent.getSource();
if(obj == ButOk)
{
ButOk_ActionPerformed(actionevent);
return;
}
if(obj == ButReset)
{
ButReset_ActionPerformed(actionevent);
}
}
public void destroy()
{
ButOk.setEnabled(false);
ButReset.setEnabled(false);
txtlogin.setVisible(false);
txtpass.setVisible(false);
}
public void inFile()
{
new StringBuffer();
try
{
countConn = inURL.openStream();
countData = new BufferedReader(new InputStreamReader(countConn));
String s;
while((s = countData.readLine()) != null)
{
if(totno < 21)
{
totno = totno + 1;
inuser[totno] = s;
s = "";
} else
{
lblstatus.setText("Cannot Exceed 10 users, Applet fail start!");
destroy();
}
}
}
catch(IOException ioexception)
{
getAppletContext().showStatus("IO Error:" + ioexception.getMessage());
}
try
{
countConn.close();
countData.close();
return;
}
catch(IOException ioexception1)
{
getAppletContext().showStatus("IO Error:" + ioexception1.getMessage());
}
}
public void init()
{
setLayout(null);
setSize(361, 191);
add(txtlogin);
txtlogin.setBounds(156, 72, 132, 24);
label1.setText("Please Enter Login Name & Password");
label1.setAlignment(1);
add(label1);
label1.setFont(new Font("Dialog", 1, 12));
label1.setBounds(41, 36, 280, 24);
label2.setText("Login");
add(label2);
label2.setFont(new Font("Dialog", 1, 12));
label2.setBounds(75, 72, 36, 24);
label3.setText("Password");
add(label3);
add(txtpass);
txtpass.setEchoChar('*');
txtpass.setBounds(156, 108, 132, 24);
lblstatus.setAlignment(1);
label3.setFont(new Font("Dialog", 1, 12));
label3.setBounds(75, 108, 57, 21);
add(lblstatus);
lblstatus.setFont(new Font("Dialog", 1, 12));
lblstatus.setBounds(14, 132, 344, 24);
ButOk.setLabel("OK");
add(ButOk);
ButOk.setFont(new Font("Dialog", 1, 12));
ButOk.setBounds(105, 156, 59, 23);
ButReset.setLabel("Reset");
add(ButReset);
ButReset.setFont(new Font("Dialog", 1, 12));
ButReset.setBounds(204, 156, 59, 23);
lbltitle.setAlignment(1);
add(lbltitle);
lbltitle.setFont(new Font("Dialog", 1, 12));
lbltitle.setBounds(12, 14, 336, 24);
String s = getParameter("title");
lbltitle.setText(s);
ButOk.addActionListener(this);
ButReset.addActionListener(this);
infile = new String("level4");
try
{
inURL = new URL(getCodeBase(), infile);
}
catch(MalformedURLException _ex)
{
getAppletContext().showStatus("Bad Counter URL:" + inURL);
}
inFile();
}
}
为了将该class文件嵌入进去html,我自己又写了一个PasswdLevel.html,代码如下:1
2
3<html>
<applet code="PasswdLevel4.class" width=500 height=500> </applet>
</html>
这时可以用如下命令查看该Applet小程序:1
appletviewer PasswdLevel4.html
提示无法进行初始化,然后仔细看java源代码,发现程序读进去了一个level4的文件,于是按照URL地址:http://try2hack.nl/levels/level4 将该文件下载下来。此时的文档结构目录为:
此时再用上面的命令查看,则终于显示出来了:
这里需要输入的用户名密码就是level4里面的用户名和密码,因为程序要验证,而就是通过这个文件读进去的,文件打开后内容如下:
因此输入用户名:appletking,密码:pieceofcake,该关就通过了。
总结:这一关主要考查Java的反编译和Applet程序嵌入网页的机制。
Level 5
网址:http://www.try2hack.nl/levels/level5-fdvbdf.xhtml
来到第五关:
该关要求下载一个东西,然后输入正确的用户名和密码。
下载下来之后,发现是一个exe的可执行文件,然而该可执行文件在win64位机器上面跑不起来,提示不兼容。于是在win32的虚拟机运行该文件,提示缺少VBRUN300.DLL,于是又去网上下载这个dll,安装后再打开该软件,呈现如下界面:
尝试输入几个用户名和密码,均提示不正确,因此这绝对是一个软件的破解了,软件逆向之后找到验证的部分就行了。于是奠出我们的神器Ollydbg。Ollydbg逆向的时候却提示这不是一个有效的可执行文件。
于是查资料发现这是一个VB3.0程序,比较老,需要用专门的VB3.0反编译工具而不能用OD。于是又得去找专门的VB3.0的反编译工具,在这里我不得不吐槽一下国内软件的下载环境,这是像坨屎一样垃圾,不是有毒就是给你装一堆稀巴烂的软件,真是深恶痛绝!把时间都浪费在这些事情上面,给初学者带来巨大的麻烦!
最终下载的是VB3.0 Decompile,下载下来之后又学了半天怎么用,最后把我们的exe文件导入,选择输出地址之后,得到了两个文件。一个文件是main.txt,另一个文件是Level5.bat。
显示内容分别如下:
main.txt:1
2Global Const gc0006 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,:;-*+=~|&!_$#@()[]{}<\/>"
Global Const gc000A = "http://www.try2hack.nl/levels/level6-ksghvb.xhtml"
Level5.bat:1
2
3
4
5
6If edtUsername = Mid(gc0006, 56, 1) & Mid(gc0006, 28, 1) & Mid(gc0006, 35, 1) & Mid(gc0006, 3, 1) & Mid(gc0006, 44, 1) & Mid(gc0006, 11, 1) & Mid(gc0006, 13, 1) & Mid(gc0006, 21, 1) Then
If edtPassword = Mid(gc0006, 45, 1) & Mid(gc0006, 48, 1) & Mid(gc0006, 25, 1) & Mid(gc0006, 32, 1) & Mid(gc0006, 15, 1) & Mid(gc0006, 40, 1) & Mid(gc0006, 25, 1) & Mid(gc0006, 14, 1) & Mid(gc0006, 19, 1) Then
MsgBox "Level 6 can be found at: " & Left$(gc000A, 37) & Mid(gc0006, 21, 1) & Mid(gc0006, 14, 1) & Mid(gc0006, 29, 1) & Mid(gc0006, 32, 1) & Mid(gc0006, 12, 1) & Mid(gc0006, 14, 1) & Mid(gc000A, 44, 6), 0, "Horray!"
End
End If
End If
很明显,这相当于把用户名和密码告诉我们了,按照程序照着对应的字符去找就行了,最后输入用户名:Try2Hack,密码:ILoveDodi,得到如下界面就过关了。
总结:这一关主要考查VB3.0程序的反编译。
Level 6
网址:http://www.try2hack.nl/levels/level6-kdsvbd.xhtml
来到第六关,这次变成了VB6.0程序:
下载下来之后打开,360杀毒软件也真是狠,报告有木马,一定要删除刚下载的文件,最后把所有360程序全部关闭了。才能把程序打开。结果打开程序又出现问题,提示缺少两个组件,分别下载安装MSWINSCK.OCX和RICHTX32.OCX后才总算打开了:
可以逆向吗?OD打开后看到的景象真是惨不忍睹:
应该是加壳了,如果直接脱壳的话,应该能解出来,但我对这块不熟。
观察发现该客户端软件需要连接服务器进行验证,有网络的发包过程,因此可以截取其数据包进行观察。这里存在一个问题就是如果用burpsuit进行截取的话,软件的请求格式由于不是正规的http协议,无法解析。因此考虑用Wireshark,抓包如下:
可以看到中间的http协议增加了一个中间层,是加密的数据,提取出来如下所示:1
2
3
4
5
6
7
8
9
10
11(ENCRYPTION TYPE)
B*C*N**N
(USERNAME)
aaabb aaaaa aaaab abbab ababb aaaab
(PASSWORD)
aabaa abbaa aaaba baaaa babba abbba baaba abaaa abbab abbaa baaaa aaaaa babaa abaab baaab
(PAGE)
babab aabab abaab abbab aabbb aaaba
谷歌之后这里采用的是培根加密,具体介绍参见:http://h2g2.com/edited_entry/A9837183
根据如下密码表对应进行一一解密:
最后解密出来的结果为:1
2
3用户名:dabomb
密码:encryptionrawks
URL:xfkohc
输入之后就通过了:
总结:这一节主要考查软件的脱壳或者从中间抓包截取数据和对一些加解密算法的了解
Level 7
网址:http://www.try2hack.nl/levels/level7-xfkohc.php
打开之后它要求我们用IE7.66版本的浏览器。可以人为修改请求头进行欺骗。
第一步正常请求头应为:
修改为IE7.66,如下(注意User-Agent字段):
结果显示:
服务器传过来要求操作系统为Linux系统,继续修改,在请求头中增加Linux:
反馈如下,服务器对跳转页面还有要求:
继续改,增加一个Referer字段,如下:
最后得到结果如下:
通过了。
总结:该关主要考查对http请求头的构造和理解,其实都是可以伪装的。
Level 8
网址:http://try2hack.nl/levels/level8-balnrg.xhtml
第八关要求输入用户名和密码:
查看页面源代码:
因此这是一个phf漏洞的利用,具体介绍可参见维基百科。
利用过程为输入如下URL:
http://try2hack.nl/cgi-bin/phf?Qalias=%0A/bin/cat%20/etc/passwd
得到一份如下的文件:
1 | root:khXGN7s.ldaJI:0:0::0:0:Charlie &:/root:/usr/local/bin/bash |
如果搞过密码档的话,这些东西就是经过系统加密的网站注册用户资料文档,其中冒号前面是用户名,用户名是不加密的,冒号后面就是该用户的密码,不过已经被系统加密。绝大部分Unix系统都使用DES加密方式,经过处理的密码应该是13位。注意看第一条记录,这样就只需解密用户root对应的密码“khXGN7s.ldaJI”就行了。
用什么解密呢?网上大部分的在线DES加密解密网站都是需要我们自己输入密钥的,因此这些网站对我们破解该密码一点卵用都没有,知道密钥了我还要你破解个毛线啊!后来我找了半天,终于找到了这个软件:John the Ripper password cracker,具体用法请参考此文。
最后我用的是穷举模式进行的破解,得到结果如下:
可以看到用户名是:root,密码是:arse,顺利通过。
总结:该关主要考查对pfh漏洞的利用以及EDS密码的破解。
Level 9
网址:http://try2hack.nl/levels/level9-gnapei.xhtml
这是第九关:
同样是输入用户名和密码。
用burpsuit拦截后分析,观察到其请求头如下:
观察cookie,会发现其很有特色,分别是用户名、密码和是否被验证的标志位。
按照会话管理的常理来说,一般会话的cookie检验通过了的话,是不需要检验浏览器提交的用户名和密码了的,于是我第一次是在cookie中将请求是否验证标志位由no改为了yes,提交之后,显示失败。可知服务器还是需要用户名和密码的,这里的用户名和密码输入可以和cookie一样,并且把验证标志位改为yes,再次尝试:
提交之后就顺利通过了。
总结:这关考查我们的cookie绕过。
Level 10
这一关开始页面如下:
要求我们下载一个IRC的客户端软件,然后登陆irc.mediamonks.net服务器的#try2hack.level10房间。
这里我搞了很久,登陆进去之后如下图所示:
这么多0和1构成的字符串,是二进制的,首先想到的二进制解密,但非常蛋疼的是,这个IRC聊天软件居然不能复制,只能先保存成图片,然后进行文字识别。找了半天,终于找到这个网站提供在线的文字识别,然后又到这个网站进行二进制文件的解密。解密出来的字符串为:
Nice job. Now type ‘/msg TRY2HACK showbug’ to see the bug
输入之后,给出的回复如下:
这看起来像一段脚本,感觉又被加密了的,这是用ROT13进行加密的,ROT13加密常被应用于聊天中或网路论坛用作隐藏八卦、妙句、脏话等。
在这个网站中将这段文字在线解密得到如下结果:1
2
3
4
5
6bind ctcr - PING ctcr:pingreply
proc ctcr:pingreply {nick uhost hand dest key arg}
{
set dur [expr [unixtime] - $arg]
putserv "NOTICE $nick :Your ping reply took $dur seconds"
}
这应该是一个活动主机检测的脚本。然后后面我也不知道该怎么做了,国外有人给出了解决方案,但我没有看懂。如果有人弄懂了,欢迎联系我。
Level 11
网址:http://www.try2hack.nl/levels/level11-vmituh.xhtml
第十一关开始的页面如下:
上面的字符串和数字均是随机生成的
它的要求就是在5秒内输入指定位数的字母对应的ASCII码的十进制值的乘积的前5位数字。
首先想到的是修改response,然后修改页面属性。使其把时间延长至无限,再手工算出来,填进去,这是一个解决方案。另一个解决方案是写一段脚本,自动计算后填进去。具体代码后面再给出。
总结:这部分考查我们写一段小脚本的能力。
Level 12
网址:http://www.try2hack.nl/levels/level12-kvdsju.xhtml
显示页面为:
下载之后发现是一个以.pyc为后缀名的文件。pyc是python的字节码文件,因此需要反编译查看源码,在这个网站可以进行python的在线反编译。
反编译后得到如下代码:
1 | from md5 import new |
由于Python版本不一样,以上代码稍加修改后就能正常运行了。
MD5是消息摘要算法,提供消息的完整性保护。这段代码的意思是密码自生成并且自检验,只要符合算法规则的用户名和密码都是合理的。
总结:这部分考查Python反编译和算法。
Level 13
网址:http://www.try2hack.nl/levels/level13-olwehfdow.xhtml
终于来到最后一关了,显示页面如下:
显示需要下载文件,这个文件比较大,有60多兆。
Sleuth Kit是一个用来分析磁盘映像和恢复文件的开源取证工具。
这是Linux的一个文件系统,我们需要挂载该文件系统。
最后得到密码为:f1ff950850ac2f1f51fa82d839f0bd1b
然后出现如下页面:
已经全部通关了。
总结:这部分考查对Linux系统的了解。
总结
Web攻击学无止境,关键在于把基本知识掌握之后,要熟悉很多常见的漏洞及利用方式,然后再加以创造性的综合利用,渗透工程师是一门非常需要积累和经验的工作。而做一名安全构架师,则更是任重而道远。这是需要花时间和精力去认真修炼打磨的。积累自己的势能。
这个try2hack网站太老了,很多技术都已经过时,不过用来训练思维还是不错的。
任何语言都是可以反编译的。还需要提高自己逆向的能力以及加强对底层的了解。
基础还不够,必须要精通一门语言才行,例如第十一关,写一段小代码都要写半天。
最后,Level10-13还有待修改完善,以及原理还有待弄懂。未完,待续。
【版权声明】
本文首发于戚名钰的博客,欢迎转载,但是必须保留本文的署名戚名钰(包含链接)。如您有任何商业合作或者授权方面的协商,请给我留言:qimingyu.security@foxmail.com
欢迎关注我的微信公众号:科技锐新