[ctf101 2023] 法国的比赛,观念不同
不是每个题都有对应的英文,有些只能网上机翻,XXXX,只作了一小部分
crypto
Encoding
hex->bytes->base64
>>> a = '4c6520666c6167206573743a205a6d78685a3374444d473548636b4230587a427558305675517a42454d57354866513d3d'
>>> bytes.fromhex(a)
>>> b'Le flag est: ZmxhZ3tDMG5HckB0XzBuX0VuQzBEMW5HfQ=='
>>> b64decode('ZmxhZ3tDMG5HckB0XzBuX0VuQzBEMW5HfQ==')
>>> b'flag{C0nGr@t_0n_EnC0D1nG}'
Substitution
这题很坑,quipquip词频的事放到crypto里,看来观念差别很大
T'MOOMQVUXV BMUDMSYMNIQZPFV CV XV YMYYZBVQV OIUCMUD CVS IVFBS, M TM YMXAIZQV XIQUVV QVSSVYWTMUD MF WVX C'FU XMUMQC, M PFVFV VGIPFMUD FU XMSDIQ, PFZ TFZ SVQD M TM BIZS CV NIFGVQUMZT CMUS T'VMF VD CV QVSVQGV CV NQMZSSV, VD M OMDDVS CV TIFDQV M BIQDVYVUD SFQOQZS TVS OQVYZVQS VJOTIQMDVFQS PFZ T'IUD CVXIFGVQD ; WIU UIYWQV CV UMDFQMTZSDVS VFQIOVVUS IUD XQF M FUV OTMZSMUDVQZV. X'VSD T'FU CVS QMQVS YMYYZBVQVS GVUZYVFJ. TV YID CV OMSSV VSD IQUZDAIQKUPFV
好在这东西也能破解法语,只不过破解完了也不认识
L'APPARENCE FANTASMAGORIQUE DE CE MAMMIFERE PONDANT DES OEUFS, A LA MACHOIRE CORNEE RESSEMBLANT AU BEC D'UN CANARD, A QUEUE EVOQUANT UN CASTOR, QUI LUI SERT A LA FOIS DE GOUVERNAIL DANS L'EAU ET DE RESERVE DE GRAISSE, ET A PATTES DE LOUTRE A FORTEMENT SURPRIS LES PREMIERS EXPLORATEURS QUI L'ONT DECOUVERT ; BON NOMBRE DE NATURALISTES EUROPEENS ONT CRU A UNE PLAISANTERIE. C'EST L'UN DES RARES MAMMIFERES VENIMEUX. LE MOT DE PASSE EST ORNITHORYNQUE
后来翻一下,最后一句是:密码是鸭嘴兽 FLAG{ORNITHORYNQUE} (为啥法语也用flag壳而不是法文呢?)
crypto 101
bin->int->bytes->base64->rot13
0011010100110101001100110011000100110110011000110011010001100110001101010011011000110100001110000011011100110011001101110110000100110101001110010011010100111000001101000011000100110111001101110011011000110011001101010011010000110100001101100011011000111000001101100011010000110100001101000011010100110110001101100011011000110110001100100011011001100100001101010011010100110111011000010011010100111000001100110011001000110101001110010011011100110111001101000110010000110100001101000011010000110010001101100011011000110110001100110011001100110010001101100011100000110110001110000011011000110110001101010011000100110011011001000011001101100100FLAG{3nc0d1ng5_ar3_s000_fun}
crypto 102
5个字符(其中1个大写)2个数字1个符号,关于hashcat的使用
字典用
?u?l?l?l?l?d?d?s
?l?u?l?l?l?d?d?s
?l?l?u?l?l?d?d?s
?l?l?l?u?l?d?d?s
?l?l?l?l?u?d?d?shashcat.exe -a 0 c102_hash.txt c102.dict.txt -m 0
#32d1eff909907fa6f5132662e8749334:plyHx22!
另外几个加密的PDF,加密的zip和巨多代码的crypto103都没作
Rev
Detective
IDA能看到,略
Obscurity
IDA能看到数字,转一下略
Reverse 1
像是python的LLVM吧,从后向前手工搓
#!/usr/bin/env python3
import argparsedef parse_args():parser = argparse.ArgumentParser(description="Can you recover the flag? If you think you got it, send it as positional argument.")parser.add_argument("flag", metavar="flag", type=str, help="The flag 🚩")args = parser.parse_args()return argsdef print_flag(flag):if len(flag) != 26:print("You got the wrong flag buddy")returnif flag[10] == 'e':print("Nope")elif flag[4] == chr(0x7B) and flag[25] == chr(0x7D):if flag[0] == 'F':if flag[23] == 'g':if flag[16] == chr(0x30) and flag[18] == '0':print("That's not it")elif flag[16] == flag[18] and flag[18] == chr(0x33):if flag[8] == 'j' or flag[3] == 'A':print("Wrong!")elif flag[15] == flag[19] == 'r':if flag[1:5] != 'FLAG':if flag[8] == chr(0x5F) and flag[5] == 'n' and flag[0xE] == '_':if flag[2] == 'G' and flag[3] == 'A': if flag[3] == 'V' and flag[1] == 'F':if flag[0x30] == 'F' and flag[0x37] == 'w':if flag[25] == '{' and flag[4] == '}':if flag[20] == 'Z' and flag[12] == 'Z':if flag[10] == 'z':print("Nope")elif flag[0x30] == 'f':if flag[20] == 'a' and flag[3] == 'A':if flag[19] == 'z':print("Not even close")else:print("Wrong") elif flag[10] == 'Y' and flag[11] == ']':if flag[20] == 'S' and flag[22] == 'n':if flag[16] == 'g' or flag[1] == 'f':print("Wrong")elif flag[2] == 'A' and flag[3] == 'G':if flag[9] == flag[0xC] == 't' and flag[24] == '!':if flag[0xD] == FUNC_00401064() and flag[1] == 'l'.upper() :eax = int(flag[6])if eax == 1 and flag[22] == str(eax):if flag[20] == 'S' and flag[10] == 'j':print("wrong")elif eax == eax ^ eax and flag[11] == FUNC_00401000():twenty_first_char = 6*int(flag[6]) + 5*int(flag[11]) + 4*int(flag[13]) + 3*int(flag[16]) - 16*int(flag[18])if twenty_first_char == str(int(hex(int('10101',2)),16)):if flag[7] == 'z' and flag[17] == 'F':print("Wrong")elif flag[0xA] == 'h' and flag[21] == str(twenty_first_char):if flag[7] == 'z' and flag[17] == 'A':if flag[20] == 'S' and flag[22] == 'N':print("You're getting close!")elif flag[7] == 'w' and flag[17] == 'v':if flag[20] == 'S' and flag[22] == 'N':print("You were sooooooo close!")elif flag[20] == 's' and flag[22] == 'n':print("Good job! You got the flag! 🚩")elif flag[7] == 'W' and flag[17] == 'V':print("You capitalized it wrong")elif flag[0xA] == 'F' or flag[17] == 'A':if flag[0x0000A].upper() == 'a':print("You have to tell me how you managed to end up here!")elif flag[1] == 'X':print("Wrong")else:if flag[1] == 'A':if flag[4] == chr(0x24) or flag[4] == chr(0x21):print("Wrong")elif flag[0:4] == "FLAG":if flag[4] == '{' or flag[24] == '}':if flag[5:24] is not None:print("Sorry...")else:print("How did you get here?")else:print("Did you take the right path? I don't think so")elif flag[16] == 'g' or flag[10] == 'f':if flag[10] == 'e' and flag[12] == 'g':if flag[13] == 'e':if flag[4] == 'F' and flag[1] == '!':print("Not even close")else:print("Your on the wrong track")elif flag[20] == 'a' and flag[15] == chr(0x01):if flag[20] == 'A'.lower() and flag[3] == 'c':print("Keep going")else:print("Wrong flag")else:print("That's not the right flag")else:print("That's not the right flag")else:print("That's not the right flag")else:print("That's not the right flag")else:print("That's not the right flag")else:print("That's not the right flag")def FUNC_00401000():function_name = 'FUNC_0040'offset = ''for i in range(56, 64, 2):offset = str(i * 3 % 10) + offsetfunction_name += offsetreturn globals()[function_name]()def FUNC_00401064():with open('flag.py', 'r') as f:file_length = len(f.read())return str(int(file_length / 0x458 - 2))def FUNC_00401128():return str((0x1 | 0x2 | 0x8) & int('0b1101', 2) & int('0b0111', 2) & int('0b1110', 2)) def FUNC_00402048():return str(0xF & int('0b1000', 2) & int('0b0001', 2) & int('0b1010', 2))def FUNC_00402240():return str((0x3 | 0xC) & int('0b1000', 2) & int('0b0001', 2) & int('0b1010', 2)) def FUNC_00406048():return str((0x3 | 0xC) & int('0b1101', 2) & int('0b0111', 2) & int('0b1110', 2))def FUNC_00408046():return str((0x1 | 0x2 | 0x8) & int('0b1000', 2) & int('0b0001', 2) & int('0b1010', 2)) def FUNC_00409032():return str((0xF) & int('0b0000', 2) & int('0b0000', 2) | int('0b1111', 2))def FUNC_00409500():return str((0x3 | 0xC) & int('0b1001', 2) | int('0b1111', 2) & int('0b0000', 2))def FUNC_00409999():return str((0x1 | 0x8) & int('0b1101', 2) & int('0b0111', 2) & int('0b1110', 2))if __name__ == "__main__":arguments = parse_args()print_flag(arguments.flag)
里边很多叉路,手工一点点搓
flag[4] == chr(0x7B) and flag[25] == chr(0x7D)
flag[0] == 'F'
flag[23] == 'g'
flag[16] == flag[18] and flag[18] == chr(0x33)
flag[15] == flag[19] == 'r'
flag[8] == chr(0x5F) and flag[5] == 'n' and flag[0xE] == '_'
flag[2] == 'A' and flag[3] == 'G'
flag[9] == flag[0xC] == 't' and flag[24] == '!'
flag[0xD] == FUNC_00401064() and flag[1] == 'l'.upper() 5
int(flag[6]) == 0
flag[11] == FUNC_00401000() 6048: 4
twenty_first_char = 6*int(flag[6]) + 5*int(flag[11]) + 4*int(flag[13]) + 3*int(flag[16]) - 16*int(flag[18])
flag[0xA] == 'h' and flag[21] == str(twenty_first_char) 1
flag[7] == 'w' and flag[17] == 'v'
flag[20] == 's' and flag[22] == 'n'FLAG{n0w_th4t5_r3v3rs1ng!}offset = ''
for i in range(56, 64, 2):offset = str(i * 3 % 10) + offset
#6048
Reverse 2
图片作为密钥文件,怎么出来的不清楚,把exit 给nop掉,gdb跟进去看
int __cdecl main(int argc, const char argv, const char envp)
{size_t rowbytes; // rax__int64 info_struct; // [rsp+18h] [rbp-48h] BYREF__int64 v6; // [rsp+20h] [rbp-40h] BYREFchar v7; // [rsp+2Fh] [rbp-31h]int image_height; // [rsp+30h] [rbp-30h]int image_width; // [rsp+34h] [rbp-2Ch]FILE *stream; // [rsp+38h] [rbp-28h]_QWORD *v11; // [rsp+40h] [rbp-20h]int j; // [rsp+48h] [rbp-18h]int i; // [rsp+4Ch] [rbp-14h]v11 = 0LL;if ( argc <= 1 ){puts("Missing argument");exit(1);}if ( strlen(argv[1]) != 38 ){puts("Invalid length");exit(1);}stream = fopen("image.png", "rb");v6 = png_create_read_struct("1.6.38", 0LL, 0LL, 0LL);info_struct = png_create_info_struct(v6);png_init_io(v6, stream);png_read_info(v6, info_struct);image_width = png_get_image_width(v6, info_struct);image_height = png_get_image_height(v6, info_struct);png_read_update_info(v6, info_struct);v11 = malloc(8LL * image_height);for ( i = 0; i < image_height; ++i ){rowbytes = png_get_rowbytes(v6, info_struct);v11[i] = malloc(rowbytes);}png_read_image(v6, v11);for ( j = 0; j <= 37; ++j ){v7 = *(_BYTE *)(*v11 + 4 * j) ^ *(_BYTE *)(v11[1] + 4 * j);if ( v7 != argv[1][j] ){puts("Wrong flag...");exit(1); //把这里干掉,在比较处下断点}}fclose(stream);png_destroy_read_struct(&v6, &info_struct, 0LL);puts("Your flag is correct!");return 0;
}
Reverse3
这回用当前执行的文件名作key,一样的跟
int __cdecl main(int argc, const char argv, const char envp)
{char s1[208]; // [rsp+10h] [rbp-1C0h] BYREFchar v5[192]; // [rsp+E0h] [rbp-F0h] BYREF__int64 v6[2]; // [rsp+1A0h] [rbp-30h] BYREFchar v7[24]; // [rsp+1B0h] [rbp-20h] BYREFchar *v8; // [rsp+1C8h] [rbp-8h]v6[0] = 0xEE8BA6DA87759523LL;v6[1] = 0x651D0881662A99E5LL;if ( argc <= 1 )exit(1);if ( !validate(argv[1]) ) // len =37exit(2);decode_key((__int64)v7);v8 = strrchr(*argv, '/');decode_ciphertext(v8 + 1, &encoded, s1); // xorAES_init_ctx_iv(v5, v7, v6);AES_CTR_xcrypt_buffer(v5, s1, 37LL);if ( !strcmp(s1, argv[1]) )puts("Your flag is correct!");elseputs("Wrong flag...");return 0;
}
Nimcoded
这是拿啥写的程序,一段段目录串,找到对比位置
__int64 __fastcall validatePassword__nimcoded_4(__int64 *a1)
{char v2[8]; // [rsp+10h] [rbp-40h] BYREFconst char *v3; // [rsp+18h] [rbp-38h]__int64 v4; // [rsp+20h] [rbp-30h]const char *v5; // [rsp+28h] [rbp-28h]__int16 v6; // [rsp+30h] [rbp-20h]__int64 *v7; // [rsp+48h] [rbp-8h]v3 = "validatePassword";v5 = "/kek/src/nimcoded.nim";v4 = 0LL;v6 = 0;nimFrame_4(v2);v4 = 6LL;v5 = "/kek/src/nimcoded.nim";v7 = 0LL;v7 = encode__pureZbase5452_42(a1, 0);if ( (unsigned __int8)eqStrings(v7, TM__Lkt3WP7X9a2MvrAhbOYd04Q_4) != 1 )// 相同{v4 = 9LL;v5 = "/kek/src/nimcoded.nim";echoBinSafe(&TM__Lkt3WP7X9a2MvrAhbOYd04Q_7, 1LL);}else{v4 = 7LL;v5 = "/kek/src/nimcoded.nim";echoBinSafe(&TM__Lkt3WP7X9a2MvrAhbOYd04Q_5, 1LL);}return popFrame_4();
}
TM__Lkt3WP7X9a2MvrAhbOYd04Q_4 是个字符串对象,有个头,去掉后是flag,直接在010也能找着
>>> a = 'RkxBR3tIMUREM05fMU5fUEw0MU5fUzFHSFR9'
>>> b64decode(a)
b'FLAG{H1DD3N_1N_PL41N_S1GHT}'
Android
Safezone
jadx打开,先看AndroidManifest.xml,找到入口com.ettic.sagezone.LoginActivity 打开就看着了
Catchme
同样找到com.ettic.catchme.LoginActivity发现他调用的jni
public class LoginActivity extends e {/* renamed from: n reason: collision with root package name */public static final /* synthetic */ int f1796n = 0;static {System.loadLibrary("catchme-native-lib");}public native String getValidPassword();public void goToMainActivity(View view) {startActivity(new Intent(this, MainActivity.class));}public void onCreate(Bundle bundle) {super.onCreate(bundle);setContentView((int) R.layout.activity_login);((Button) findViewById(R.id.button)).setOnClickListener(new a(this, (EditText) findViewById(R.id.editTextPassword)));}
}
把.apk加上.zip解出内置的库,IDA打开
__int64 __fastcall Java_com_ettic_catchme_LoginActivity_getValidPassword(__int64 a1)
{return (*(__int64 (__fastcall )(__int64, const char *))(*(_QWORD *)a1 + 1336LL))(a1,"FINCTF{NATIV3_C0DE_IS_N0T_SAF3_T00}");
}
Cipherguard
题目提示里有base64的密文:X/Is9ULhqsfnEMuZFxv9wBxuU6WQ1FuF+D2ZwPFilwQ=
这个调用了com.ettic.cipherguard.utils.Crypto,这里有加密方法AES,和key 直接找个网站解
package com.ettic.cipherguard.utils;import android.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;public class Crypto {private static final String KEY = "noonecanguessthiskeysoitissafehh";private Crypto() {}public static String encrypt(String str) {String str2 = "AES";try {SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), str2);Cipher instance = Cipher.getInstance(str2);instance.init(1, secretKeySpec);return Base64.encodeToString(instance.doFinal(str.getBytes()), 0);} catch (Exception unused) {return "Une erreur s'est produite";}}
}
Unchained
也是APK里的jni 加密有点复杂,都是xmm的指令,不过仔细看非常简单,就是异或
__int64 __fastcall Java_com_ettic_unchained_SecretActivity_getFl0g(__int64 a1)
{int v2; // eaxint v3; // r15dconst char *v4; // raxconst char *v5; // r13__int64 v6; // rbx__int64 v7; // rbpunsigned int v8; // eax__int64 v9; // rcxunsigned __int64 i; // rdx__int64 v11; // rdi__m128 v12; // xmm2unsigned __int64 j; // rdx__int64 v14; // rdi__m128 v15; // xmm2unsigned __int64 k; // rdx__int64 v17; // rdi__m128 v18; // xmm2unsigned __int64 v19; // rdx__int64 v20; // rdi__m128 v21; // xmm2__int64 m; // rdx__int64 v23; // rax__int64 v24; // rsi__m128 v25; // xmm2char nptr[2]; // [rsp+Dh] [rbp-8Bh] BYREFchar v28; // [rsp+Fh] [rbp-89h]_WORD v29[40]; // [rsp+10h] [rbp-88h] BYREFunsigned __int64 v30; // [rsp+60h] [rbp-38h]v30 = __readfsqword(0x28u);strcpy(v29, "0c0304091e0c310b0909791919151a187a1e79091e790e150905071a050479041e1937");v2 = __strlen_chk(v29, 71LL);v3 = v2;if ( (v2 & 1) != 0 || (v4 = malloc(v2 / 2 + 1)) == 0LL ){fwrite("Oups\\n", 5uLL, 1uLL, stderr);exit(1);}v5 = v4;v6 = 0LL;if ( v3 > 0 ){v7 = 0LL;do{*nptr = v29[v7];v28 = 0;v5[v7++] = strtol(nptr, 0LL, 16);LODWORD(v6) = v6 + 2;}while ( v6 < v3 );v6 = v7;}v5[v6] = 0;v8 = strlen(v5); // v8=35if ( v8 <= 0 )return (*(*a1 + 1336LL))(a1, v5);v9 = v8;if ( v8 <= 0x1FuLL ){for ( i = 0LL; i != v8; v5[i++] ^= 0x58u )
LABEL_13:;goto LABEL_14;}i = v8 - (v8 & 0x1F); // 35-3v11 = 0LL;do{v12 = _mm_xor_ps(*&v5[v11 + 16], xmmword_C10);// 58*&v5[v11] = _mm_xor_ps(*&v5[v11], xmmword_C10);*&v5[v11 + 16] = v12;v11 += 32LL;}while ( i != v11 );if ( (v8 & 0x1F) != 0 )goto LABEL_13;
LABEL_14:if ( v8 <= 0x1FuLL ){for ( j = 0LL; j != v8; v5[j++] ^= 0x50u )
LABEL_19:;goto LABEL_20;}j = v8 - (v8 & 0x1F);v14 = 0LL;do{v15 = _mm_xor_ps(*&v5[v14 + 16], xmmword_C20);// \\x50*&v5[v14] = _mm_xor_ps(*&v5[v14], xmmword_C20);*&v5[v14 + 16] = v15;v14 += 32LL;}while ( j != v14 );if ( (v8 & 0x1F) != 0 )goto LABEL_19;
LABEL_20:if ( v8 <= 0x1FuLL ){for ( k = 0LL; k != v8; v5[k++] ^= 0x54u )
LABEL_25:;goto LABEL_26;}k = v8 - (v8 & 0x1F);v17 = 0LL;do{v18 = _mm_xor_ps(*&v5[v17 + 16], xmmword_C30);// 54*&v5[v17] = _mm_xor_ps(*&v5[v17], xmmword_C30);*&v5[v17 + 16] = v18;v17 += 32LL;}while ( k != v17 );if ( (v8 & 0x1F) != 0 )goto LABEL_25;
LABEL_26:if ( v8 > 0x1FuLL ){v19 = v8 - (v8 & 0x1F);v20 = 0LL;do{v21 = _mm_xor_ps(*&v5[v20 + 16], xmmword_C40);// 44*&v5[v20] = _mm_xor_ps(*&v5[v20], xmmword_C40);*&v5[v20 + 16] = v21;v20 += 32LL;}while ( v19 != v20 );if ( (v8 & 0x1F) == 0 )goto LABEL_32;}else{v19 = 0LL;}dov5[v19++] ^= 0x44u;while ( v8 != v19 );
LABEL_32:if ( v8 <= 0x1FuLL ){for ( m = 0LL; m != v9; ++m )
LABEL_37:v5[m] ^= 0x52u;return (*(*a1 + 1336LL))(a1, v5);}v23 = v8 & 0x1F;m = v9 - v23;v24 = 0LL;do{v25 = _mm_xor_ps(*&v5[v24 + 16], xmmword_C50);// 25*&v5[v24] = _mm_xor_ps(*&v5[v24], xmmword_C50);*&v5[v24 + 16] = v25;v24 += 32LL;}while ( m != v24 );if ( v23 )goto LABEL_37;return (*(*a1 + 1336LL))(a1, v5);
}
a = list(bytes.fromhex('0c0304091e0c310b0909791919151a187a1e79091e790e150905071a050479041e1937'))
for i in range(35):a[i]^=(0x58^0x50^0x54^0x44^0x52)print(bytes(a))
#b'FINCTF{ACC3SS_PR0T3CT3D_COMPON3NTS}'
Steganography
ROTengo Spirilum
一个png文件,通过观察发现每字符高4位被加密,因为PNG文件有固定的头和chunk头的4字符,根据这些字符猜出加密方式是高4个加3
解密后在哈里的脑门上有flag
from pwn import xor msg = open('on_my_way_to_hogwarts.png','rb').read()d = [(i+3)%0x10 for i in range(0x10)]#高位-3
dec = [d[v>>4]*0x10+(v&0xf) for v in msg]
open('on_my2.png', 'wb').write(bytes(dec))#flag-YerAHackerHarry
#FLAG-YerAHackerHarry
PWN
Dogbolt Level 1 - Harry Pupper
pwn题都没有远端,在国内就都是逆向了,IDA能看到略
Dogbolt Level 2 - Harry Boxer
同上
Dogbolt Level 3 - Harry Retriever
打开看到一堆数,直接转bytes
bytes([102,108,97,103,45,109,111,115,116,95,77,117,103,103,108,101,115,95,97,114,101,110,39,116,95,101,120,97,99,116,108,121,95,97,99,99,117,115,116,111,109,101,100,95,116,111,95,115,101,101,105,110,103,95,97,95,102,108,121,105,110,103,95,99,97,114])
#flag-most_Muggles_aren't_exactly_accustomed_to_seeing_a_flying_car
Network
Auth
一开始没弄明白他要干什么,就能看到ftp登录信息,后来才知道让输入密码
Pouvez-vous retrouver le mot de passe utilisé pour se connecter à ce serveur FTP ?
Format : FLAG {flag-ici}