Secret Conversation
附件有两个文件,分别是
main.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
| import secrets
from Crypto.Cipher import AES
from binascii import hexlify, unhexlify
previousCt = ""
previousPt = ""
rand_iv = secrets.token_bytes(16)
def pad(plaintext):
ext = len(plaintext) % 16
if ext != 0:
plaintext += "0" * (16 - ext)
return plaintext
def encrypt(plaintext):
pt = pad(plaintext)
if previousPt == "":
key = pt[:16]
iv = rand_iv
c = AES.new(key, AES.MODE_CBC, iv)
else:
key = previousPt[:16]
iv = previousCt[-16:]
c = AES.new(key, AES.MODE_CBC, iv)
ct = c.encrypt(pt)
return ct, iv
# if recive():
# save(recive())
# if read():
# previousCt = unhexlify(read())
# previousPt = decrypt(previousCt)
plaintext = input()
ciphertext, st = encrypt(plaintext)
print(hexlify(ciphertext + st))
# send(hexlify(ciphertext + st))
|
output.txt
1
2
3
4
| Alice: 73d7db011639016953d686a0e1a35bb41500c979211a1cf354bd54f8b38a37a866da4b221f71b2e02f9c08d24908f957
Bob: 52295dc859c7f99e0b711e438fe82009fc3bb14648437adca2ff350a26cdc23c66da4b221f71b2e02f9c08d24908f957
Alice: 89a103a7825bc8e4f6b10062c8a5ff39d224143fd2bc3e7a67085656c054719e66da4b221f71b2e02f9c08d24908f957
Bob: a3f75a5afb2f2d7dfc0fbfe9d01f17cb8aa192f9da49f009c3d467b908b72b3466da4b221f71b2e02f9c08d24908f957
|
根据题目描述,已知第一句密文的明文为hello, how are you?
从main.py代码中可以得到以下几点内容
1、第一句加密的key为明文的前16个字符
2、后一句加密使用的key是前一句明文的前16个字符
由此可以写出解密代码如下
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
| from Crypto.Cipher import AES
from binascii import hexlify, unhexlify
previousCt = "hello, how are you?"
previousPt = "73d7db011639016953d686a0e1a35bb41500c979211a1cf354bd54f8b38a37a866da4b221f71b2e02f9c08d24908f957"
rand_iv = bytes.fromhex("66da4b221f71b2e02f9c08d24908f957")
def pad(plaintext):
ext = len(plaintext) % 16
if ext != 0:
plaintext += "0" * (16 - ext)
return plaintext
def encrypt(plaintext):
pt = pad(plaintext)
if previousPt == "":
key = pt[:16]
iv = rand_iv
c = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv)
else:
key = previousPt[:16]
iv = previousCt[-16:]
c = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
ct = c.encrypt(pt.encode("utf-8"))
return ct, iv
#
def decrypt(cipertext):
key = previousPt[:16]
iv = previousCt[-16:]
print(key,iv)
c = AES.new(key, AES.MODE_CBC, iv)
ct = c.decrypt(cipertext[:-16])
return ct
# if recive():
# save(recive())
# if read():
# previousCt = unhexlify(read())
# previousPt = decrypt(previousCt)
plaintext = input()
ciphertext, st = encrypt(plaintext)
print(hexlify(ciphertext + st))
# send(hexlify(ciphertext + st))
previousPt = "hello, how are you?".encode("utf-8")
previousCt = unhexlify("73d7db011639016953d686a0e1a35bb41500c979211a1cf354bd54f8b38a37a866da4b221f71b2e02f9c08d24908f957")
previousPt = decrypt(previousCt)
print(previousPt)
previousCt = unhexlify("52295dc859c7f99e0b711e438fe82009fc3bb14648437adca2ff350a26cdc23c66da4b221f71b2e02f9c08d24908f957")
previousPt = decrypt(previousCt)
print(previousPt)
previousCt = unhexlify("89a103a7825bc8e4f6b10062c8a5ff39d224143fd2bc3e7a67085656c054719e66da4b221f71b2e02f9c08d24908f957")
previousPt = decrypt(previousCt)
print(previousPt)
previousCt = unhexlify("a3f75a5afb2f2d7dfc0fbfe9d01f17cb8aa192f9da49f009c3d467b908b72b3466da4b221f71b2e02f9c08d24908f957")
previousPt = decrypt(previousCt)
print(previousPt)
# send(hexlify(ciphertext + st))
|
最终输出结果
PatienceApp
附件内含一个可执行性文件,在windows下修改后缀后运行,结果如下
拖入IDA,可以看到以下代码,程序在这样的循环体中花费大量时间
此时有多种做法,比如直接修改掉跳转语句。这里不做过多说明,主要想通过这题,演示patch过程
通过IDA定位到长循环的汇编代码如下
其中涉及到两个跳转语句
1
2
| .text:004011F0 jle short loc_4011D5
.text:00401207 jge short loc_4011D0
|
打算将其修改成相关的跳转语句
比如
选中语句,右键选择Keypatch->Patcher
Assembly中将jle修改成jge即可,同理修改另一处,修改后的结果如下
此时通过下图选项将修改保存
此时成功将我们两次修改保存下来,退出IDA,直接运行程序,直接打印flag
It all starts from the beginning
Level: Hard
Category: Reverse Engineering
Point: 200
SB-Coin: 5
Challenge Description
Can you find the beginning!?
File:fina,Main.class
fina内容如下:
1
2
| ~T\7EWE1W;A5ZTdJ0Vag[ZREaHQEK~
|
用java反编译工具打开Main.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
| import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
public class Main {
static String passer="a";
static int run=0;
public static void main(String[] args)throws IOException {
System.out.println("you shouldn't start from here :)");
}
public static void juzbYn(String[] args)throws IOException {
String Input;
if (args[0].contains("SBCTF{")){
Input=args[0];
}
else {
run++;
if (run==5){
System.exit(0);
}
Input=passer;
}
char array[]=passer.toCharArray();
int j=0;
for (int i=0;i<array.length;i++){
if (i%5==0){
if (j!=0) {
System.out.println(i + " : " + array[i]);
char a = array[j* 5];
System.out.println(a);
array[j* 5] = array[j-1];
array[j-1] = a;
}
j++;
}
}
StringBuilder stringBuilder=new StringBuilder();
for (char ch:array){
stringBuilder.append(ch);
}
passer = stringBuilder.toString();
Ft7BEg(new String[]{args[0]});
}
public static void b837Lz(String[] args) throws IOException {
String Input;
if (args[0].contains("SBCTF{")){
Input=args[0];
args[0]="aa";
}
else {
run++;
if (run==5){
System.exit(0);
}
Input=passer;
}
char array[]=passer.toCharArray();
for (int i=0;i<array.length;i++){
if (i%5==0){
array[i]=(char)((array[i]+255)-51*5);
}
if (i%2==0){
array[i]=(char)((array[i]+282)-141*2);
}
}
StringBuilder stringBuilder=new StringBuilder();
for (char ch:array){
stringBuilder.append(ch);
}
passer = stringBuilder.toString();
FileWriter myWriter = new FileWriter("fina",true);
myWriter.write(passer+"\n");
myWriter.close();
e66Cbf(new String[]{args[0]});
}
public static void e66Cbf(String[] args)throws IOException {
String Input;
Random rand = new Random();
if (args[0].contains("SBCTF{")){
Input=args[0];
args[0]="aa";
run++;
}
else {
run++;
if (run==5){
System.exit(0);
}
Input=passer;
}
char array[]= Input.toCharArray();
System.out.println(array);
int i=0;
for (char b:array){
array[i]= (char) (b+1);
i++;
}
int randoms[] = new int[6];
for (i=0;i<5;i++){
randoms[i]= rand.nextInt(9);
}
i=0;
for (char b:array) {
array[i] = (char) (b + randoms[i % 6]);
i++;
}
StringBuilder stringBuilder=new StringBuilder();
for (char ch:array){
stringBuilder.append(ch);
}
passer = stringBuilder.toString();
juzbYn(new String[]{args[0]});
}
public static void Ft7BEg(String[] args)throws IOException {
String Input;
if (args[0].contains("SBCTF{")){
Input=args[0];
}
else {
run++;
if (run==5){
System.exit(0);
}
Input=passer;
}
char array[]=passer.toCharArray();
for (int i=0;i<array.length;i++){
if (i%2==0){
array[i]= (char) (array[i]^2);
}
}
StringBuilder stringBuilder=new StringBuilder();
for (char ch:array){
stringBuilder.append(ch);
}
passer = stringBuilder.toString();
b837Lz(new String[]{args[0]});
}
}
|
通过运行可以知道函数的运行顺序是e66Cbf->juzbYn->Ft7BEg->b837Lz
然后代码阅读可以知道一下几点内容:
- Flag开头是SBCTF{
- e66Cbf:随机生成一个长度为6的数组randoms,将用户输入后的Flag,先每个字符都+1,再根据索引i,每个字符加上randoms[i%6],逆过程可以根据Flag开头6位的变动可以推出实际的randoms
- juzbYn:将上一步的结果的前6位,分别与索引5,10,15,20,25的字符交换位置。逆过程是同样的。
- Ft7BEg:偶数索引的字符与2做异或。逆过程是同样的
- b837Lz:将结果输出到文件中。函数内的循环是一个烟雾弹
基于以上几点内容,写出以下脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| prefix = "SBCTF{"
result = "~T\\7EWE1W;A5ZTdJ0Vag[ZREaHQEK~"
rlist = list(result)
for i in range(len(rlist)):
if i % 2 == 0:
rlist[i] = chr(ord(rlist[i]) ^ 2)
j = 0
for i in range(len(rlist)):
if i % 5 == 0:
if j != 0:
rlist[i], rlist[j - 1] = rlist[j - 1], rlist[i]
j += 1
randoms = []
for i in range(6):
randoms.append(ord(rlist[i]) - ord(prefix[i]))
rlist[i] = prefix[i]
for i in range(6, len(rlist)):
rlist[i]=chr(ord(rlist[i])-randoms[i%6])
print("".join(rlist))
|
运行后的结果如下: