My girlfriend and I captured our best moments of Valentine's Day in a portable graphics network. But unfortunately I am not able to open it as I accidentally ended up encrypting it. Can you help me get my memories back?
Author : Pushkar Deore
Attachments:
source.txt
from PIL import Image
from itertools import cycle
def xor(a, b):
return [i^j for i, j in zip(a, cycle(b))]
f = open("original.png", "rb").read()
key = [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]]
enc = bytearray(xor(f,key))
open('enc.txt', 'wb').write(enc)
enc.txt
Solution:
Ở bài này, chương trình thực hiện XOR một bức ảnh png với key là 8 bytes đầu của nó. Vì là file png nên mình có thể dễ dàng biết được 8 bytes này thông qua File SIgnature trên Google. Tiến hành xor lại với key đó mình sẽ ra được ảnh gốc
Code để recover bức ảnh:
from PIL import Image
from itertools import cycle
def xor(a, b):
return [i^j for i, j in zip(a, cycle(b))]
f = open("enc.txt", "rb").read()
key = [137, 80, 78, 71, 13, 10, 26, 10]
flag = bytearray(xor(f,key))
open('flag.png', 'wb').write(flag)
Ảnh thu được:
Flag: VishwaCTF{h3ad3r5_f0r_w1nn3r5}
Teyvat Tales
Description:
All tavern owners in Mondstadt are really worried because of the frequent thefts in the Dawn Winery cellars. The Adventurers’ Guild has decided to secure the cellar door passwords using a special cipher device. But the cipher device itself requires various specifications….which the guild decided to find out by touring the entire Teyvat.
PS: The Guild started from the sands of Deshret then travelled through the forests of Sumeru and finally to the cherry blossoms of Inazuma
Author: Amruta Patil
Solution:
Đây là giao diện của trang web challenge:
Đến tận bây giờ thì mình cũng chưa biết đống này là cái của khỉ gì. Cách mình giải được bài này là bằng cách nhìn vào code front-end
Ở đây mình thấy một file script.js ở cuối. Đây là đoạn code của nó
const submitBtn1 = document.getElementById("submit-btn-1");
const firstFour = document.querySelector(".first-four");
const submitBtn2 = document.getElementById("submit-btn-2");
const secFour = document.querySelector(".sec-four");
const submitBtn3 = document.getElementById("submit-btn-3");
const thirdFour = document.querySelector(".third-four");
const submitBtn4 = document.getElementById("submit-btn-4");
const fourthFour = document.querySelector(".fourth-four");
submitBtn1.addEventListener("click", ()=> {
const inputText1 = document.getElementById("input1").value.trim();
if (inputText1.toLowerCase() === "enigma m3") {
firstFour.classList.remove("centered-align");
firstFour.classList.add("hidden");
}
else{
alert("Incorrect deciphering! Try again!")
}
});
submitBtn2.addEventListener("click", ()=> {
const inputText2 = document.getElementById("input2").value.trim();
if (inputText2.toLowerCase() === "ukw c") {
secFour.classList.remove("centered-align");
secFour.classList.add("hidden");
}
else{
alert("Incorrect deciphering! Try again!")
}
});
submitBtn3.addEventListener("click", ()=> {
const inputText3 = document.getElementById("input3").value.trim();
if (inputText3.toLowerCase() === "rotor1 i p m rotor2 iv a o rotor3 vi i n") {
thirdFour.classList.remove("centered-align");
thirdFour.classList.add("hidden");
}
else{
alert("Incorrect deciphering! Try again!")
}
});
submitBtn4.addEventListener("click", ()=> {
const inputText4 = document.getElementById("input4").value.trim();
if (inputText4.toLowerCase() === "vi sh wa ct fx") {
fourthFour.classList.remove("centered-align");
fourthFour.classList.add("hidden");
}
else{
alert("Incorrect deciphering! Try again!")
}
});
Từ đây thì mình có được luôn 4 đáp án cho 4 ảnh lần lượt là:
enigma m3
ukw c
rotor1 i p m rotor2 iv a o rotor3 vi i n
vi sh wa ct fx
Sau khi điền từng kết quả vào thì mình ra được ảnh sau (thứ mà mình cũng đã thấy trước ở trong style.css với url(img/GenshinNoticeBoard.png);)
Mình thu được đoạn flag bị mã hóa là CYNIPJ_RE_LSKR-YAZN_MBSJ. Ban đầu, mình không tìm ra được nó là thể loại mã hóa gì. Tuy nhiên, sau khi nhìn vào đống đáp án mà mình phải điền trước đó, mình thử search enigma m3 và mình tìm thấy một loại mã hóa có các tham số như trong đáp án.
Sau khi chỉnh các tham số đó cho y hệt như các đáp án trước đó, mình đã ra được flag.
Flag: Vishwactf{beware_of_tone-deaf_bard}
Poly Fun
Description:
Its a simple symmetric key encryption, I am sure you will be able to solve it (what do you mean the key looks weird)
Author : Revak Pandkar
Attachments:
challenge.py
import numpy as np
import random
polyc = [4,3,7]
poly = np.poly1d(polyc)
def generate_random_number():
while True:
num = random.randint(100, 999)
first_digit = num // 100
last_digit = num % 10
if abs(first_digit - last_digit) > 1:
return num
def generate_random_number_again():
while True:
num = random.randint(1000, 9999)
if num % 1111 != 0:
return num
def transform(num):
number = random.randint(1, 100000)
org = number
number *= 2
number += 15
number *= 3
number += 33
number /= 6
number -= org
if number == 13:
num1 = random.randint(1, 6)
num2 = random.randint(1, 6)
number = num1 * 2
number += 5
number *= 5
number += num2
number -= 25
if int(number / 10) == num1 and number % 10 == num2:
number = generate_random_number()
num1 = int(''.join(sorted(str(number), reverse=True)))
num2 = int(''.join(sorted(str(number))))
diff = abs(num1 - num2)
rev_diff = int(str(diff)[::-1])
number = diff + rev_diff
if number == 1088:
org = num
num *= 2
num /= 3
num += 5
num *= 4
num -= 9
num -= org
return num
else:
number = generate_random_number_again()
i = 0
while number != 6174:
digits = [int(d) for d in str(number)]
digits.sort()
smallest = int(''.join(map(str, digits)))
digits.reverse()
largest = int(''.join(map(str, digits)))
number = largest - smallest
i += 1
if i <= 7:
org = num
num *= 2
num += 7
num += 5
num -= 12
num -= org
num += 4
num *= 2
num -= 8
num -= org
return num
else:
org = num
num **= 4
num /= 9
num += 55
num *= 6
num += 5
num -= 23
num -= org
return num
else:
org = num
num *= 10
num += 12
num **= 3
num -= 6
num += 5
num -= org
return num
else:
org = num
num += 5
num -= 10
num *= 2
num += 12
num -= 20
num -= org
return num
def encrypt(p,key):
return ''.join(chr(p(transform(i))) for i in key)
key = open('key.txt', 'rb').read()
enc = encrypt(poly,key)
print(enc)
In my friend circle, Mr. Olmstead and Mr. Ben always communicate with each other through a secret code language that they created, which we never understand. Here is one of the messages Mr. Ben sent to Mr. Olmstead, which I somehow managed to hack and extract it from Ben's PC. However, it's encrypted, and I don't comprehend their programming language. Besides being proficient programmers, they are also professional chess players. It appears that this is a forced mate in a 4-move chess puzzle, but the information needs to be decrypted to solve it. Help me out here to solve the chess puzzle and get the flag.
Flag format: VishwaCTF{move1ofWhite_move1ofBlack_move2ofWhite_move2ofBlack_move3ofWhite_move3ofBlack_move4ofWhite}.
Note: Please use proper chess notations while writing any move.
Đó chính là vị trí để ta dựng lại một tình huống trong bộ môn cờ vua. Mình sử dụng trang sau để dựng lại bàn cờ: https://nextchessmove.com/
FEN: k5rr/pp4bp/4N1p1/4Q3/4p3/1P5q/P2P1PpP/2R1K2R w - - 0 1
Các bạn có thể tự giải sao cho trắng thắng trong 4 bước, hoặc có thể dùng chức năng Calculate Next Move của trang web trên để tính được 4 bước đó. Kết quả mình ra được chính là flag
Flag: VishwaCTF{Nc7+_Kb8_Na6+_Ka8_Qb8+_Rxb8_Nc7#}
CODEON
Description:
My biochemist friend has doubt that his phone is used by others for calling without knowing him. So, he wants me to find some information related to it, that’s why he sent me some information related to it, also he uses one word short-forms mostly. But I am unable to understand sent data, can you help me?
Author : Sankalp Chakre
Attachment:
CODEON.txt
DATA:
RSC BGT FFH HFT TPD WMA OCZ CCD DCZ ZVA
He gave me some instructions related to it:
1)He told me he saw some names in call logs those are:
Felix Delastelle, Dmitri Mendeleev
2)He also gave me 2 matrices A and B and told to perform same operation on matrix A and B as of performed on matrix P and Q. Find something related to biochemistry to crack my phone password.
Matrix A = 45 35 93 95 24 65
25 15 55 64 36 45
15 65 62 16 65 38
19 64 35 69 65 63
47 67 48 60 39 27
66 48 77 22 10 69
Matrix B = 33 25 30 11 68 65
83 36 19 33 55 51
20 16 48 63 41 71
30 42 12 25 31 37
51 03 44 23 43 85
20 39 28 41 01 70
Matrix P= 13 81 60
40 99 88
39 87 92
Matrix Q= 50 52 36
90 75 28
80 9 18
Result Matrix of P and Q = 60 82 36
60 109 104
52 75 4
Solution:
Ở đây với hint đầu tiên, mình có 2 cái tên là Felix Delastelle và Dmitri Mendeleev.
Với Felix, mình tìm thấy được ông là một nhà mật mã học, nổi tiếng nhất với Bifid cipher. Nó cũng có vẻ giống với data mình nhận được luôn. Tuy nhiên, để giải được mình phải tìm được ra key nữa.
Với Dmitri, đây là người tìm ra bảng tuần hoàn hóa học, có thể sẽ liên quan tới Periodic table cipher.
Đến với hint thứ 2, mình có 2 ma trận A, B. Mình được yêu cầu phải thực hiện một phép toán nào đó giữa chúng giống với phép toán của 2 ma trận P, Q. Tuy nhiên, mình chưa biết phép toán đó là gì mà chỉ biết output của chúng.
Ta có:
<latex>
Sau một hồi guessing thì mình nhận ra các số này đều có thể chuyển về dạng các nguyên tố trong bảng tuần hoàn hóa học. Hiện tại bảng tuần hoàn có 118 nguyên tố, nên mình đã thử lấy ma trận (P*Q)% 119 nhưng không ra. Thử với (P*Q)%118 và mình đã ra được ma trận kết quả
43 23 21 24 32 44 31 31 33 33 31 44 44 41 22 52 12 11 15 21 55 21 21 22 22 21 55 55 51 11
43 23 21 24 32 44 31 31 33 33 31 44 44 41 22
52 12 11 15 21 55 21 21 22 22 21 55 55 51 11
4 3 2 3 2 1 2 4 3 2 4 4 3 1 3 1 3 3 3 3 3 1 4 4 4 4 4 1 2 2
5 2 1 2 1 1 1 5 2 1 5 5 2 1 2 1 2 2 2 2 2 1 5 5 5 5 5 1 1 1
U G C G C A C U G C U U G A G A G G G G G A U U U U U A C C
Đoạn mã mình thu được là UGCGCACUGCUUGAGAGGGGGAUUUUUACC, chỉ chứa 4 kí tự U, A, G, C, giống các bazơ nitơ của gen trong bộ môn Sinh Học. Mình tìm thì có một cipher liên quan tới nó là Codon cipher (Giờ thì mình đã hiểu tên challenge :v)
Và sau khi decode, mình đã ra được flag.
Flag: Vishwactf{CALLERGIFT}
Intellectual Heir
Description:
You received a package, and you got to know that you are the descendant of RIADSH. There are four files and a safe in the package.
You should analyze the files, unlock the safe, and prove your worth. The safe has alphanumeric and character combinations.
# my secret to hide the combination of my safe in fornt of all without anyone getting a clue what it is ;)
#some boring python function for conversion nothing new
def str_to_ass(input_string):
ass_values = []
for char in input_string:
ass_values.append(str(ord(char)))
ass_str = ''.join(ass_values)
return ass_str
input_string = input("Enter the Combination: ")
result = str_to_ass(input_string)
msg = int(result)
#not that easy, you figure out yourself what the freck is a & z
a =
z =
f = (? * ?) #cant remember what goes in the question mark
e = #what is usually used
#ohh yaa!! now you cant figure out $h!t
encrypted = pow(msg, e, f)
print(str(encrypted))
#bamm!! protection for primes
number =
bin = bin(number)[2:]
#bamm!! bamm!! double protection for primes
bin_arr = np.array(list(bin), dtype=int)
result = np.sin(bin_arr)
result = np.cos(bin_arr)
np.savetxt("file1", result)
np.savetxt("file2", result)
Solution:
Bài này thì không khó, chủ yếu mình phải guessing. Đầu tiên mình phân tích hàm str_to_ass.
def str_to_ass(input_string):
ass_values = []
for char in input_string:
ass_values.append(str(ord(char)))
ass_str = ''.join(ass_values)
return ass_str
Hàm này sẽ lấy từng kí tự trong input_string , biến chúng về dạng ascii decimal sau đó join với nhau để tạo thành một chuỗi số.
Để dịch ngược hàm này thì ĐÁNG LẼ chúng ta phải handle trường hợp mã ascii là 2 hay 3 chữ số (cũng không khó). Tuy nhiên, do đề bài nói rằng cái két này không có kí tự lowercase (ascii sẽ có phần 3 chữ số), nên ta có thể bỏ trường hợp 3 chữ số đi và viết được một hàm kiểu như sau:
def ass_to_str(ass_str):
output_string = ""
i = 0
while i < len(ass_str):
if i + 2 <= len(ass_str):
part = ass_str[i:i+2]
output_string += chr(int(part))
i += 2
return output_string
Tiếp theo là đoạn này:
input_string = input("Enter the Combination: ")
result = str_to_ass(input_string)
msg = int(result)
#not that easy, you figure out yourself what the freck is a & z
a =
z =
f = (? * ?) #cant remember what goes in the question mark
e = #what is usually used
#ohh yaa!! now you cant figure out $h!t
encrypted = pow(msg, e, f)
print(str(encrypted))
Nếu các bạn đã chơi Crypto nhiều thì có thể dễ dàng nhận ra đây là mã hóa RSA với a, z là p, q; f là n. Tham số e được comment là #what is usually used, có thể đoán là 65537. Kết quả được in ra có vẻ chính là số trong file.txt
Tiếp đến là đoạn này:
#bamm!! protection for primes
number =
bin = bin(number)[2:]
#bamm!! bamm!! double protection for primes
bin_arr = np.array(list(bin), dtype=int)
result = np.sin(bin_arr)
result = np.cos(bin_arr)
np.savetxt("file1", result)
np.savetxt("file2", result)
Đoạn này sẽ thực hiện chuyển một số đầu vào thành dạng nhị phân, sau đó với mỗi bit nhị phân, ta lấy sin và cos của nó? Tuy nhiên khi mình nhìn vào 2 file file1.txt và file2.txt thì có vẻ một file là lấy sin một file là lấy cos. Hàm sin, cos chưa chắc có thể reverse, tuy nhiên do nhị phân chỉ có 2 bit 0 và 1, mình hoàn toàn có thể khôi phục lại 2 số này. Và vì là 2 số, mình đoán đây chính là p,q bị mã hóa.
with open('file1.txt', 'r') as file:
data1 = file.readlines()
data1 = [float(line.strip()) for line in data1]
bits1 = ['0' if value == 1.0 else '1' for value in data1]
bit_string1 = ''.join(bits1)
prime1 = int(bit_string1,2)
assert isPrime(prime1) == True
with open('file2.txt', 'r') as file:
data2 = file.readlines()
data2 = [float(line.strip()) for line in data2]
bits2 = ['0' if value == 0.0 else '1' for value in data2]
bit_string2 = ''.join(bits2)
prime2 = int(bit_string2,2)
assert isPrime(prime2) == True
Hai assert của mình đều không trả về lỗi, có nghĩa là ta đã có được 2 số nguyên tố p, q
Giờ chỉ cần tiến hành giải mã RSA, mình sẽ ra được flag
Code final:
from Crypto.Util.number import *
def ass_to_str(ass_str):
output_string = ""
i = 0
while i < len(ass_str):
if i + 2 <= len(ass_str):
part = ass_str[i:i+2]
output_string += chr(int(part))
i += 2
return output_string
with open('file1.txt', 'r') as file:
data1 = file.readlines()
data1 = [float(line.strip()) for line in data1]
bits1 = ['0' if value == 1.0 else '1' for value in data1]
bit_string1 = ''.join(bits1)
prime1 = int(bit_string1,2)
assert isPrime(prime1) == True
with open('file2.txt', 'r') as file:
data2 = file.readlines()
data2 = [float(line.strip()) for line in data2]
bits2 = ['0' if value == 0.0 else '1' for value in data2]
bit_string2 = ''.join(bits2)
prime2 = int(bit_string2,2)
assert isPrime(prime2) == True
p = prime1
q = prime2
n = p*q
e = 65537
d = inverse(e, (p-1)*(q-1))
c = 4400037514278889258479265625258024039636437755883377709505596356049534358755375772484057042989024750972247184288820831886430459963472328358741858934783775986591400972020736548834642094922678189447202173710409868474198821576627330424767999152339702779346380
m = pow(c, d, n)
print("VishwaCTF{" + ass_to_str(str(m)) + "}")
Flag: VishwaCTF{Y0U_@R3_T#3_W0RT#Y_OF_3}
BitBane - Cryptic Chaos
Description:
Once again, Mr. David made a blunder by encrypting some confidential data and deleting the original file. Can you help him retrieve the data from the encrypted file?
Author : Saksham Saipatwar
Attachments:
Encrypt.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int createTopping(int curr, int idx, int ¬_remainder)
{
int temp = 0;
int num = 1;
num = num << 1;
while (curr)
{
int remainder = curr % idx;
if (remainder)
{
temp = temp * 10 + remainder;
curr = curr - remainder;
}
else
{
num = num | 1;
curr = curr / idx;
}
num = num << 1;
}
temp = temp << 1;
temp = temp | 1;
not_remainder = temp;
return num | 1;
}
int createBase(int not_remainder)
{
int num = 0;
for (int i = 0; i < 30; ++i)
{
if (not_remainder)
{
num = num | (not_remainder & 1);
not_remainder = not_remainder >> 1;
}
num = num << 1;
}
return num;
}
int create(int curr, int idx)
{
int not_remainder = 0;
int topping = createTopping(curr, idx, not_remainder);
int base = createBase(not_remainder);
int num = base | topping;
return num;
}
bool checkValidity(int num)
{
for (int i = 2; i * i < num; ++i)
{
if (num % i == 0)
return false;
}
return true;
}
void extraSecurity(vector<int> &encryption)
{
int n = encryption.size();
for (int i = 0; i < n; ++i)
{
int idx = i + 2;
if (checkValidity(idx))
{
encryption[i] = ~encryption[i];
}
}
}
void encode(vector<int> &encryption, const string &data, string &key)
{
int len = data.length();
for (int i = 0; i < len; ++i)
{
int curr = data[i];
int idx = (i % 8) + 2;
int num = create(curr, idx);
encryption.push_back(num);
}
}
void applyKey(vector<int> &encryption, string &key)
{
int n = key.size();
for (int i = 0; i < n; ++i)
{
int curr = key[i];
int cnt = 0;
int cpy = curr;
while (cpy)
{
if (cpy & 1)
++cnt;
cpy = cpy >> 1;
}
curr = curr << (i + 10);
while (cnt--)
{
curr = curr << 1;
curr = curr ^ 1;
}
int k = encryption.size();
for (int j = 0; j < k; ++j)
{
encryption[j] = encryption[j] ^ curr;
}
}
}
void writeToFile(const vector<int> &encryption)
{
ofstream outfile("Encrypted.txt");
string data;
for (auto ele : encryption)
{
data += to_string(ele);
data += " ";
}
outfile << data;
outfile.close();
}
int main()
{
fstream file;
file.open("Flag.txt");
string data;
file >> data;
file.close();
vector<int> encryption;
string key = "VishwaCTF";
encode(encryption, data, key);
applyKey(encryption, key);
extraSecurity(encryption);
writeToFile(encryption);
return 0;
}
Ở bài này, flag được mã hóa qua 3 bước là encode, applyKey và extraSecurity. Mình sẽ giải mã ngược lại từng bước để ra được flag
Với bước extraSecurity:
bool checkValidity(int num)
{
for (int i = 2; i * i < num; ++i)
{
if (num % i == 0)
return false;
}
return true;
}
void extraSecurity(vector<int> &encryption)
{
int n = encryption.size();
for (int i = 0; i < n; ++i)
{
int idx = i + 2;
if (checkValidity(idx))
{
encryption[i] = ~encryption[i];
}
}
}
Trông có vẻ dài dòng, nhưng code này chỉ check một số các phần tử sao cho nếu nó không phải số nguyên tố thì thực hiện phép NOT (đảo bit). Hàm này có thể được reverse bằng cách chạy chính nó lần nữa
Với bước applyKey:
void applyKey(vector<int> &encryption, string &key)
{
int n = key.size();
for (int i = 0; i < n; ++i)
{
int curr = key[i];
int cnt = 0;
int cpy = curr;
while (cpy)
{
if (cpy & 1)
++cnt;
cpy = cpy >> 1;
}
curr = curr << (i + 10);
while (cnt--)
{
curr = curr << 1;
curr = curr ^ 1;
}
int k = encryption.size();
for (int j = 0; j < k; ++j)
{
encryption[j] = encryption[j] ^ curr;
}
}
}
Hàm này sẽ làm một loạt các thao tác với key, sau đó lấy key đã biến đổi để XOR với input. Do ta đã biết key, hàm này cũng có thể dễ dàng được reverse chỉ bằng cách chạy lại lần nữa.
Cuối cùng là hàm encode:
int createTopping(int curr, int idx, int ¬_remainder)
{
int temp = 0;
int num = 1;
num = num << 1;
while (curr)
{
int remainder = curr % idx;
if (remainder)
{
temp = temp * 10 + remainder;
curr = curr - remainder;
}
else
{
num = num | 1;
curr = curr / idx;
}
num = num << 1;
}
temp = temp << 1;
temp = temp | 1;
not_remainder = temp;
return num | 1;
}
int createBase(int not_remainder)
{
int num = 0;
for (int i = 0; i < 30; ++i)
{
if (not_remainder)
{
num = num | (not_remainder & 1);
not_remainder = not_remainder >> 1;
}
num = num << 1;
}
return num;
}
int create(int curr, int idx)
{
int not_remainder = 0;
int topping = createTopping(curr, idx, not_remainder);
int base = createBase(not_remainder);
int num = base | topping;
return num;
}
void encode(vector<int> &encryption, const string &data, string &key)
{
int len = data.length();
for (int i = 0; i < len; ++i)
{
int curr = data[i];
int idx = (i % 8) + 2;
int num = create(curr, idx);
encryption.push_back(num);
}
}
Hàm này sẽ truyền 2 giá trị cur và idx vào hàm create. Hàm create cũng sẽ lại gọi tới 2 hàm createTopping và createBase để thực hiện một loại các thao tác với 2 tham số này. Nhìn qua một hồi thì có thể thấy các thao tác này khá là khó để reverse, vì các phép như OR không có trường hợp cố định.
Tuy nhiên, để ý thì idx được tính bằng (i%8) + 2 , là thứ mà ta hoàn toàn có thể tính được hết. cur chính là từng kí tự của flag. Do đã reverse hết 2 hàm trước đó nên mình có kết quả của hàm encode này. Từ đây, mình nghĩ có thể bruteforce giá trị cur, sao cho nếu output của hàm encode ra đúng thì đấy sẽ chính là kí tự của flag. Kể cả khi bạn bruteforce cả 256 kí tự ascii cho mỗi kí tự, việc này cũng sẽ diễn ra rất rất nhanh
Dưới đây là code final:
from Crypto.Util.number import *
import random
enc = [-1934298443, -1728250251, -2103640211, -1153630219, 1775435890, -1670578291, 2009268234, -2009268235, 1950549658, -1992754035, 1673724026, -1398997107, 1405288466, 1824718858, 2131951730, -1765998643, 1934298490, -1330315635, 2063794322, 1889730674, 1124270194, -2059599891, 1086521394, -1858273331, 1909484170, 1229390194, 1757609994, -1275265139, 1201864818, -1892876403, 1673723922, 2009268234, 1950549402, 1229390194, 1947140466, -1942159371, 1849884786, 1703084146, 1824718858, -1665335347, 1909484170, -1229390195, 1757609994, 1170407434, 1124270194, -1918042227, 2038628466, -1982005363, 1950549834, 1124270322, 1782775922, -1738735731, 1768095858, 1842544754, 2127757426]
key = "VishwaCTF"
def check_validity(num):
for i in range(2, int(num**0.5) + 1):
if num % i == 0:
return False
return True
def extra_security(encryption):
n = len(encryption)
for i in range(n):
idx = i + 2
if check_validity(idx):
encryption[i] = ~encryption[i]
extra_security(enc)
print(enc)
def apply_key(encryption, key):
n = len(key)
for i in range(n):
curr = ord(key[i])
cnt = 0
cpy = curr
while cpy:
if cpy & 1:
cnt += 1
cpy = cpy >> 1
curr = curr << (i + 10)
while cnt:
curr = curr << 1
curr = curr ^ 1
cnt -= 1
k = len(encryption)
for j in range(k):
encryption[j] = encryption[j] ^ curr
apply_key(enc, key)
print(enc)
def create_topping(curr, idx):
temp = 0
num = 1
num = num << 1
not_remainder = 0
while curr:
remainder = curr % idx
if remainder:
temp = temp * 10 + remainder
curr = curr - remainder
else:
num = num | 1
curr = curr // idx
num = num << 1
temp = temp << 1
temp = temp | 1
not_remainder = temp
return num | 1, not_remainder
def create_base(not_remainder):
num = 0
for i in range(30):
if not_remainder:
num = num | (not_remainder & 1)
not_remainder = not_remainder >> 1
num = num << 1
return num
def create(curr, idx):
topping, not_remainder = create_topping(curr, idx)
base = create_base(not_remainder)
num = base | topping
return num
flag = []
for i in range(len(enc)):
for curr in range(48, 126):
idx = (i % 8) + 2
num = create(curr, idx)
if(num == enc[i]):
flag.append(chr(curr))
print(''.join(flag))
# VihwaCF{BIT5_3NCRYPT3_D3CRYPTED_M1ND5_D33PLYTE5T3D}
Mặc dù mình vẫn đoán được ra flag tuy nhiên nhìn hơi ngứa mắt, có vẻ do mình implement từ C++ sang python bị sai ở đâu đó. Dưới đây là code final sử dụng C++:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
bool checkValidity(int num)
{
for (int i = 2; i * i < num; ++i)
{
if (num % i == 0)
return false;
}
return true;
}
void extraSecurity(std::vector<int>& encryption)
{
int n = encryption.size();
for (int i = 0; i < n; ++i)
{
int idx = i + 2;
if (checkValidity(idx))
{
encryption[i] = ~encryption[i];
}
}
}
void applyKey(std::vector<int>& nums, std::string& key)
{
int n = key.size();
for (int i = 0; i < n; ++i)
{
int curr = key[i];
int cnt = 0;
int cpy = curr;
while (cpy)
{
if (cpy & 1)
++cnt;
cpy = cpy >> 1;
}
curr = curr << (i + 10);
while (cnt--)
{
curr = curr << 1;
curr = curr ^ 1;
}
int k = nums.size();
for (int j = 0; j < k; ++j)
{
nums[j] = nums[j] ^ curr;
}
}
}
int createTopping(int curr, int idx, int ¬_remainder)
{
int temp = 0;
int num = 1;
num = num << 1;
while (curr)
{
int remainder = curr % idx;
if (remainder)
{
temp = temp * 10 + remainder;
curr = curr - remainder;
}
else
{
num = num | 1;
curr = curr / idx;
}
num = num << 1;
}
temp = temp << 1;
temp = temp | 1;
not_remainder = temp;
return num | 1;
}
int createBase(int not_remainder)
{
int num = 0;
for (int i = 0; i < 30; ++i)
{
if (not_remainder)
{
num = num | (not_remainder & 1);
not_remainder = not_remainder >> 1;
}
num = num << 1;
}
return num;
}
int create(int curr, int idx)
{
int not_remainder = 0;
int topping = createTopping(curr, idx, not_remainder);
int base = createBase(not_remainder);
int num = base | topping;
return num;
}
std::string decode(std::vector<int>& nums)
{
std::string message;
for (int i = 0; i < nums.size(); i++) {
int idx = (i % 8) + 2;
// Brute force character
int c = 0;
for (c = 0; c < 128; c++) {
int num = create(c, idx);
if (num == nums[i])
break;
}
message += c;
}
return message;
}
void print_nums(std::vector<int>& nums)
{
for (int i = 0; i < nums.size() - 1; i++)
std::cout << nums[i] << ' ';
std::cout << nums[nums.size() - 1] << std::endl;
}
int main()
{
std::string key = "VishwaCTF";
// Read encrypted nums
std::fstream file("Encrypted.txt");
std::vector<int> nums;
while (true) {
int num;
file >> num;
if (file.fail())
break;
nums.push_back(num);
}
file.close();
// Undo extraSecurity
extraSecurity(nums);
// Undo applyKey
applyKey(nums, key);
// Undo encode
std::string message = decode(nums);
std::cout << message << std::endl;
return 0;
}
One of my friends Dhruv is a cryptography genius, but he likes to annoy me by playing pranks with my passwords. He recently changed my accounts password and has given the following files as hints, he also gave this buggy code which had some import statements removed, help me retrieve my lost password!!!
Author : Kanishk Kumar
Attachments:
Code.txt
There are some things missing here but I can assure you there are no changes in the encryption
Code:
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Scanner;
public class BuggedBlowfish {
public static void main(String[] args) throws Exception {
Scanner myObj = new Scanner(System.in);
System.out.println("Enter the text to be encrypted: ");
String plaintext = myObj.nextLine();
System.out.println("Enter the key: ")
String keyString = myObj.nextLine();
byte[] keyData = keyString.getBytes();
SecretKey secretKey = new SecretKeySpec(keyData, "Blowfish");
String encryptedText = encrypt(plaintext, secretKey);
System.out.println("Encrypted Text: " + encryptedText)
}
private static String encrypt(String plaintext, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
byte[] ivBytes = new byte[cipher.getBlockSize()];
SecureRandom random = new SecureRandom();
random.nextBytes(ivBytes);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
encryptedBytes = cipher.doFinal(encryptedBytes);
return Base64.getEncoder().encodeToString(encryptedBytes);
}
}