首页
社区
课程
招聘
[原创]2020太湖杯物联网安全大赛easy-app解题wp
发表于: 2022-10-8 17:10 8012

[原创]2020太湖杯物联网安全大赛easy-app解题wp

2022-10-8 17:10
8012

easy-app

题目描述

2020太湖杯物联网安全大赛easy-app,这题在网上的题解很少且不够详细。故分享下。

 

下载附件安装后打开

 

 

随便输入字符串的话,弹窗error

 

 

把apk拖入jeb去分析

 


当我们点击check按钮的时候,程序会调用check方法,参数即是我们的输入字符串,check方法的实现在native-lib.so库中

 

对其进行解包操作,获得该so库

 

 

然后将其拖入到ida中,找到Java_com_example_myapplication_MainActivity_check函数。

 

但代码量太大了,为了增强对它的理解,这里我们采用ida动态调试的方法。

题目分析

上传ida的服务端,并对它赋予可执行权限,然将其运行起来

1
2
3
4
5
6
7
8
9
10
>adb push android_server /data/local/tmp
>adb push android_server64 /data/local/tmp
 
# chmod 777 android_server64
# chmod 777 android_server
 
# ./android_server64 &
[1] 11122
taimen:/data/local/tmp # IDA Android 64-bit remote debug server(ST) v1.22. Hex-Rays (c) 2004-2017
Listening on 0.0.0.0:23946...

进行端口转发

1
>adb forward tcp:23946 tcp:23946

手机端打开应用

 

 

ida进行远程调试配置

 

 

 

选中要调试的进程

 

 

点击ok,成功调试起来了,

 

在Modules模块窗口,通过ctal+f寻找到native-lib.so

 

 

双击这个so,即可查看so库中的函数

 

 

找到目标函数Java_com_example_myapplication_MainActivity_check(),继续双击这个函数,即可查看对应的汇编代码,

 

点击tab键对其进行反编译为伪代码

 

 

参数a1其实为_JNIEnv *env,我们导入jni.h文件,然后改变下它的数据类型

 

对获取v3(即输入的字符串开始调试)的地址处下断点

 

 

通过静态分析,可以得知我们要输入的字符串长度为38位,且前5位为"flag{",最后一位为“}”

 

而中间是32位是需要我们去逆向分析得到的,这里我们我们首先先自己随便构造用来调试。

1
2
3
4
flag{                   //5
0123456789              //10
abcdefghijklmnopqrstuv  //22
}                        //1

这道题的代码量很大,完全静态分析的话回很耗时间。

 

这里用ida动态调试的方式。

 

 

 

起了个大怪,重启debug一次,发现原来是输入的时候少数如了个"d",额...麻了.

 

重新来下

 

首先将接收到的字符串,然后将其前5个字符存放到栈地址上。

 

 

然后比较输入的前五个字符是否和"flag{"一致。

 

然后比较输入的最后一个字符是否和"}"一致。

 

然后再去判断输入的字符串的长度是否为38即0x26

 

 

接下来经过了中间的32位字符串经过高位替换的函数7008D55D50()处理

