刚刚参与了2024年ISCC2024年第21届信息安全与对抗技术竞赛,我们体验了一场紧张而充满挑战的竞技之旅。现在,让我们共同回顾一下竞赛中那些引人入胜的题目和巧妙的解题方法吧!在今天的讨论中,我们将专注于剖析那些与RE题目及其解答方法!
迷失之门
1.查壳发现64位无壳
2.ida64打开
3.开始找
发现没有正确输出,推断check函数可能会关键函数,跟进进行分析
发现错误输出但是没有发现正确输出,继续跟进check_2函数
发现如图,当result=a1[0]时,result=F
此时发现正确返回
得到明文FSBBhKZuUgLKVjJVSCFTUrctpG6
继续分析得
一个经典的换表,首先将输入(密文)与v3进行比较(密钥)
如果相减小于0则输出flag错误
接着继续比较减的过程,怎么减备注也写在上面了
然后开始写逆向算法
首先如果输入和v3相减小于25的话,此时需要将v16表换入
首先如果输入和v3相减大于25小于51的话,此时需要将v10表换入
首先如果输入和v3相减大于51的话,此时需要将v4表换入
如下
Exp
v16 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
v10 = "abcdefghijklmnopqrstuvwxyz"
v4 = "0123456789+/-=!#&()?;:*^%"
v3 = "DABBZXQESVFRWNGTHYJUMKIOLPC"
flag = []
a1 = "FSBBhKZuUgLKVjJVSCFTUrctpG6"
for i in a1:
if i in v16:
flag.append(v16.index(i))
elif i in v10:
flag.append(v10.index(i) + 26)
elif i in v4:
flag.append(v4.index(i) + 52)
for i in range(len(flag)):
print(chr(ord(v3[i]) + flag[i]), end="")
print()
CrypticConundrum
1.先用upx脱壳
2.然后进行分析,如下图
3.跟进加密算法
Exp:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
void decrypt(char* enc, char* key1, int len_key2) {
uint8_t v4;
int i;
int m;
int k;
int j;
for (int i = 0; i < len_key2; i++) {
enc[i] -= 10;
}
for (int m = 0; m <=len_key2-2; ++m) {
enc[m] += enc[m + 1];
}
for (int k = 0; k < len_key2 - 1; ++k) {
enc[k] ^= key1[2];
}
for (int j = 0; j < len_key2; j += 2) {
enc[j] ^= key1[j % 4];
}
for (int i = 0; i < len_key2; ++i)
enc[i] += key1[i % 4];
}
int main() {
char enc[] = {};
char key1[] = "ISCC";
char key2[] = "So--this-is-the-right-flag";
int len_key2 = 26;u'p;
decrypt(enc, key1, len_key2);
puts(enc);
return 1;
}
Badcode
1.魔改xxtea算法
开始分析代码
2.跟进伪随机数函数
3.v3为key值,将伪代码转化为c语言运行得出key
4.继续返回主函数进行分析
5.跟进btea算法进行分析
逆向得exp
Exp
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t* v, int n, uint32_t const key[4])
{
uint32_t y, z, sum,a;
unsigned p, rounds, e;
if (n > 1)
{
rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v
;
z = v
+= MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}
else if (n < -1)
{
n = -n;
rounds = 6 + 52 / n;
sum = rounds * DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v
;
y = v
-= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= DELTA;
} while (--rounds);
}
}
int main(){
unsigned int Buf2[6];
Buf2[0] = 0xB3F3CAB4;
Buf2[1] = 0x4D61D3ED;
Buf2[2] = 0xBD4B08DD;
Buf2[3] = 0x8BF53D90;
Buf2[4] = 0x2DA72EB8;
Buf2[5] = 0x5696F098;
unsigned int key[] = { 0x12345678,0x9ABCDEF0,0x0FEDCBA98,0x76543210 };
btea(Buf2, -6, key);
unsigned char* p = (unsigned char*)Buf2;
unsigned char aaa[24] = {0};
for (int i = 0; i < 24; i++)
{
aaa[i] = p[i];
}
char encbuf[] = "674094872038771148666737";
for (int i = 0; i < 24; i++)
{
aaa[i]=(encbuf[i] - '0') ^ aaa[i];
}
for (int i = 0; i < 24; i++)
{
if (i % 2)
{
aaa[i] -= 2;
}
else {
aaa[i] += 3;
}
}
printf("%s",aaa);
}
DLLCode
1.首先分析得是对密文的奇数位和偶数位进行分别运算
2.接着动调进入
进行分析
发现文件进入了BH_Dll中,分析发现文件将偶数位和block进行异或加密
3.接着跟进进行分析
发现是将奇数替换成v4数组中的数据
4.继续进行分析
找到密文,直接写exp代入即可得flag
Exp
key1=[ord(i) for i in "ISCC"]
v4=[]
enc=[]
flag=[0]*24
for i in range(12):
flag[2*i+1]=enc[v4[i]+12]
for i in range(12):
enc[i]^=key1[i&3]
flag[2*i]=enc[i]
print(bytes(flag))
WinterBegins
1. ida打开发现存在控制流平坦化
2. 用d810插件去平坦化
3. 从主函数开始进行静态分析
4. 跟进encode1进行分析
5. 跟进encode2进行分析
6. 分别跟进以上三个函数进行分析
7. 下断点dump密文
然后就开始逆
解密的时候有几个细节要注意
获取到的index得//2
步长跨两步因为是中文字符
如果是11就拿后面的元素+61
因为这里是v4[v3++]=11 把上一个元素值替换成了11可以当成标记 然后拿下一个-61
Exp
table = "冻笔新诗懒写寒炉美酒时温醉看墨花月白恍疑雪满前村"
enc = "美酒恍疑时温寒炉美酒寒炉寒炉懒写墨花前村时温时温前村恍疑醉看新诗醉看美酒醉看新诗墨花墨花醉看月白墨花墨花墨花冻笔墨花醉看醉看恍疑醉看新诗醉看前村月白醉看前村时温醉看月白醉看时温醉看恍疑墨花新诗醉看前村墨花墨花月白墨花前村墨花"
index_l = []
flag = ''
for i in range(len(enc)//2):
index_l.append(table.index(enc[i*2:(i+1)*2])//2)
print(index_l)
i = 0
while (i<len(index_l)):
if index_l[i]==11:
flag += chr(index_l[i+1]+61)
i += 2
else:
flag += chr(index_l[i]+48)
i += 1
for i in range(len(flag)//2):
print(chr(int(flag[i*2:(i+1)*2],16)),end='')
Find_All
1.ida打开发现存在反调试
2.很经典的反调试,直接把jz改成jmp就可以过掉反调试
3.可以发现是一个迷宫,分析一下
4.编写解迷宫代码
运行得迷宫图
迷宫图出来了直接手搓迷宫路线
ddssddwwdddssssssss
迷宫路线就是压缩包密码
压缩包里面是一堆16进制,不知道干啥的。
5.于是开始分析汇编层,发现程序藏了一个函数跟进看一下
6.分析得这个是后一位和前一位异或没啥难的逻辑
7.找到密文直接秒了
Exp
#include<stdio.h>
#include <stdlib.h>
int main() {
int v4_len = 0,i = 0;
char v4[25] = { 0 };
v4[0] = 26;
v4[1] = 16;
v4[2] = 0;
v4[3] = 67;
v4[4] = 12;
v4[5] = 55;
v4[6] = 22;
v4[7] = 86;
v4[8] = 30;
v4[9] = 89;
v4[10] = 8;
v4[11] = 110;
v4[12] = 37;
v4[13] = 0;
v4[14] = 50;
v4[15] = 81;
v4[16] = 24;
v4[17] = 103;
v4[18] = 124;
v4[19] = 67;
v4[20] = 97;
v4[21] = 97;
v4[22] = 92;
v4[23] = 125;
v4_len = sizeof(v4) / sizeof(v4[0]) - 1;
for (i; i < v4_len; i += 4) {
v4[i + 2] ^= v4[i + 3];
v4[i + 1] ^= v4[i + 2];
v4[i] ^= v4[i + 1];
}
puts(v4);
return 0;
}
I_am_the_Mathematician
1.shift+F12查看一下字符串
发现有很多和斐波那契数列有关的信息,还有一串二进制数据
2.转换一下二进制
发现还是与斐波那契数列相关
测量了一下长度为18,
试一下是不是斐波那契数列的前18个数字为索引
然后读取codebook里面的数据
Exp
def fib(n):
"""生成斐波那契数列的前 n 个数字"""
a, b = 0, 1
lis = []
for _ in range(n):
a, b = b, a + b
lis.append(a)
return lis
with open("code_book_14.txt", "r") as file:
data = file.read()
target = fib(20) # 指定斐波那契数列的长度为 20
output = ""
for i in target:
if i <= len(data): # 注意这里的条件判断,改为小于等于号
output += data[i - 1]
print("ISCC{" + output + "}")
AI
https://tool.lu/pyc/
import base64
a = '123456789012345678901234'
b = 'TWF/c1sse19GMW5gYVRoWWFrZ3lhd0B9'
c = list(base64.b64decode(b))
for d in range(len(c)):
c[d] ^= int(a[d])
if d % 2 == 0:
c[d] -= int(a[d])
else:
c[d] += int(a[d])
print("".join(map(chr, c)))
Key{Y0u_F1nd_The_key_w@}
解压出来一个模型和图片,用模型识别图片,得到压缩密码,解压出来替换表,替换密码就是flag
import torch
import torch.nn as nn
from torchvision import transforms
from PIL import Image
class ConfusedNet(nn.Module):
def __init__(self):
super(ConfusedNet, self).__init__()
self.layer1 = nn.Linear(28 * 28, 128)
self.layer2 = nn.Linear(128, 64)
self.layer3 = nn.Linear(64, 10)
def forward(self, x):
x = x.view(-1, 28 * 28)
x = torch.relu(self.layer1(x))
x = torch.relu(self.layer2(x))
x = self.layer3(x)
return x
m = torch.load('./confused_digit_recognition_model.pt')
m.eval()
t = transforms.Compose([
transforms.Grayscale(num_output_channels=1),
transforms.Resize((28, 28)),
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
def get_predictions(mod, trans):
preds = []
for img_index in range(1, 25):
img = Image.open(f"E:\shili\attachment-35\AI-12\{img_index}.png")
img_trans = trans(img)
img_trans = img_trans.unsqueeze(0)
with torch.no_grad():
output = mod(img_trans)
_, pred = torch.max(output, 1)
preds.append(pred.item())
return preds
preds = get_predictions(m, t)
enc_str = ""
for idx, pred_class in enumerate(preds, start=1):
enc_str += str(pred_class)
enc_list = [int(x) for x in enc_str]
flag_str = ""
for val in enc_list:
if val == 0:
flag_str += "@nd"
elif val == 1:
flag_str += "a!"
elif val == 2:
flag_str += "_"
elif val == 3:
flag_str += 'F'
elif val == 4:
flag_str += "SSS"
elif val == 5:
flag_str += "W@"
elif val == 6:
flag_str += "K"
elif val == 7:
flag_str += "1"
elif val == 8:
flag_str += 'C'
elif val == 9:
flag_str += "d"
print(flag_str)
Which_is_the_flag
1.打开ida
发现存在一个反调试
2.nop掉后分析代码
继续分析得
继续分析得
3.跟进which is flag 函数
4.发现了新天地,开始动调
修改zf寄存器步入which is flag函数
跟进switch语句,在第72个switch处下断点
将hex转字符
然后再base64解码,得出flag
今天,我们将主要揭晓有关RE方向的练习题目。其他方向的题目也将在后续几天逐步公布,请大家继续保持关注!
更多资源,敬请关注ZeroPointZero安全团队
注:ZeroPointZero安全团队有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的
原文始发于微信公众号(Zacarx随笔):2024年ISCC竞赛之RE篇
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论