flaren-on11_re_by_Flooc

1-frog

1
2
3
4
5
6
cipher = "\xa5\xb7\xbe\xb1\xbd\xbf\xb7\x8d\xa6\xbd\x8d\xe3\xe3\x92\xb4\xbe\xb3\xa0\xb7\xff\xbd\xbc\xfc\xb1\xbd\xbf"

for i in range(1000):
tmp = ("".join([chr(ord(x) ^ i) for x in cipher]))
if("flare" in tmp):
print(tmp)

2-checksum

go逆向,使用xchacha20poly1305加密flag.jpg。

与正常的chacha20poly1305不用的是,x___是扩展版的,key仍是32字节,nonce变成24字节。

逻辑就是先整几个随机数,然后输入他们的和,check一下对不对,最后输入64长度的key,然后将它hex编码。。

先IDA反编译一下,看到这里nonce应该是取自32字节的key的前24字节

然后就是将key异或后base64,这里IDA动调到的是错的,不知道为什么,可能是我前面nop了不改nop的东西?

有一个main_encryptedFlagData,有0x2c52c的字节的大小,应该就是加密后的flag了,用python脚本拿出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import idc


address = 0x32DA80
arr = []
for i in range(0x2c52c):
arr.append(idc.get_wide_byte(address + i))

with open(r"C:\Users\86158\Downloads\ebcrypted_data.bin", "wb") as p:
for i in arr:
p.write(i.to_bytes(1, byteorder='little'))

print("ok")
print(hex(len(arr)))

用ghidra和bn看到最后的Base64check的key密文数据

拿出来解密一下得到key:
1
2
3
4
5
6
7
8
9
10
11
12
import base64
cipher = "cQoFRQErX1YAVw1zVQdFUSxfAQNRBXUNAxBSe15QCVRVJ1pQEwd/WFBUAlElCFBFUnlaB1ULByRdBEFdfVtWVA=="

data = base64.b64decode(cipher)

cipher1 = list(data)

table = "FlareOn2024"

for i in range(len(cipher1)):
print(chr(cipher1[i] ^ ord(table[i % len(table)])),end='')
print()

最后就是写个go脚本解密这个文件

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
package main

import (
"fmt"
"io/ioutil"
"log"

"golang.org/x/crypto/chacha20poly1305"
)

func main() {
// 密钥和随机数
key := []byte{0x7f, 0xd7, 0xdd, 0x1d, 0x0e, 0x95, 0x9f, 0x74, 0xc1, 0x33, 0xc1, 0x3a, 0xbb, 0x74, 0x0b, 0x9f,
0xaa, 0x61, 0xab, 0x06, 0xbd, 0x0e, 0xcd, 0x17, 0x76, 0x45, 0xe9, 0x3b, 0x1e, 0x38, 0x25, 0xdd}
nonce := []byte{0x7f, 0xd7, 0xdd, 0x1d, 0x0e, 0x95, 0x9f, 0x74, 0xc1, 0x33, 0xc1, 0x3a, 0xbb, 0x74, 0x0b, 0x9f,
0xaa, 0x61, 0xab, 0x06, 0xbd, 0x0e, 0xcd, 0x17}

// 打开加密文件
ciphertext, err := ioutil.ReadFile("C:\\Users\\86158\\Downloads\\encrypted_data.bin")
if err != nil {
log.Fatal(err)
}

// 创建xChaCha20-Poly1305密钥
aead, err := chacha20poly1305.NewX(key)
if err != nil {
log.Fatal(err)
}

// 解密数据
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
if err != nil {
log.Fatal("解密失败: ", err)
}

// 将解密后的内容写入文件
err = ioutil.WriteFile("decrypted_output.jpg", plaintext, 0644)
if err != nil {
log.Fatal(err)
}

fmt.Println("解密成功,内容已写入 decrypted_output.txt")
}

3-aray

手搓。。

先提取每个字节相关的condition,与crc32和md5的condition:

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
import re

filesize_lines = []

