Created
September 2, 2024 10:50
-
-
Save realazizk/cdd9add44de5780a129420c3c67ce2b4 to your computer and use it in GitHub Desktop.
bhmea quals rev
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| 1. unpack Jscript code | |
| 2. brute force random key | |
| */ | |
| #include <windows.h> | |
| #include <wincrypt.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <iostream> | |
| #include <string> | |
| #include <iomanip> | |
| #define MD5_DIGEST_LENGTH 16 | |
| #define AES_BLOCK_SIZE 16 | |
| void PrintHex(BYTE* data, DWORD dataLen) { | |
| for (DWORD i = 0; i < dataLen; i++) { | |
| printf("%02x", data[i]); | |
| } | |
| printf("\n"); | |
| } | |
| void PrintErrorMessage(DWORD dwError) | |
| { | |
| char* messageBuffer = NULL; | |
| FormatMessageA( | |
| FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| NULL, | |
| dwError, | |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
| (LPSTR)&messageBuffer, | |
| 0, | |
| NULL | |
| ); | |
| if (messageBuffer != NULL) | |
| { | |
| printf("Error: %s\n", messageBuffer); | |
| LocalFree(messageBuffer); | |
| } | |
| else | |
| { | |
| printf("Error code: %d\n", dwError); | |
| } | |
| } | |
| int main() { | |
| HCRYPTPROV hProv = 0; | |
| HCRYPTHASH hHash = 0; | |
| HCRYPTKEY hKey = 0; | |
| BYTE ciphertext[] = { | |
| 0x73, 0xE3, 0x67, 0x95, 0x07, 0xCC, 0x81, 0x97, 0xF6, 0x65, 0xFD, 0x5B, 0x46, 0xF5, 0x53, 0x21, | |
| 0xCF, 0x89, 0xBB, 0x82, 0x8C, 0xD7, 0xBB, 0x42, 0x4B, 0x18, 0x17, 0x34, 0xD4, 0x68, 0x70, 0x97, | |
| 0x09, 0xD4, 0x90, 0x85, 0x86, 0x8C, 0xDA, 0x1B, 0x98, 0x92, 0xB9, 0x47, 0x99, 0x9E, 0x4F, 0x64 | |
| }; | |
| DWORD cipherLen = sizeof(ciphertext); | |
| BYTE* plaintext = NULL; | |
| DWORD plaintextLen = cipherLen; | |
| char pbData[9]; | |
| const char* expectedPrefix = "BHFlagY"; | |
| size_t expectedPrefixLen = strlen(expectedPrefix); | |
| if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, 0)) { | |
| PrintErrorMessage(GetLastError()); | |
| return 1; | |
| } | |
| for (int i = 0; i <= 99999999; i++) { | |
| sprintf_s(pbData, "%08d", i); | |
| if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { | |
| PrintErrorMessage(GetLastError()); | |
| CryptReleaseContext(hProv, 0); | |
| return 1; | |
| } | |
| if (!CryptHashData(hHash, (BYTE*)pbData, 8, 0)) { | |
| PrintErrorMessage(GetLastError()); | |
| CryptDestroyHash(hHash); | |
| continue; | |
| } | |
| if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey)) { | |
| PrintErrorMessage(GetLastError()); | |
| CryptDestroyHash(hHash); | |
| continue; | |
| } | |
| plaintext = (BYTE*)malloc(plaintextLen); | |
| if (!plaintext) { | |
| printf("Memory allocation failed\n"); | |
| CryptDestroyKey(hKey); | |
| CryptDestroyHash(hHash); | |
| CryptReleaseContext(hProv, 0); | |
| return 1; | |
| } | |
| memcpy(plaintext, ciphertext, cipherLen); | |
| DWORD tempLen = plaintextLen; | |
| if (CryptDecrypt(hKey, 0, TRUE, 0, plaintext, &tempLen)) { | |
| if (tempLen >= expectedPrefixLen && memcmp(plaintext, expectedPrefix, expectedPrefixLen) == 0) { | |
| printf("Possible key: %s\n", pbData); | |
| printf("Decrypted data: "); | |
| PrintHex(plaintext, tempLen); | |
| printf("As text: %.*s\n", tempLen, plaintext); | |
| free(plaintext); | |
| break; | |
| } | |
| } | |
| free(plaintext); | |
| CryptDestroyKey(hKey); | |
| CryptDestroyHash(hHash); | |
| } | |
| CryptReleaseContext(hProv, 0); | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 1. unpack using binwalk | |
| 2. decompress zlib files | |
| 3. readRDS the files will print decompiled bytecode in R studio | |
| 4. solve constraints with z3 | |
| """ | |
| """ | |
| function () | |
| { | |
| if (exists("flag", envir = .GlobalEnv)) { | |
| flag_value <- get("flag", envir = .GlobalEnv) | |
| if (is.character(flag_value)) { | |
| xor_key <- "BHMEAISTHEBESTCTFEVERBETTERTHANALLOFTHEOTHERCTF" | |
| key_length <- nchar(xor_key) | |
| flag_length <- nchar(flag_value) | |
| if (flag_length != key_length) { | |
| xor_key <- substr(rep(xor_key, length.out = ceiling(flag_length/key_length)), | |
| 1, flag_length) | |
| } | |
| xor_result <- sapply(1:flag_length, function(i) { | |
| flag_char <- substr(flag_value, i, i) | |
| key_char <- substr(xor_key, i, i) | |
| int_val <- as.integer(charToRaw(flag_char)) | |
| xor_val <- as.integer(charToRaw(key_char)) | |
| xored_val <- bitwXor(int_val, xor_val) | |
| as.raw(xored_val) | |
| }) | |
| return(paste0(xor_result, collapse = "")) | |
| } | |
| } | |
| else { | |
| system("echo 'try better next time'") | |
| } | |
| } | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| x <- 9 | |
| delayedAssign("y", x) | |
| x <- x * (x - 5 + 4 + 6 - 3 - 2 - 3 - 6) | |
| as.integer(substr(flag, 1, 1)) == y | |
| } | |
| """ | |
| import z3 | |
| # Create a solver | |
| solver = z3.Solver() | |
| # Create a string of 94 characters (assuming the flag length is 94 based on the constraints) | |
| flag = [z3.BitVec(f"flag_{i + 1}", 32) for i in range(94)] | |
| flag = [None, *flag] | |
| def substr(x, y): | |
| z = 0 | |
| m = 1 | |
| for i in list(range(x, y + 1))[::-1]: | |
| z += flag[i] * m | |
| m *= 10 | |
| return z | |
| # Add constraints for printable ASCII characters | |
| for char in flag: | |
| if char is None: | |
| continue | |
| # check hexadicmal range | |
| solver.add(char >= 0, char <= 0xF) | |
| pass | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- as.integer(substr(flag, 51, 51)) | |
| val_2 <- as.integer(substr(flag, 22, 22)) | |
| (val_1 - val_2) == 1 | |
| } | |
| """ | |
| solver.add(substr(51, 51) - substr(22, 22) == 1) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 14, 14) | |
| val_2 <- substr(flag, 18, 18) | |
| val_3 <- substr(flag, 24, 24) | |
| val_4 <- substr(flag, 32, 32) | |
| val_5 <- substr(flag, 36, 36) | |
| val_6 <- substr(flag, 62, 62) | |
| (val_1 == val_2) & (val_1 == "a") & (val_1 == val_3) & (val_3 == | |
| val_4) & (val_5 == val_4) & (val_6 == val_5) | |
| } | |
| """ | |
| solver.add(substr(14, 14) == substr(18, 18)) | |
| solver.add(substr(14, 14) == 0xA) | |
| solver.add(substr(14, 14) == substr(24, 24)) | |
| solver.add(substr(24, 24) == substr(32, 32)) | |
| solver.add(substr(36, 36) == substr(32, 32)) | |
| solver.add(substr(62, 62) == substr(36, 36)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 16, 16) | |
| val_2 <- substr(flag, 30, 30) | |
| (val_1 == val_2) & (val_1 == "f") | |
| } | |
| """ | |
| solver.add(substr(16, 16) == substr(30, 30)) | |
| solver.add(substr(16, 16) == 0xF) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 51, 51) | |
| val_2 <- substr(flag, 59, 59) | |
| val_3 <- substr(flag, 63, 63) | |
| val_4 <- substr(flag, 65, 65) | |
| val_5 <- substr(flag, 77, 77) | |
| val_6 <- substr(flag, 91, 91) | |
| (val_1 == val_2) & (val_1 == val_3) & (val_1 == val_4) & | |
| (val_1 == val_5) & (val_1 == val_6) | |
| } | |
| """ | |
| solver.add(substr(51, 51) == substr(59, 59)) | |
| solver.add(substr(51, 51) == substr(63, 63)) | |
| solver.add(substr(51, 51) == substr(65, 65)) | |
| solver.add(substr(51, 51) == substr(77, 77)) | |
| solver.add(substr(51, 51) == substr(91, 91)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 54, 54) | |
| val_2 <- substr(flag, 84, 84) | |
| val_3 <- substr(flag, 12, 12) | |
| (val_1 == val_2) & (val_1 == "e") & (val_1 == val_3) | |
| } | |
| """ | |
| solver.add(substr(54, 54) == substr(84, 84)) | |
| solver.add(substr(54, 54) == 0xE) | |
| solver.add(substr(84, 84) == substr(12, 12)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 72, 72) | |
| val_2 <- substr(flag, 92, 92) | |
| val_3 <- substr(flag, 26, 26) | |
| val_4 <- substr(flag, 34, 34) | |
| val_5 <- substr(flag, 60, 60) | |
| (val_1 == val_2) & (val_1 == val_3) & (val_1 == val_4) & | |
| (val_1 == val_5) | |
| } | |
| """ | |
| solver.add(substr(72, 72) == substr(92, 92)) | |
| solver.add(substr(72, 72) == substr(26, 26)) | |
| solver.add(substr(72, 72) == substr(34, 34)) | |
| solver.add(substr(72, 72) == substr(60, 60)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 17, 17) | |
| val_2 <- substr(flag, 23, 23) | |
| val_3 <- substr(flag, 28, 28) | |
| val_4 <- substr(flag, 35, 35) | |
| val_5 <- substr(flag, 37, 37) | |
| val_6 <- substr(flag, 43, 43) | |
| val_7 <- substr(flag, 44, 44) | |
| val_8 <- substr(flag, 52, 52) | |
| val_9 <- substr(flag, 69, 69) | |
| val_10 <- substr(flag, 74, 74) | |
| (val_1 == val_2) & (val_1 == val_3) & (val_1 == val_4) & | |
| (val_1 == val_5) & (val_1 == val_6) & (val_1 == val_7) & | |
| (val_1 == val_8) & (val_1 == val_9) & (val_1 == val_10) | |
| } | |
| """ | |
| solver.add(substr(17, 17) == substr(23, 23)) | |
| solver.add(substr(17, 17) == substr(28, 28)) | |
| solver.add(substr(17, 17) == substr(35, 35)) | |
| solver.add(substr(17, 17) == substr(37, 37)) | |
| solver.add(substr(17, 17) == substr(43, 43)) | |
| solver.add(substr(17, 17) == substr(44, 44)) | |
| solver.add(substr(17, 17) == substr(52, 52)) | |
| solver.add(substr(17, 17) == substr(69, 69)) | |
| solver.add(substr(17, 17) == substr(74, 74)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, 22, 22) | |
| val_2 <- substr(flag, 48, 48) | |
| val_3 <- substr(flag, 78, 78) | |
| val_4 <- substr(flag, 89, 89) | |
| (val_1 == val_2) & (val_1 == val_3) & (val_1 == val_4) | |
| } | |
| """ | |
| solver.add(substr(22, 22) == substr(48, 48)) | |
| solver.add(substr(22, 22) == substr(78, 78)) | |
| solver.add(substr(22, 22) == substr(89, 89)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- as.integer(substr(flag, 17, 17)) | |
| val_2 <- as.integer(substr(flag, 87, 87)) | |
| (val_1 - val_2) == -2 | |
| } | |
| """ | |
| solver.add(substr(17, 17) - substr(87, 87) == -2) | |
| """ | |
| function check_val_11(index, val) | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- substr(flag, index, index) | |
| val_1 == val | |
| } | |
| check_val_11(76, "8") & | |
| check_val_11(93, "3") & | |
| check_val_11(13, "0") & | |
| check_val_11(26, "5") & | |
| check_val_11(87, "3") & | |
| check_val_11(88, "c") & | |
| check_val_11(81, "0") & | |
| check_val_11(86, "0") & | |
| check_val_11(17, "1") & | |
| check_val_11(18, "a") & | |
| check_val_11(19, "2") & | |
| check_val_11(20, "b") & | |
| check_val_11(31, "3") & | |
| check_val_11(44, "1") & | |
| check_val_11(49, "3") & | |
| check_val_11(55, "3") & | |
| check_val_11(44, "1") & | |
| check_val_11(45, "2") & | |
| check_val_11(39, "2") & | |
| check_val_11(58, "2") & | |
| check_val_11(66, "c") | |
| """ | |
| solver.add(substr(76, 76) == 0x8) | |
| solver.add(substr(93, 93) == 0x3) | |
| solver.add(substr(13, 13) == 0x0) | |
| solver.add(substr(26, 26) == 0x5) | |
| solver.add(substr(87, 87) == 0x3) | |
| solver.add(substr(88, 88) == 0xC) | |
| solver.add(substr(81, 81) == 0x0) | |
| solver.add(substr(86, 86) == 0x0) | |
| solver.add(substr(17, 17) == 0x1) | |
| solver.add(substr(18, 18) == 0xA) | |
| solver.add(substr(19, 19) == 0x2) | |
| solver.add(substr(20, 20) == 0xB) | |
| solver.add(substr(31, 31) == 0x3) | |
| solver.add(substr(44, 44) == 0x1) | |
| solver.add(substr(49, 49) == 0x3) | |
| solver.add(substr(55, 55) == 0x3) | |
| solver.add(substr(44, 44) == 0x1) | |
| solver.add(substr(45, 45) == 0x2) | |
| solver.add(substr(39, 39) == 0x2) | |
| solver.add(substr(58, 58) == 0x2) | |
| solver.add(substr(66, 66) == 0xC) | |
| """ | |
| (substr(get_flag_or_die(), 6, 6) == "b") & | |
| """ | |
| solver.add(substr(6, 6) == 0xB) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| val_1 <- as.integer(substr(flag, 7, 8)) | |
| val_2 <- as.integer(substr(flag, 9, 10)) | |
| val_3 <- as.integer(substr(flag, 89, 91)) | |
| val_4 <- as.integer(substr(flag, 92, 93)) | |
| ((val_1 - val_2) == 9) & ((val_3 + val_4) == 680) | |
| } | |
| """ | |
| solver.add((substr(7, 8) - substr(9, 10)) == 9) | |
| solver.add((substr(89, 91) + substr(92, 93)) == 680) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| as.integer(substr(flag, 7, 11)) == 29202 | |
| } | |
| """ | |
| solver.add(substr(7, 11) == 29202) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| as.integer(substr(flag, 25, 29)) == 25213 | |
| } | |
| """ | |
| solver.add(substr(25, 29) == 25213) | |
| """ | |
| function check_val_6(index_0, index_1, val) | |
| { | |
| flag <- get_flag_or_die() | |
| as.integer(substr(flag, index_0, index_1)) == val | |
| } | |
| check_val_6(67, 71, 22103) & | |
| check_val_6(72, 76, 50138) & | |
| check_val_6(37, 41, 19230) & | |
| check_val_6(43, 47, 11202) & | |
| """ | |
| solver.add(substr(67, 71) == 22103) | |
| solver.add(substr(72, 76) == 50138) | |
| solver.add(substr(37, 41) == 19230) | |
| solver.add(substr(43, 47) == 11202) | |
| """ | |
| check_val_6(77, 79, 763) & | |
| check_val_6(85, 87, 303) & | |
| check_val_6(59, 61, 753) & | |
| check_val_6(39, 41, 230) & | |
| check_val_6(21, 23, 361) & | |
| check_val_6(51, 53, 713) & | |
| check_val_6(33, 35, 351) & | |
| check_val_6(45, 47, 202) & | |
| check_val_6(63, 65, 707) & | |
| """ | |
| solver.add(substr(77, 79) == 763) | |
| solver.add(substr(85, 87) == 303) | |
| solver.add(substr(59, 61) == 753) | |
| solver.add(substr(39, 41) == 230) | |
| solver.add(substr(21, 23) == 361) | |
| solver.add(substr(51, 53) == 713) | |
| solver.add(substr(33, 35) == 351) | |
| solver.add(substr(45, 47) == 202) | |
| solver.add(substr(63, 65) == 707) | |
| """ | |
| function check_val_1(index_0, index_1, index_2) | |
| { | |
| flag <- get_flag_or_die() | |
| first_two <- substr(flag, index_0, index_0) == substr(flag, | |
| index_1, index_1) | |
| second_two <- substr(flag, index_1, index_1) == substr(flag, | |
| index_2, index_2) | |
| final <- all(first_two, second_two) | |
| return(final) | |
| } | |
| function (flag) | |
| { | |
| check_val_1(94, 82, 6) & | |
| check_val_1(1, 86, 10) & | |
| check_val_1(90, 83, 9) & | |
| check_val_1(9, 11, 15) & | |
| check_val_1(29, 61, 57) & | |
| } | |
| """ | |
| def check_val_1(idx0, idx1, idx2): | |
| return z3.And( | |
| substr(idx0, idx0) == substr(idx1, idx1), | |
| substr(idx1, idx1) == substr(idx2, idx2), | |
| ) | |
| solver.add(check_val_1(94, 82, 6)) | |
| solver.add(check_val_1(1, 86, 10)) | |
| solver.add(check_val_1(90, 83, 9)) | |
| solver.add(check_val_1(9, 11, 15)) | |
| solver.add(check_val_1(29, 61, 57)) | |
| """ | |
| function () | |
| { | |
| flag <- get_flag_or_die() | |
| if (nchar(flag) < 5) { | |
| return(FALSE) | |
| } | |
| first_five <- substr(flag, 1, 5) | |
| all_same <- all(strsplit(first_five, "")[[1]] == substr(flag, | |
| 1, 1)) | |
| return(all_same) | |
| } | |
| """ | |
| solver.add(flag[1] == flag[2] == flag[3] == flag[4] == flag[5]) | |
| final_flag = flag[1:] | |
| hehe = [] | |
| # Join the flag characters by two | |
| for i in range(len(final_flag) // 2): | |
| left = z3.Extract(4, 0, final_flag[i * 2]) | |
| right = z3.Extract(4, 0, final_flag[i * 2 + 1]) | |
| hehe.append( | |
| (z3.ZeroExt(4, z3.Extract(4, 0, left)) << 4) | |
| | z3.ZeroExt(4, z3.Extract(4, 0, right)) | |
| ) | |
| ff = "BHMEAISTHEBESTCTFEVERBETTERTHANALLOFTHEOTHERCTF" | |
| chars_to_include = ( | |
| "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'./:<=>?@_{}|" | |
| ) | |
| calcs = [] | |
| for i, c in enumerate(hehe): | |
| rezo = ord(ff[i]) ^ c | |
| solver.add(z3.Or(*[ord(cc) == rezo for cc in chars_to_include])) | |
| calcs.append(rezo) | |
| solver.add(calcs[0] == ord("B")) | |
| solver.add(calcs[1] == ord("H")) | |
| solver.add(calcs[2] == ord("F")) | |
| solver.add(calcs[3] == ord("l")) | |
| solver.add(calcs[4] == ord("a")) | |
| solver.add(calcs[5] == ord("g")) | |
| solver.add(calcs[6] == ord("Y")) | |
| solver.add(calcs[7] == ord("{")) | |
| solver.add(calcs[39] == ord("r")) | |
| solver.add(calcs[20] == ord("_")) | |
| solver.add(calcs[33] == ord("n")) | |
| solver.add( | |
| z3.Or( | |
| calcs[24] == ord("i"), | |
| calcs[24] == ord("1"), | |
| ) | |
| ) | |
| solver.add( | |
| z3.Or( | |
| calcs[27] == ord("i"), | |
| calcs[27] == ord("1"), | |
| ) | |
| ) | |
| # print(solver) | |
| if solver.check() == z3.sat: | |
| model = solver.model() | |
| print(model) | |
| flag_str = "".join([hex(model[flag[i]].as_long())[2:] for i in range(1, 95)]) | |
| import binascii | |
| print("Flag found:", flag_str) | |
| x = binascii.unhexlify(flag_str) | |
| for i, c in enumerate(x): | |
| print(chr(c ^ ord(ff[i])), end="") | |
| else: | |
| print("No solution found") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment