0x00 WEB
PHP execise -web150
这是一道分值150的web题,打开题目链接之后,看到题目界面
可以看到有一处输入的地方可以输入PHP语句
尝试执行以下phpinfo(),这里解释下,phpinfo是一个运行指令,目的为显示php服务器的配置信息。
phpinfo()输出 PHP 当前状态的大量信息,包含了 PHP 编译选项、启用的扩展、PHP 版本、服务器信息和环境变量(如果编译为一个模块的话)、PHP环境变量、操作系统版本信息、path 变量、配置选项的本地值和主值、HTTP 头和PHP授权信息(License)。
![phpinfo()](https://img-blog.csdn.net/20170917171416943?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后发现禁用了以下的函数
![函数禁用](https://img-blog.csdn.net/20170917171806352?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接着可以输入一下代码
foreach (glob("./*") as $filename) { echo $filename."<br>"; }
来获取当前目录
再用highlight_file()函数读取flag文件
附上highlight_file()用法
![这里写图片描述](https://img-blog.csdn.net/20170917191705676?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
wanna to see your hat? -web250
这是一道分值250的web题
打开题目链接之后???
肿么肥事,给我一堆帽子??还好不是绿色的
点击下面的链接之后
发现一个输入框输入名字,当然随便输入了点东西,之后…………
???!!!
他还真的绿了……
暂时没发现什么特别的
查看了一下register的界面
假设,这道题存在sql注入的漏洞。当然这还不是最后的结论,当我在一通操作之后,发现还是没有突破。
那就要考虑下自己的方向是不是错了,然后考虑一下尝试别的常见的题型,比如源码泄露,这里利用自己搜集的字典,用一些扫描工具扫一下,果然,发现了源码泄露
![这里写图片描述](https://img-blog.csdn.net/20170917195856984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
svn恢复工具: https://github.com/kost/dvcs-ripper
使用方法
可以看到已经恢复完了
这里利用一个工具进行代码审计——Seay源代码审计系统
打开之后,首先寻找我们最关心的flag值,在index.php里看到了它的身影,嗯,已经很接近了,再来看看它需要什么条件。
if(isset($_SESSION['hat'])){
if($_SESSION['hat']=='green'){
output("<img src='green-hat-1.jpg'>",10);
}else{
output("<img src='black-fedora.jpg'>",1);
echo $flag;
}
这里需要一个session值不为green且不为空则输出flag
然后我们继续寻找在哪里进行session的设置
嗯,有了重大突破
if (isset($_POST["name"])){
$name = str_replace("'", "", trim(waf($_POST["name"])));
if (strlen($name) > 11){
echo("<script>alert('name too long')</script>");
}else{
$sql = "select count(*) from t_info where username = '$name' or nickname = '$name'";
echo $sql;
$result = mysql_query($sql);
$row = mysql_fetch_array($result);
if ($row[0]){
$_SESSION['hat'] = 'black';
echo 'good job';
}else{
$_SESSION['hat'] = 'green';
}
header("Location: index.php");
}
}
if(strlen($name)>11)
name字段长度不能大于11
if($row[0])
只要查询语句返回不为空,就执行
尴尬的时候来了,我们不知道哪个name值返回不为空,于是猜测存在注入,其实也符合一开始的猜想,利用burpsuite抓包
测试一下是否存在注入
那么我们可以看到当我们输入了“
' or 1=1#
之后回显的结果是
\or1=1#
发现做了一定的过滤,比如空格被过滤,引号等
最后经过尝试之后,发现/**/代替空格可以绕过
![这里写图片描述](https://img-blog.csdn.net/20170917235120865?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
构造的查询语句为
select count(*) from t_info where username = 'or/**/1=1#\' or nickname = 'or/**/1=1#\'
最后得到flag
![这里写图片描述](https://img-blog.csdn.net/20170917234852873?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
0x01 MISC
传感器1
![这里写图片描述](https://img-blog.csdn.net/20170918235651649?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
曼彻斯特编码(Manchester Encoding),也叫做相位编码( Phase Encode,简写PE),是一个同步时钟编码技术,被物理层使用来编码一个同步位流的时钟和数据。它在以太网媒介系统中的应用属于数据通信中的两种位同步方法里的自同步法(另一种是外同步法),即接收方利用包含有同步信号的特殊编码从信号自身提取同步信号来锁定自己的时钟脉冲频率,达到同步目的。
根据提示,编码方式为线路码,经过查询,可能为曼彻斯特编码,然而解码结果与ID不符。尝试差分曼彻斯特编码,可以解出第一个传感器报文为0024D8893CA584181,包含已知ID。使用相同方式,第二个传感器解码为0024D8845ABF34119,因此ID为8845ABF3。
脚本一
from Crypto.Util.number import*
id1=0x8893CA58
msg1 = 0x3EAAAAA56A69AA55A95995A569AA95565556
msg2 = 0x3EAAAAA56A69AA556A965A5999596AA95656
print(hex(msg1^msg2).upper())
s = bin(msg2)[6:]
print(s)
r=""
tmp=0
for i in xrange(len(s)/2):
c=s[i*2]
if c == s[i*2-1]:
r+='1'
else:
r+='0'
print(hex(int(r,2)).upper())
脚本一需要用到crypto模块,安装过程的问题可以参考
crypto模块安装问题
脚本二
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2017-09-19 12:27:41
# @Author : Your Name (you@example.org)
# @Link : http://example.org
# @Version : $Id$
a = 0x3EAAAAA56A69AA55A95995A569AA95565556
b = 0x3EAAAAA56A69AA556A965A5999596AA95656
ba = bin(b)
print ba
ss = ""
for i in xrange(len(ba[2:])/2):
a1 = ba[i*2:i*2+2]
a2 = ba[i*2+2:i*2+4]
# print 'a1:'+a1
# print 'a2:'+a2
if a2 !='10' and a2 !='01':
continue
if a1 !='10' and a1 !='01':
ss+='1'
continue
if a1!=a2:
ss+='1'
else:
ss+='0'
# print ss
print ss
print len(ss)
ret = ''
# if '8893CA58' in ret:
print hex(int(ss,2)).upper()
#0X10024D8893CA584181L
#0X30024D8845ABF34119L
![这里写图片描述](https://img-blog.csdn.net/20170919123410687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
0x02 reverse by 极光-吹雪
溯源
1、运行一遍、看看情况
模式很简单,就是输入一段密钥,返回一个提示结果;
2、打开IDA,根据字符串“fail”锁定位置,按F5反汇编,核心代码如下:
这上面我已经根据自己的理解给部分变量添加了名字;
3、它的算法大概是这样的,首先需要用户输入一个10×10的矩阵,矩阵中每个元素的类型是dword,将矩阵命名为Memory,行以x坐标表示,列以y坐标表示。然后从存放数字0的那个矩阵位置开始,每次根据某个算法跳到另外一个位置,若成功跳转,则在跳转的同时交换这两个位置中存放的数,否则不跳转,也不交换数。经过1000×4次操作后,若Memory[i]=i (i=0…99),则输入的矩阵是成功的,否则是失败的;
4、下面先讲一讲矩阵是如何输入的,它这里并不是直接输入数字,而是输入两个大写字母,通过大写字母的偏移来算出的。比如说37=16*2+5,由于“C”的偏移为2,“F”的偏移为5,所以CF即代表37。输入时就按顺序输入100个这样的大写字母对就可以了,成功的那100个大写字母对就是最后的flag;
5、接下来分析一下跳转的算法。首先有一个长度为1000的数组byte_403230,每个元素的类型为byte,这个数组可以直接从.rdata段中读取出来,其值为:
[160, 142, 226, 128, 189, 158, 130, 145, 29, 181, 223, 138, 200, 152, 4, 76, 25, 83, 197, 181, 50, 204, 116, 198, 72, 96, 183, 251, 41, 63, 46, 254, 237, 155, 86, 206, 116, 155, 94, 132, 228, 54, 226, 88, 104, 140, 83, 246, 81, 19, 145, 255, 1, 140, 65, 82, 71, 102, 206, 34, 69, 75, 228, 220, 104, 128, 91, 76, 206, 194, 115, 158, 123, 2, 4, 114, 85, 189, 0, 149, 132, 45, 219, 153, 154, 31, 179, 30, 108, 199, 224, 34, 223, 110, 235, 106, 181, 124, 175, 250, 214, 172, 45, 74, 147, 120, 191, 60, 26, 210, 224, 47, 221, 70, 99, 142, 20, 78, 84, 83, 237, 163, 210, 66, 34, 140, 192, 251, 98, 166, 145, 195, 245, 35, 254, 190, 229, 70, 14, 21, 245, 32, 14, 145, 27, 151, 6, 43, 154, 205, 10, 91, 151, 60, 229, 182, 26, 188, 125, 81, 160, 163, 207, 130, 19, 22, 144, 144, 124, 173, 222, 182, 135, 239, 83, 56, 250, 207, 186, 211, 238, 53, 103, 198, 56, 67, 145, 218, 190, 192, 235, 210, 103, 131, 231, 18, 156, 113, 172, 180, 93, 155, 219, 96, 41, 176, 29, 167, 33, 158, 1, 13, 137, 166, 13, 148, 195, 115, 121, 129, 189, 232, 133, 94, 41, 78, 195, 120, 91, 187, 114, 187, 153, 30, 51, 223, 142, 239, 127, 105, 200, 47, 149, 88, 65, 223, 1, 4, 46, 203, 181, 6, 38, 237, 131, 167, 107, 60, 241, 161, 110, 221, 175, 181, 236, 90, 226, 96, 22, 113, 30, 135, 136, 212, 26, 111, 131, 31, 187, 131, 106, 71, 91, 235, 254, 43, 8, 52, 166, 83, 62, 151, 36, 29, 250, 97, 202, 131, 236, 159, 172, 40, 21, 61, 192, 62, 173, 26, 191, 168, 121, 115, 227, 37, 198, 87, 235, 204, 51, 45, 220, 155, 84, 104, 50, 37, 212, 59, 175, 177, 104, 156, 119, 110, 195, 202, 217, 188, 160, 122, 51, 180, 239, 20, 133, 232, 58, 235, 166, 68, 38, 209, 4, 187, 209, 41, 133, 28, 230, 60, 234, 69, 194, 213, 214, 14, 206, 241, 60, 239, 167, 126, 216, 175, 184, 138, 229, 125, 254, 30, 50, 122, 24, 4, 150, 33, 139, 127, 65, 58, 104, 102, 80, 76, 37, 29, 25, 65, 14, 61, 58, 101, 30, 94, 205, 242, 78, 63, 124, 163, 60, 45, 85, 0, 18, 78, 74, 215, 49, 147, 80, 138, 185, 30, 43, 169, 157, 223, 169, 77, 131, 97, 151, 75, 147, 251, 99, 23, 251, 32, 19, 122, 166, 209, 129, 120, 90, 204, 165, 28, 51, 79, 104, 19, 31, 75, 111, 167, 37, 201, 35, 248, 120, 215, 234, 80, 82, 255, 2, 92, 64, 105, 3, 93, 22, 39, 1, 139, 231, 71, 46, 214, 24, 67, 22, 230, 3, 213, 188, 20, 110, 180, 122, 237, 48, 132, 184, 238, 205, 40, 177, 198, 29, 201, 88, 100, 102, 253, 178, 56, 201, 223, 156, 105, 251, 137, 234, 121, 171, 236, 154, 232, 228, 203, 35, 131, 230, 83, 185, 250, 68, 200, 192, 93, 101, 223, 191, 77, 130, 122, 205, 18, 100, 135, 199, 68, 22, 236, 63, 81, 2, 154, 210, 222, 127, 18, 113, 32, 114, 18, 114, 205, 1, 140, 82, 178, 180, 226, 71, 165, 91, 57, 246, 111, 169, 97, 45, 194, 116, 127, 232, 124, 11, 69, 71, 17, 26, 4, 50, 241, 18, 39, 116, 81, 70, 72, 109, 26, 134, 206, 15, 241, 49, 64, 97, 16, 133, 176, 96, 247, 184, 228, 238, 189, 177, 80, 103, 73, 2, 102, 232, 152, 93, 2, 15, 190, 127, 157, 39, 138, 91, 13, 150, 252, 49, 193, 212, 145, 209, 180, 21, 88, 140, 233, 8, 113, 236, 2, 118, 141, 204, 110, 209, 36, 229, 212, 149, 76, 110, 57, 166, 196, 22, 16, 207, 98, 77, 40, 156, 117, 192, 120, 203, 174, 49, 251, 25, 197, 140, 9, 156, 203, 37, 21, 76, 100, 184, 201, 240, 36, 214, 236, 38, 183, 167, 27, 125, 150, 245, 186, 248, 163, 192, 236, 107, 237, 104, 31, 0, 46, 231, 137, 38, 161, 73, 44, 235, 239, 187, 145, 212, 110, 84, 37, 159, 51, 155, 137, 197, 175, 118, 225, 142, 77, 36, 71, 198, 132, 27, 209, 207, 168, 57, 70, 11, 120, 22, 115, 96, 201, 160, 229, 95, 248, 182, 43, 24, 60, 102, 119, 13, 159, 30, 111, 254, 195, 65, 97, 111, 161, 140, 45, 160, 87, 106, 195, 50, 131, 54, 126, 60, 232, 29, 54, 76, 68, 99, 45, 107, 56, 238, 187, 148, 246, 83, 42, 69, 225, 248, 162, 17, 116, 117, 47, 249, 148, 150, 32, 158, 137, 110, 3, 218, 80, 13, 121, 22, 227, 113, 241, 154, 238, 191, 10, 247, 126, 59, 232, 251, 162, 49, 151, 109, 18, 204, 1, 101, 173, 129, 112, 236, 75, 73, 214, 98, 211, 216, 228, 4, 100, 67, 114, 143, 62, 212, 214, 124, 167, 189, 136, 161, 228, 56, 77, 165, 76, 222, 111, 138, 184, 163, 98, 113, 103, 19, 74, 59, 233, 199, 242, 151, 129, 51, 15, 60, 102, 237, 134, 205, 1, 14, 212, 57, 13, 167, 193, 171, 80, 133, 193, 46, 186, 251, 157, 222, 169, 201, 160, 44, 185, 123, 129, 215, 72, 251, 250, 211, 242, 92, 83, 142, 98, 116, 189, 184, 95, 167, 138, 238, 125, 169, 137, 124, 60, 33, 234, 161, 206, 143, 15, 31, 180, 54, 185, 130, 77, 252, 237, 37, 180, 218, 240, 17, 43, 189, 184, 238, 234, 154, 166, 68, 204, 164, 209, 72, 212, 17, 24, 123, 46, 117, 132, 87, 125, 27, 204, 190, 12, 187, 85, 202, 159, 86, 41, 205, 52, 238, 208, 88, 122, 46, 139, 252, 72, 163, 162, 156, 125, 91, 154]
这时从byte_403230[999]中取出一字节数记为content_of_array,通过和十进制3作按位与运算提取出该值的最低2个二进制位,将其保存到v6(0<=v6<=3)中,若v6<2,则v7=1-v6,否则v7=5-v6,所以0<=v7<=3。v34和v35分别为16字节数,且这两个数内存空间连续。但是这个程序并不把v34和v35当成两个16字节数,而是把它当成8个4字节数。由低地址到高地址分别为:
00000000 00000001 00000000 FFFFFFFF
00000001 00000000 FFFFFFFF 00000000
我们可以等效地把v34和v35这段32字节空间解释为长度为8的4字节数组arr。arr[]={0,1,0,-1,1,0,-1,0}。
跳转就是从(x,y)这个位置跳到(x+arr[2*v7],y+arr[2*v7+1]),若新坐标不在矩阵范围内则跳转不成功,否则跳转并交换。
这时content_of_array右移两位,继续与3进行按位与运算,按刚刚所说操作。那么一个content_of_array可以提供4次跳转机会,而从byte_403230[999]到byte_403230[0]共1000个content_of_array,所以操作次数是1000×4次;
6、而我们只要编写一个逆算法就行,我们可以先建立一个矩阵,满足Memory[i]=i (i=0…99),然后穷举每一个位置,按逆算法回去,若最后的目的地位置存放的数是0,则那个矩阵就是所求输入矩阵;
7、flag为
CEBGAMBEBHDBBNCPBKBLABADCCACBIBFEOCGAOBCEGCACIEAAPBDBMCNBABBDJANCMAIAFDMAECHDACBDDCJFPBOALDHEEDGBPCFEHEIBJDLFNAGAJDKFIFHAKECEJCDAHDNEPFJFGGBDOFADCCKFDDIEDELEMCOFLFCFBDPFMCLFFGCGDENFKAADEDFFOEBEKFEEFGA
填数游戏
1、首先我必须说一下,这个填数游戏其实是数独游戏,如果不知道这个分析起来会很困难。数独游戏是一个9×9的数表,其中按3×3划分一个块,每块是一个3×3的小数表。数独游戏就是先在表中写上一些数作为已知条件,然后在“每行每列每块都不允许有数重复”的规则前提下把每一个空位全部填写完;
2、有了这些知识以后,分析起这段代码就比较容易了,只要耐心一点,基本上可以分析得八九不离十:
![这里写图片描述](https://img-blog.csdn.net/20171007162702173?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
Sudu::set_data函数中,data_start_是数独表中预先存放数的首地址,双击这个变量跟踪进去发现:
![这里写图片描述](https://img-blog.csdn.net/20171007162727595?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
数独表中空下来给用户填的部分设为了0,而非0的数都是数独题目中预先设置好的数,我们从首地址开始依次读81×4个字节(因为每个数是dword类型4字节),可以分析出该程序给我们的数独题目是这样的:
![这里写图片描述](https://img-blog.csdn.net/20171007162749485?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
set_sudu是用户填数的函数,双击跟进去:
while函数里面的Sudu::set_number就是一个一个填数的函数,双击跟进去:
![这里写图片描述](https://img-blog.csdn.net/20171007162836760?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
回到最开始的主函数,跟进Sudu::check函数:
![这里写图片描述](https://img-blog.csdn.net/20171007162858040?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
跟进块检查函数:
跟进列检查函数:
![这里写图片描述](https://img-blog.csdn.net/20171007162955002?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
跟进行检查函数:
![这里写图片描述](https://img-blog.csdn.net/20171007163014977?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
3、所以这个程序就是让你解掉前面展示的那个数独游戏,然后输入进去,原先有数的位置注意要输入0以表示跳过。至于这个数独,你可以选择自己动手玩玩,也可以直接丢到 http://shudu.gwalker.cn/ 这个网站在线解。解出的结果如下:
![这里写图片描述](https://img-blog.csdn.net/20171007163042684?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
所以flag为
340089102508406930016207058060875349709064820854392006093650071170023604602740590
![这里写图片描述](https://img-blog.csdn.net/20171007163112498?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
欢迎来到加基森
1、IDA查看程序,根据字符串定位到关键函数,暂且命名为main函数:
2、程序流程是接收16位输入,然后主要进行了sub_804A310和sub_804A5A0这2个函数的操作。第一个函数看起来很复杂,好像是某种置换加密,类似AES。
跟到第二个函数里去,发现最终的校验函数,感觉是将输入转成一个16*16的01表,然后根据预先准备的数据进行了置换和异或等操作,一次竖着取16bit进行运算,循环和final上的数据比较,总共循环16次:
![这里写图片描述](https://img-blog.csdn.net/20171007163317365?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
3、验证时候的关键代码如下:
![这里写图片描述](https://img-blog.csdn.net/20171007163338340?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
其代码可简化为:
for ( int i = 0; i < 16; ++i )
{
for ( int j = 0; j < 8; ++j )
{
table[s_box[i * 8 + j]] = (input >> j) & 1;
table[s_box[(i + 16) * 8 + j]] = (input[15 - i] >> j)&1;
}
}
for ( int i = 0; i < 16; ++i )
{
k = 0;
for ( int j = 0; j < 16; ++j )
{
k = k^(table[j * 16 + i] * data[i * 16 + j]);
}
if(k != final)
return 0;
由此可以爆破求解出这里的输入数据:
0xca, 0xd3, 0xe5, 0x43, 0xf2, 0x3c, 0x3f, 0xec, 0x33, 0xa9, 0x3f, 0x95, 0xdd, 0x8c, 0x4c, 0x2a
4、接下来是对第一个函数求解了,分析半天的,找到了一份AES源码
https://github.com/dhuertas/AES/blob/master/aes.c
根据源码比对分析,发现有几处与原始AES算法不同:
①:
![这里写图片描述](https://img-blog.csdn.net/20171007163443319?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![这里写图片描述](https://img-blog.csdn.net/20171007163455864?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
②:
![这里写图片描述](https://img-blog.csdn.net/20171007163516130?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![这里写图片描述](https://img-blog.csdn.net/20171007163531891?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
③:
![这里写图片描述](https://img-blog.csdn.net/20171007163609323?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
以上这几处,是跟原始代码有区别的地方,还有s盒,也是不一样的;
5、然后根据他对AES代码的修改,着手对手上的原始代码进行修改,首先求inv_s_box,满足条件如下:
v = s_box[16*i+j]
i + 16 * j == inv_s_box[ 16 * (v & 0xf ) + v / 0x10 ]
6、然后是逆向列混淆,由于其原理:
![这里写图片描述](https://img-blog.csdn.net/20171007163655131?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这里的 2,1,1,3 换成了13, 14, 15, 13,根据AES定义在GF(28)上的乘法和加法:
![这里写图片描述](https://img-blog.csdn.net/20171007163729438?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
求解出inv_a = {7, 1, 5, 2};
7、整改好AES后,接下来是对AES里的vm进行分析,提取出来vm的opcode,发现长度为110字节,那么可以通过opcode分析出哪些指令被调用了,然后分析那些指令就行了,分析出指令后化简其过程,得到如下结果:
t[0] = 0
t[1] = 0x10
t[2] = 0xf
while(t[0] < t[2]):
t[3] = mem[t[0]]
t[4] = mem[t[1]]
t[3] ^= t[4]
mem[t[0]] = t[3]
t[3] = 0xf - t[0]
t[4] = 0xe - t[0]
t[3] = mem[t[3]]
t[5] = mem[t[4]]
t[5] ^= t[3]
mem[t[4]] = t[5]
t[0] += 1
t[1] += 1
这里要注意的是,这个vm会对opcode进行修改
而mem上的数据,前面16字节是输入,后面是ichunqiuichunqiu
![这里写图片描述](https://img-blog.csdn.net/20171007163815389?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这里相当于:
key = "ichunqiuichunqiu"
input ^= key
input[14-i] ^= input [15-i]
所以可以分析出AES的实际加密过程:
![这里写图片描述](https://img-blog.csdn.net/20171007163852373?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
由此修改AES的原始代码inv_cipher,即可求解出我们的输入了:
![这里写图片描述](https://img-blog.csdn.net/20171007163911663?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
8、然而这并不是flag,后面才发现他打印了一张门票,实际上是个二维码,把二维码提取出来,扫描一下,就得到了真正的flag:
![这里写图片描述](https://img-blog.csdn.net/20171007163934586?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3N1X3Zj/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)