crc_lines = []

md5_lines = []

i_lines = [[] for c in range(85)]
print(len(i_lines))

with open(r"C:\Users\86158\Downloads\flare\aray.yara", "r") as p:
line = p.readline()
while line:
if "filesize" in line:
filesize_lines.append(line.replace(" and", "").strip())
if "crc" in line:
crc_lines.append(line.replace(" and", "").strip())
if "md5" in line:
md5_lines.append(line.replace(" and", "").strip())
for i in range(85):
if "uint8({})".format(i) in line or "uint32({})".format(i) in line:
i_lines[i].append(line.replace(" and", "").strip())
line = p.readline()
for x in range(len(i_lines)):
print(i_lines[x])
print()
print(filesize_lines)
print()
print(md5_lines)
print()
print(crc_lines)

先算hash相关的几个字节,采用爆破,大概模板是一样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import hashlib
import zlib

filesize = 85

# 示例 bytes 对象
# data = b"hello"
# # # 计算 SHA-256
# md5_hash = hashlib.md5(data).hexdigest()
# print(md5_hash)

# 计算 CRC32
for a in range(3,156):
for b in range(6, 154):
data = a.to_bytes(1, byteorder="big") + b.to_bytes(1, byteorder="big")
# print(data)
if a ^ filesize != 88 and a ^ filesize != 30 and a & 128 == 0:
if b ^ filesize != 22 and b ^ filesize != 223 and b & 128 == 0:
md5_hash = hashlib.md5(data).hexdigest()
if md5_hash == "f98ed07a4d5f50f7de1410d905f1477f":
print(data)

剩下的就是可以直接计算结果的,要注意uint32的计算完要反过来赋值,比如uint32(3):

1
2
3
4
3 -> 0x65
4 -> 0x20
5 -> 0x66
6 -> 0x6c

最后搓出来下面这样的,我这里用字典表示。。:

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
known_data = {0: "r",
1: "u",
2: 108,
6:0x6c,
5:0x66,
4:0x20,
3:0x65,
7: 67,
8: "r",
9: "e",
13:0x7b,
12:0x20,
11:0x6e,
10:0x6f,
16: 116,
20:0x67,
19:0x6e,
18:0x69,
17:0x72,
21: 115,
25:0x66,
24:0x24,
23:0x20,
22:0x3a,
26: 34,
27: 60,
31:0x52,
30:0x31,
29:0x22,
28:0x20,
32: "u",
33: "l",
34: "e",
35: "A",
36: 68,
40:0x33,
39:0x4b,
38:0x79,
37:0x61,
44:0x4d,
43:0x24,
42:0x70,
41:0x33,
45: 97,
49:0x72,
48:0x34,
47:0x77,
46:0x6c,
50: "3",
51: "A",
55:0x40,
54:0x79,
53:0x34,
52:0x77,
58: 97,
62:0x6f,
61:0x2d,
60:0x65,
59:0x72,
63: "n",
64: ".",
65: 99,
69:0x20,
68:0x22,
67:0x6d,
66:0x6f,
73:0x64,
72:0x6e,
71:0x6f,
70:0x63,
74: 105,
75: 116,
76: "i",
77: "o",
78: "n",
79: ":",
83:0x20,
82:0x66,
81:0x24,
80:0x20,
84: 125}
# print(known_data.values())
for key, value in known_data.items():
# print(value)
if isinstance(value, int):
# print("ok")
tmpvalue = chr(value)
known_data[key] = tmpvalue
print(known_data)

filesize = 85
flag = dict(sorted(known_data.items()))
print(flag)
for key,value in flag.items():
print(value,end='')

有的位置的字节是需要爆破的,但是看一眼,flag部分的字符是连续的,在最后补上flare-on.com就行了

4-Meme Maker 3000

