VNCTF2023 | Reverse
BabyAnti
与WMCTF那道2一样
将AntiCheat和app 两个so都patch一下 重签名打包运行得到flag
flag{D1n0_Run_0ut_0f_The_F0rest_F1nally^_^}
PZGalaxy
在index.html找到RC4
function Leaf(k, p) {
var s = [], j = 0, x, res = '';
for (var i = 0; i < 256; i++) {
s[i] = i;
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k.charCodeAt(i % k.length)) % 256;
x = s[i];
s[i] = s[j];
s[j] = x;
}
i = 0;
j = 0;
for (var y = 0; y < p.length; y++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
x = s[i];
s[i] = s[j];
s[j] = x;
res += String.fromCharCode(p.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);
}
return res;
}
form.addEventListener("submit", (ev) => {
ev.preventDefault();
var date = document.getElementById('date').value;
var enc = ['¦', 'p', ':', 'Ü', '\x92', 'Ã', '\x97', 'ó', '\x1A', 'ß', '\b', 'Ö', 'A', ' ', '5', '\x90', '{', '\x06', 'Ô', '÷', 's', '_', '\x1D', ':', 'I', 'L', 'C', 'X', 'Ñ', '¹', 'O', '\x99', '\x85', '3', 'à', 'i', '|'];
flag = Leaf(date, enc.join(''));
if ( flag.substring(0, 4) == "flag" && date.length == 8 && date.substring(0, 4) == "2023"){
Galaxy('Neko.jpg', 50);
alert(flag);
} else{
Galaxy('Fish.jpg', 50);
alert("鱼怎么抓痒?");
}
})
思路就是爆破date
#include<bits/stdc++.h>
using namespace std;
signed main(){
int base64_table[] = {166,112,58,220,146,195,151,243,26,223,8,214,65,32,53,144,123,6,212,247,115,95,29,58,73,76,67,88,209,185,79,153,133,51,224,105,124};
string key1 = "2023";
string table="0123456789";
for(char c1:table){
for(char c2:table){
for(char c3:table){
for(char c4:table){
string key=key1+c1+c2+c3+c4;
int s[256],k[256];
int j=0;
for (int i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % key.length()];
}
for (int i2 = 0; i2 < 256; i2++) {
j = (s[i2] + j + k[i2]) & 255;
int temp = s[i2];
s[i2] = s[j];
s[j] = temp;
}
int j2 = 0;
int i3 = 0;
string flag="";
for (int i4 : base64_table) {
i3 = (i3 + 1) & 255;
j2 = (s[i3] + j2) & 255;
int temp2 = s[i3];
s[i3] = s[j2];
s[j2] = temp2;
int rnd = s[(s[i3] + s[j2]) & 255];
flag += ((char) ((i4 ^ rnd))&0xff);
}
if(flag[0]=='f'&&flag[1]=='l'&&flag[2]=='a'){
cout<<flag<<"\n";
cout<<key;
}
}
}
}
}
}
C输出的flag有乱码 但是可以得到date 20230127
靶机提交得到flag
flag{HitYourSoulAndSeeYouInTheGalaxy}
confuse_re
... 就硬考察AES的每一步...
程序采用了一大堆 call $+5
这种 f7慢慢动调能找到所有函数
输入 bor
后进入checkpasswd
unsigned __int64 __fastcall check_passwd_sub_40291F(__int64 a1, __int64 a2)
{
char v2; // al
char v3; // al
unsigned __int64 result; // rax
int i; // [rsp+4h] [rbp-28Ch]
int j; // [rsp+4h] [rbp-28Ch]
int k; // [rsp+4h] [rbp-28Ch]
int l; // [rsp+4h] [rbp-28Ch]
int m; // [rsp+4h] [rbp-28Ch]
int n; // [rsp+4h] [rbp-28Ch]
int v11; // [rsp+8h] [rbp-288h]
__int64 v12[2]; // [rsp+10h] [rbp-280h]
char v13; // [rsp+20h] [rbp-270h]
__int64 v14[2]; // [rsp+30h] [rbp-260h] BYREF
char v15; // [rsp+40h] [rbp-250h]
__int64 v16[2]; // [rsp+50h] [rbp-240h]
char v17; // [rsp+60h] [rbp-230h]
__int64 v18[4]; // [rsp+70h] [rbp-220h]
char v19[240]; // [rsp+90h] [rbp-200h] BYREF
__int64 INPUT[2]; // [rsp+180h] [rbp-110h] BYREF
char v21[232]; // [rsp+190h] [rbp-100h] BYREF
int v22; // [rsp+278h] [rbp-18h]
__int16 v23; // [rsp+27Ch] [rbp-14h]
char v24; // [rsp+27Eh] [rbp-12h]
unsigned __int64 v25; // [rsp+288h] [rbp-8h]
v25 = __readfsqword(0x28u);
v12[0] = 0LL;
v12[1] = 0LL;
v13 = 0;
v14[0] = 0LL;
v14[1] = 0LL;
v15 = 0;
v16[0] = 0LL;
v16[1] = 0LL;
v17 = 0;
v18[0] = 0x153CF38D66CCDCDCLL;
v18[1] = 0xDFD7D94616EF5E50LL;
v18[2] = 0x39A7DC6577442750LL;
v18[3] = 0xF64DD887B7FCB68LL;
INPUT[0] = 0LL;
INPUT[1] = 0LL;
memset(v21, 0, sizeof(v21));
v22 = 0;
v23 = 0;
v24 = 0;
sub_4043D8(); // a2: print password:
sub_4043F7(); // input
for ( i = 0; *((_BYTE *)INPUT + i); ++i )
;
if ( i == 32 ) // len=32
{
for ( j = 0; j <= 15; ++j )
{
sub_404444();
*((_BYTE *)v16 + j) = v2; // sub_4028F0
}
for ( k = 0; k <= 15; ++k )
{
*((_BYTE *)v12 + k) = *((_BYTE *)INPUT + k);// v12:input[:16]
*((_BYTE *)v14 + k) = *((_BYTE *)&INPUT[2] + k);// v14:input[16:]
}
sub_404462(); // sub_40462(v16,v19) sub_4026B0
sub_40449B(); // sub_40449b(v12,v19) sub_40253C
for ( l = 0; l <= 15; ++l )
{
sub_4044D4(); // v14[] = (v14[]^v12[])+1
*((_BYTE *)v14 + l) = v3; // sub_4028D2:a1^a2 + 1
}
sub_40450C(v14, v19); // sub_40253C AES
v11 = 1;
for ( m = 0; m <= 15; ++m ) // check
{
if ( *((_BYTE *)v12 + m) != *((_BYTE *)v18 + m) )
v11 = 0;
}
for ( n = 0; n <= 15; ++n )
{
if ( *((_BYTE *)v14 + n) != *((_BYTE *)&v18[2] + n) )
v11 = 0;
}
if ( v11 == 1 )
sub_404545();
else
sub_404564();
}
else
{
sub_404425(INPUT, a2);
}
result = __readfsqword(0x28u) ^ v25;
if ( result )
sub_45FE30();
return result;
}
确实对AES的实现不是很熟悉
魔改点在这里
在AddRoundKey
的时候多xor了一个0x23
这个函数
是扩展轮密钥的时候的标准函数
所以key就是 v16 动调提取出来
但我c的AES要炸... 找python的跑一跑
import re
import binascii
class Aes:
sbox = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
s_box = {}
ns_box = { }
Rcon = {
1: ['0x01', '0x00', '0x00', '0x00'],
2: ['0x02', '0x00', '0x00', '0x00'],
3: ['0x04', '0x00', '0x00', '0x00'],
4: ['0x08', '0x00', '0x00', '0x00'],
5: ['0x10', '0x00', '0x00', '0x00'],
6: ['0x20', '0x00', '0x00', '0x00'],
7: ['0x40', '0x00', '0x00', '0x00'],
8: ['0x80', '0x00', '0x00', '0x00'],
9: ['0x1B', '0x00', '0x00', '0x00'],
10: ['0x36', '0x00', '0x00', '0x00']
}
Matrix = [
['0x02', '0x03', '0x01', '0x01'],
['0x01', '0x02', '0x03', '0x01'],
['0x01', '0x01', '0x02', '0x03'],
['0x03', '0x01', '0x01', '0x02']
]
ReMatrix = [
['0x0e', '0x0b', '0x0d', '0x09'],
['0x09', '0x0e', '0x0b', '0x0d'],
['0x0d', '0x09', '0x0e', '0x0b'],
['0x0b', '0x0d', '0x09', '0x0e']
]
plaintext = [[], [], [], []]
plaintext1 = [[], [], [], []]
subkey = [[], [], [], []]
def __init__(self, key):
self.s_box = dict(zip(["0x%02x"%i for i in range(256)], ["0x%02x"%i for i in self.sbox]))
self.ns_box = dict(zip(self.s_box.values(), self.s_box.keys()))
for i in range(4):
for j in range(0, 8, 2):
self.subkey[i].append("0x" + key[i * 8 + j:i * 8 + j + 2])
# print(self.subkey)
for i in range(4, 44):
if i % 4 != 0:
tmp = xor_32(self.subkey[i - 1], self.subkey[i - 4],0)
self.subkey.append(tmp)
else: # 4的倍数的时候执行
tmp1 = self.subkey[i - 1][1:]
tmp1.append(self.subkey[i - 1][0])
# print(tmp1)
for m in range(4):
tmp1[m] = self.s_box[tmp1[m]]
# tmp1 = self.s_box['cf']
tmp1 = xor_32(tmp1, self.Rcon[i / 4], 0)
self.subkey.append(xor_32(tmp1, self.subkey[i - 4],0))
# print(self.subkey)
def AddRoundKey(self, round):
for i in range(4):
self.plaintext[i] = xor_32(self.plaintext[i], self.subkey[round * 4 + i],0x23)
# print('AddRoundKey',self.plaintext)
def PlainSubBytes(self):
for i in range(4):
for j in range(4):
self.plaintext[i][j] = self.s_box[self.plaintext[i][j]]
# print('PlainSubBytes',self.plaintext)
def RePlainSubBytes(self):
for i in range(4):
for j in range(4):
self.plaintext[i][j] = self.ns_box[self.plaintext[i][j]]
def ShiftRows(self):
p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1]
self.plaintext[0][1] = p2
self.plaintext[1][1] = p3
self.plaintext[2][1] = p4
self.plaintext[3][1] = p1
p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2]
self.plaintext[0][2] = p3
self.plaintext[1][2] = p4
self.plaintext[2][2] = p1
self.plaintext[3][2] = p2
p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3]
self.plaintext[0][3] = p4
self.plaintext[1][3] = p1
self.plaintext[2][3] = p2
self.plaintext[3][3] = p3
# print('ShiftRows',self.plaintext)
def ReShiftRows(self):
p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1]
self.plaintext[3][1] = p3
self.plaintext[2][1] = p2
self.plaintext[0][1] = p4
self.plaintext[1][1] = p1
p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2]
self.plaintext[0][2] = p3
self.plaintext[1][2] = p4
self.plaintext[2][2] = p1
self.plaintext[3][2] = p2
p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3]
self.plaintext[0][3] = p2
self.plaintext[1][3] = p3
self.plaintext[2][3] = p4
self.plaintext[3][3] = p1
def MixColumns(self):
for i in range(4):
for j in range(4):
self.plaintext1[i].append(MatrixMulti(self.Matrix[j], self.plaintext[i]))
# print('MixColumns',self.plaintext1)
def ReMixColumns(self):
for i in range(4):
for j in range(4):
self.plaintext1[i].append(MatrixMulti(self.ReMatrix[j], self.plaintext[i]))
def AESEncryption(self, plaintext):
self.plaintext = [[], [], [], []]
for i in range(4):
for j in range(0, 8, 2):
self.plaintext[i].append("0x" + plaintext[i * 8 + j:i * 8 + j + 2])
self.AddRoundKey(0)
for i in range(9):
self.PlainSubBytes()
self.ShiftRows()
self.MixColumns()
self.plaintext = self.plaintext1
self.plaintext1 = [[], [], [], []]
self.AddRoundKey(i + 1)
self.PlainSubBytes()
self.ShiftRows()
self.AddRoundKey(10)
return Matrixtostr(self.plaintext)
def AESDecryption(self, cipher):
self.plaintext = [[], [], [], []]
for i in range(4):
for j in range(0, 8, 2):
self.plaintext[i].append('0x' + cipher[i * 8 + j:i * 8 + j + 2])
# print(self.ns_box)
self.AddRoundKey(10)
for i in range(9):
self.ReShiftRows()
self.RePlainSubBytes()
self.AddRoundKey(9-i)
self.ReMixColumns()
self.plaintext = self.plaintext1
self.plaintext1 = [[], [], [], []]
self.ReShiftRows()
self.RePlainSubBytes()
self.AddRoundKey(0)
return Matrixtostr(self.plaintext)
def Encryption(self, text):
group = PlaintextGroup(TextToByte(text), 32, 1)
# print(group)
cipher = ""
for i in range(len(group)):
cipher = cipher + self.AESEncryption(group[i])
return cipher
def Decryption(self, cipher):
group = PlaintextGroup(cipher, 32, 0)
# print(group)
text = ''
for i in range(len(group)):
text = text + self.AESDecryption(group[i])
text = ByteToText(text)
return text
def xor_32(start, end, key):
a = []
for i in range(0, 4):
xor_tmp = ""
b = hextobin(start[i])
c = hextobin(end[i])
d = bin(key)[2:].rjust(8,'0')
for j in range(8):
tmp = int(b[j], 10) ^ int(c[j], 10) ^ int(d[j],10)
xor_tmp += str(tmp )
a.append(bintohex(xor_tmp))
return a
def xor_8(begin, end):
xor_8_tmp = ""
for i in range(8):
xor_8_tmp += str(int(begin[i]) ^ int(end[i]))
return xor_8_tmp
def hextobin(word):
word = bin(int(word, 16))[2:]
for i in range(0, 8-len(word)):
word = '0'+word
return word
def bintohex(word):
word = hex(int(word, 2))
if len(word) == 4:
return word
elif len(word) < 4:
return word.replace('x', 'x0')
def MatrixMulti(s1, s2):
result = []
s3 = []
for i in range(4):
s3.append(hextobin(s2[i]))
for i in range(4):
result.append(MultiProcess(int(s1[i], 16), s3[i]))
for i in range(3):
result[0] = xor_8(result[0], result[i+1])
return bintohex(result[0])
def MultiProcess(a, b):
if a == 1:
return b
elif a == 2:
if b[0] == '0':
b = b[1:] + '0'
else:
b = b[1:] + '0'
b = xor_8(b, '00011011')
return b
elif a == 3:
tmp_b = b
if b[0] == '0':
b = b[1:] + '0'
else:
b = b[1:] + '0'
b = xor_8(b, '00011011')
return xor_8(b, tmp_b)
elif a == 9:
tmp_b = b
return xor_8(tmp_b, MultiProcess(2, MultiProcess(2, MultiProcess(2, b))))
elif a == 11:
tmp_b = b
return xor_8(tmp_b, xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, b)))
elif a == 13:
tmp_b = b
return xor_8(tmp_b, xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, MultiProcess(2, b))))
elif a == 14:
return xor_8(MultiProcess(2, b), xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, MultiProcess(2, b))))
def Matrixtostr(matrix):
result = ""
for i in range(4):
for j in range(4):
result += matrix[i][j][2:]
return result
def PlaintextGroup(plaintext, length, flag):
group = re.findall('.{'+str(length)+'}', plaintext)
group.append(plaintext[len(group)*length:])
if group[-1] == '' and flag:
group[-1] = '16161616161616161616161616161616'
elif len(group[-1]) < length and flag:
tmp = int((length-len(group[-1])) / 2)
if tmp < 10:
for i in range(tmp):
group[-1] = group[-1] + '0'+str(tmp)
else:
for i in range(tmp):
group[-1] = group[-1] + str(tmp)
elif not flag:
del group[-1]
return group
def TextToByte(words):
text = words.encode('utf-8').hex()
return text
def ByteToText(encode):
tmp = int(encode[-2:])
word = ''
for i in range(len(encode)-tmp*2):
word = word + encode[i]
# print(word)
word = bytes.decode(binascii.a2b_hex(word))
return word
def xorbytes(bytes1,bytes2):
length=min(len(bytes1),len(bytes2))
output=bytearray()
for i in range(length):
output.append(bytes1[i]^bytes2[i])
return bytes(output)
res='DCDCCC668DF33C15505EEF1646D9D7DF5027447765DCA73968CB7F7B88DD640F'.lower()
key = 'CA9D7FF8A4099004FAD40661E93B775A'.lower()
A1 = Aes(key)
p1 = A1.AESDecryption(res[:32])
p2 = A1.AESDecryption(res[32:])
from Crypto.Util.number import *
p1 = long_to_bytes(int(p1,16))
p2 = long_to_bytes(int(p2,16))
flag = p1.decode()
p1 = long_to_bytes(int(res[:32],16))
for i in range(len(p2)):
flag += chr(((p2[i]-1)^p1[i])&0xff)
print(flag)
VNCTF{fa9ad36bd2de1586d944cf7b2935dd91}
jijiji
附件下载不了...
dll_puzzle
好题!
这题加了一大堆反调试... 再加上是dll 狗都不动调...
SM4~
注意到有TlsCallback 先看Tls
有两个分支 分别进入看看 猜测出来下面那个sub_1000A670
为真正分支
可以猜出来这里的xor是在生成SM4 SBOX
由最后的check 结合标准Sbox
正是标准的SM4
进入DllEntry -> DllMain
看汇编发现还有很多没有反编译 把 ret 9
patch掉
最后还有一处花指令
典型的jz jnz patch掉
start = 0x10001000
end = 0x10009000
while start<end:
if((get_wide_byte(start)==0x74) and (get_wide_byte(start+2)==0x75)):
ida_bytes.patch_byte(start+4,0x90)
start += 1
print("[+] OK !")
得到 sub_10001BA2
很容易知道是flag的check
回到前面
这里可以通过SM4_CK表引用得到SM4函数
往前找 SM4_key
这里的v42可以由后面的check算出来==42
将数据xor 42即可得到key
然后z3解出SM4的密文
注意要 Bitvec(16)
然后加 0~0xff
的约束 因为z3设置的bit长度是整个过程都不能超过的 也就是会随时取模256
得到hex的密文 cyberchef一把梭
flag{3f27d7470d8967fd344ec7f1261e64b3}