1
2
3
4
5
6
处理之前
0123456789abcdef         30313233343536373839616263646566
ghijklmnopqrstuv         6768696a6b6c6d6e6f70717273747576
处理之后
60616263646566676879717273747576----->   `abcdefghyqrstuv
3738393a3b3c3d3e6f30616263646566----->    789:;<=>o0abcdef

 

然后再接下来就是个变异的tea算法处理

 


处理之后的字符串后面又经过了变异的base64的函数处理。(不小心直接run结束了,下次记得多打些断点。)

 

 

然后我们跟进去base64函数

 

 

 

 

 

通过动态调式可以得知这个base64函数并不是标准的base64算法,这次apk中将table表给替换成了"abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ+/",并且每加密三个明文得到4个密文,有将前3三个密文依次左移2个字符。

 

下面为

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
#模拟输入
flag{0123456789abcdefghijklmnopqrstuv}
#高位移换以及变异tea算法加密后的前三个密文
71 FA BD    0b1110001  0b11111010  0b10111101
#base64加密前获取偏移
 
01110001  11111010  10111101
011100 01  1111 1010  10 111101
011100  011111  101010 111101
0x1c     0x1f    0x2a    0x3d
#table表
abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ+/
 
#正常加密
 hex(ord(str[0x1c]))
'0x23'
 
 hex(ord(str[0x1f]))
'0x5e'
 
>>> hex(ord(str[0x2a]))
'0x47'
 
hex(ord(str[0x3d]))
'0x5a'
 
正常应该加密成这样
0x235e47 5a
123->231
但实际加密后是这样的
0x5e4723 5A
即这里最后一位是不变的,前三位发现都依次进行了循环右移2

加密后的结果如下

1
2
3
5E 47 23 5A 68 67 62 2A  79 76 4E 4C 68 29 77 6C  ^G#Zhgb*yvNLh)wl
77 43 63 6F 70 64 24 66  40 73 74 4B 6D 74 24 62  wCcopd$f@stKmt$b
77 7A 46 71 58 45 4A 2F  59 51 76 3D 00 00 00 00  wzFqXEJ/YQv=....

结果如果和"e)n*pNe%PQy!^oS(@HtkUu+Cd$#hmmK&ieytiWwYkIA="相等的话才会输出Congratulations,you found it!!!

 

 

所以这里需要我们进行逆向。

 

首先需要将"e)n*pNe%PQy!^oS(@HtkUu+Cd$#hmmK&ieytiWwYkIA="以4字节为单位,将每个单位的前三个字符依次右移2位。然后将其再进行base64解密,在解密的时候需要替换table为

1
abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ+/

然后将base64解密后的结果再依次进行变异的tea算法进行解密。

 

tea算法解密后还需要将结果以16字节为单位进行高位移换操作,便是最终的flag了。

 

第一步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#coding:utf8
 
base64_out="e)n*pNe%PQy!^oS(@HtkUu+Cd$#hmmK&ieytiWwYkIA="
print(len(base64_out))#44
base64_ok=""
temp=""
for i in range(len(base64_out)):
    if i%4==0:
        temp=base64_out[i:i+4]
        #print(temp)
        base64_ok+=temp[2]
        base64_ok+=temp[0]
        base64_ok+=temp[1]
        base64_ok+=temp[3]
    else:
        print("")
print(base64_ok)#ne)*epN%yPQ!S^o(t@Hk+UuC#d$hKmm&yietwiWYAkI=

base64解密

1
2
3
4
5
6
7
8
9
10
11
12
13
import base64
import string
import binascii
base64_ok="ne)*epN%yPQ!S^o(t@Hk+UuC#d$hKmm&yietwiWYAkI="
 
outtab  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
intab   = "abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
 
teaout=(base64.b64decode(base64_ok.translate(base64_ok.maketrans(intab,outtab))))#b'4H\xe1\x10\xfc^c=\x1a\xd9\xf3\xa2M\xba\xca\xfb\x85&p7G\xb8\xc3 `\x81\x13X\x8e\xbc\x90\xab'
print(teaout)
print(type(teaout))
tea_out=binascii.hexlify(teaout).decode('utf-8')#https://www.delftstack.com/zh/howto/python/python-convert-hex-to-byte/
print(tea_out)#3448e110fc5e633d1ad9f3a24dbacafb8526703747b8c320608113588ebc90ab

然后在进行tea解密

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
#include<stdio.h>
#include <string.h>
 
void decrypt(unsigned int *v, unsigned int *k)
{
  unsigned int v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
  unsigned int delta = 0x9e3779b9;
  unsigned int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
  for (i = 0; i < 32; i++)
  {
    v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
    sum -= delta;
  }
  v[0] = v0;
  v[1] = v1;
}
int main(){
    int i=0;
    unsigned int v[2] = {0, 0}, k[4] = {66, 55, 44, 33};
 
    char tea_out[64]="\x34\x48\xe1\x10\xfc\x5e\x63\x3d\x1a\xd9\xf3\xa2\x4d\xba\xca\xfb\x85\x26\x70\x37\x47\xb8\xc3\x20\x60\x81\x13\x58\x8e\xbc\x90\xab";
 
    for(i=0;i<strlen(tea_out);i+=8){
            unsigned int *v=(unsigned int *)&tea_out[i];
            //printf("%x %x\n", v[0], v[1]);
            decrypt(v, k);
            printf("%x %x\n", v[0], v[1]);
    }
      return 0;
  }
 
/*
36346065 38673534
65353537 62303531
61333232 34363160
63316239 35356761
6560343634356738373535653135306232323361603136343962316361673535
*/

最后在进行高位替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tea="6560343634356738373535653135306232323361603136343962316361673535"
tea1=tea[::2]#从0都结束 每step2进行取值     https://blog.csdn.net/Evan123mg/article/details/49232089
tea2=tea[1::2]#从1都结束 每step2进行取值
print(tea1)#6633336333363336   3336633336366633
print(tea2)#50464578755515022231016492131755
 
temp=tea1[16:]+tea1[:16] #3336633336366633  6633336333363336  高16位和低16位换位置
print(temp)
 
 
flag=""
for i in range(len(temp)):
    flag+=temp[i]+tea2[i]
print(flag)#3530346664353738376535656165303262623331303166343932316331373565
print(bytes.fromhex(flag))#b'504fd5787e5eae02bb3101f4921c175e'

然后再拼接上面的"flag{"和"}"就是正确的输入

1
flag{504fd5787e5eae02bb3101f4921c175e}

参考

2020太湖杯物联网安全大赛easy-app的wp_sln_1550的博客-CSDN博客
2020太湖杯Reverse Writeup及复盘-安全客 - 安全资讯平台 (anquanke.com)


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 3678
活跃值: (2342)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
2
大佬,附件能分享下吗
2022-10-9 11:43
1
雪    币: 606
活跃值: (1514)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
5
mark!
2023-3-19 23:37
0
游客
登录 | 注册 方可回帖
返回
//