js混淆,,解混淆一下 https://js-deobfuscator.vercel.app
a0e是图片的base64编码,太多了删掉,逻辑很清晰了

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
const a0c = ["When you find a buffer overflow in legacy code", "Reverse Engineer", "When you decompile the obfuscated code and it makes perfect sense", "Me after a week of reverse engineering", "When your decompiler crashes", "It's not a bug, it'a a feature", "Security 'Expert'", "AI", "That's great, but can you hack it?", "When your code compiles for the first time", "If it ain't broke, break it", "Reading someone else's code", "EDR", "This is fine", "FLARE On", "It's always DNS", "strings.exe", "Don't click on that.", "When you find the perfect 0-day exploit", "Security through obscurity", "Instant Coffee", "H@x0r", "Malware", "$1,000,000", "IDA Pro", "Security Expert"];
const a0d = {
doge1: [["75%", "25%"], ["75%", "82%"]],
boy_friend0: [["75%", "25%"], ["40%", "60%"], ["70%", "70%"]],
draw: [["30%", "30%"]],
drake: [["10%", "75%"], ["55%", "75%"]],
two_buttons: [["10%", "15%"], ["2%", "60%"]],
success: [["75%", "50%"]],
disaster: [["5%", "50%"]],
aliens: [["5%", "50%"]]
};
const a0e = {

};
function a0f() {
document.getElementById("caption1").hidden = true;
document.getElementById("caption2").hidden = true;
document.getElementById("caption3").hidden = true;
const a = document.getElementById("meme-template");
var b = a.value.split(".")[0];
a0d[b].forEach(function (c, d) {
var e = document.getElementById("caption" + (d + 1));
e.hidden = false;
e.style.top = a0d[b][d][0];
e.style.left = a0d[b][d][1];
e.textContent = a0c[Math.floor(Math.random() * (a0c.length - 1))];
});
}
a0f();
const a0g = document.getElementById("meme-image");
const a0h = document.getElementById("meme-container");
const a0i = document.getElementById("remake");
const a0j = document.getElementById("meme-template");
a0g.src = a0e[a0j.value];
a0j.addEventListener("change", () => {
a0g.src = a0e[a0j.value];
a0g.alt = a0j.value;
a0f();
});
a0i.addEventListener("click", () => {
a0f();
});
function a0k() {
const a = a0g.alt.split("/").pop();
if (a !== Object.keys(a0e)[5]) {
return;
}
const b = a0l.textContent;
const c = a0m.textContent;
const d = a0n.textContent;
if (a0c.indexOf(b) == 14 && a0c.indexOf(c) == a0c.length - 1 && a0c.indexOf(d) == 22) {
var e = new Date().getTime();
while (new Date().getTime() < e + 3000) {}
var f = d[3] + "h" + a[10] + b[2] + a[3] + c[5] + c[c.length - 1] + "5" + a[3] + "4" + a[3] + c[2] + c[4] + c[3] + "3" + d[2] + a[3] + "j4" + a0c[1][2] + d[4] + "5" + c[2] + d[5] + "1" + c[11] + "7" + a0c[21][1] + b.replace(" ", "-") + a[11] + a0c[4].substring(12, 15);
f = f.toLowerCase();
alert(atob("Q29uZ3JhdHVsYXRpb25zISBIZXJlIHlvdSBnbzog") + f);
}
}
const a0l = document.getElementById("caption1");
const a0m = document.getElementById("caption2");
const a0n = document.getElementById("caption3");
a0l.addEventListener("keyup", () => {
a0k();
});
a0m.addEventListener("keyup", () => {
a0k();
});
a0n.addEventListener("keyup", () => {
a0k();
});

remake到有三个输入框的,根据条件,三个输入框内分别是:

1
2
3
b = a0c[14] = "FLARE On"
c = a0c[a0c.length - 1] = a0c[25] = "Security Expert"
d = a0c[22] = "Malware"

输入进去,alert出来了

这次只做到这了,第一次做这种题,主要还是对Linux系统和linux系统调试工具不是很熟悉,再加上是第一次做这种很像取证的题目,被硬控了很长时间也没做出来。

网上能搜索到很多大佬的WP,看完后也是有很大感悟。