# MISC

## KcufsJ

We got a file called “kcufsj.dms”.

If we reverse its name, it will be “jsfuck”, which is an esoteric subset of JavaScript, where code is written in only six characters [, ], (, ), !, and +.

Now we can implement code to get the information of the file.

 1 2 3 4 5 6 7  f = open("kcufsj.dms", "r") d = f.readline() s = "" for c in d: s = c + s f.close() print(s) 

And we get a very long string written in JSFuck.

Past that string into the console of a web developer in your web browser, and we can get the flag AIS3{R33v33rs33_JSFUCKKKKKK}.

## Crystal Maze

When you connect to the server, it is a maze-like program.

We are at the entrance of the maze, the prompt will ask for whether to go up, down, left, or right.

Whenever we send our decision, it will send the feedback to us. There are three kinds of feedback:

• Hit the wall, and connection will be cut down
• Get the flag

My idea to deal with this problem is that whenever I go to a point, I will try all four directions, and store those serializations of the footwork in a two-dimensional list about what I need to check next.

Such as
[[up, left, left],
[up, left, right],
[up, left down]]

This is how I implemented

  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  from pwn import * import numpy as np steps = [] steps.append([]) steps[0].append("right") def check(s): p = remote('pre-exam-chals.ais3.org', 10202) for step in steps[0]: p.recvuntil('move:') payload = step p.sendline(payload) p.recvuntil('move:') payload = s p.sendline(payload) feedback = p.recvline(keepends=False) return feedback success = 0 while success is 0: feedback_1 = check("up") feedback_2 = check("down") feedback_3 = check("left") feedback_4 = check("right") #print(feedback_1, feedback_2, feedback_3, feedback_4) feedback = str(feedback_1) + str(feedback_2) + str(feedback_3) + str(feedback_4) if "AIS3" in feedback: print(feedback) break last_step = steps[0][-1] if ("ok" in str(feedback_1)) and (last_step is not "down"): l = steps[0].copy() steps.append(l) steps[-1].append("up") if ("ok" in str(feedback_2)) and (last_step is not "up"): l = steps[0].copy() steps.append(l) steps[-1].append("down") if ("ok" in str(feedback_3)) and (last_step is not "right"): l = steps[0].copy() steps.append(l) steps[-1].append("left") if ("ok" in str(feedback_4)) and (last_step is not "left"): l = steps[0].copy() steps.append(l) steps[-1].append("right") steps.remove(steps[0]) print(steps) 

And we get the flag AIS3{4R3_Y0U_RUNN1NG_45_F45T_45_CRY5T4L?}.

We got a source code main.rb.

  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  #!/usr/bin/ruby require 'json' STDOUT.sync = true puts "Your name:" name = STDIN.gets.chomp puts "Your age:" age = STDIN.gets.chomp if age.match(/[[:alpha:]]/) puts "No!No!No!" exit end string = "{\"name\":\"#{name}\",\"is_admin\":\"no\", \"age\":\"#{age}\"}" res = JSON.parse(string) if res['is_admin'] == "yes" puts "AIS3{xxxxxxxxxxxx}" # flag is here else puts "Hello, " + res['name'] puts "You are not admin :(" end 

It seems like we need to make is_admin to yes to get the flag.

Type bc", "is_admin":"yes","report":[{"subject":"Math for Your name, and type 23"}], “00":"01 for your age.

In this way, the whole string will become {"name"=>"bc", "is_admin"=>"yes", "report"=>[{"subject"=>"Math", "is_admin"=>"no", "age"=>"23"}], "00"=>"01"}, which makes is_admin to yes.

# Reverse

## Trivial

It is a relatively easy one.

We get a file Trivial.dms. After looking at its strings, we can get the flag AIS3{This_is_a_reallllllllllly_boariiing_challenge}.

## TsaiBro

In this question, we get a file TsaiBro.dms, which is the main program on the connection. And we get a file flag.txt, which contains the context of the encoded flag.

The program takes the argument as input, and output its encoded form.

I input characters to the program to make a dictionary. With this dictionary, I can read flag.txt and transfer the code back to its original character.

  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  import os test_list = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_" this_dict = {} for i in test_list: a = os.popen("./TsaiBro %c" % i).read() a = a.split("\n")[1] if a != "": this_dict[str(a)] = i f = open("flag.txt", "r") gar = f.readline() target = f.readline() num = 0 l = [] s = "" for c in target: if c != ".": num += 1 if num == 5: num = 1 l.append(s) s = "" s += c l.append(s) f.close() for e in l: print(this_dict[e], end='') print("\n", end='') 

And we can get the flag AIS3{y0u_4re_a_b1g_f4n_0f_tsaibro_n0w}.

We get files HolyGrenade.pyc and output.txt, which contains encoded message.

If we decompile the .pyc file directly with pycdc, we can only get part of the code because pycdc does not do a modification for python version 3.7.

So we should modify the .pyc file before decompile.

Address Before Modification After Modification Meaning
0x152 and 0x90 a1 83 CALL_METHOD -> CALL_FUNCTION

After modification, we can decompile successfully.

This is the code after rename.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24  from secret import flag from hashlib import md5 # 0 -> 1 # 1 -> 3 # 2 -> 0 # 3 -> 2 def func(arg): arg = bytearray(arg, 'ascii') for i in range(0, len(arg), 4): a = arg[i] b = arg[i + 1] c = arg[i + 2] d = arg[i + 3] arg[i + 2] = d arg[i + 1] = a arg[i + 3] = b arg[i] = c return arg.decode('ascii') flag += b'0' * (len(flag) % 4) for i in range(0, len(flag), 4): print(func(md5(bytes(flag[i:i + 4])).hexdigest())) 

It cut the flag into pieces and do md5 hash, switch the position in each block with func(arg).

This is how I reverse this process. I get the flag by reversing func(arg) and make a dictionary with md5 hash value from a combination of 4 characters. Finally, make the collision.

  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  from hashlib import md5 from itertools import product # 0 -> 1 # 1 -> 3 # 2 -> 0 # 3 -> 2 def func(arg): arg = bytearray(arg, 'ascii') for i in range(0, len(arg), 4): a = arg[i] b = arg[i + 1] c = arg[i + 2] d = arg[i + 3] arg[i + 2] = d arg[i + 1] = a arg[i + 3] = b arg[i] = c return arg.decode('ascii') def de_func(arg): arg = bytearray(arg, 'ascii') for i in range(0, len(arg), 4): a = arg[i] b = arg[i + 1] c = arg[i + 2] d = arg[i + 3] arg[i + 1] = d arg[i + 2] = a arg[i] = b arg[i + 3] = c return arg.decode('ascii') l = [] f = open("output.txt") for line in f: l.append(line[:-1]) f.close() l_defunc = [] for i in l: l_defunc.append(de_func(i)) this_dict = {} char_list = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}0123456789_" tmp = list(product(char_list, repeat=4)) for i in range(len(tmp)): tmp[i] = ''.join(list(tmp[i])) for i in tmp: arg = bytearray(i, 'ascii') this_dict[md5(bytes(arg)).hexdigest()] = i s = '' for i in l_defunc: if i in this_dict: s += this_dict[i] print(s) 

And we can get the flag AIS3{7here_15_the_k1ll3r_ra661t}.

Note: Instead of pycdc, using uncompyle6 can be a better solution because there is no need to revise the binary code.

# Crypto

## TCash

We get a file task.py.

  1 2 3 4 5 6 7 8 9 10 11 12 13  from hashlib import md5,sha256 from secret import FLAG cand = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPWRSTUVWXYZ1234567890@,- _{}' md5s = [] sha256s = [] for f in FLAG : assert f in cand md5s.append( int(md5(f.encode()).hexdigest(),16)%64 ) sha256s.append( int(sha256(f.encode()).hexdigest(),16)%64 ) # md5s = [41, 63, 46, 51, 6, 26, 42, 50, 44, 33, 29, 50, 27, 28, 30, 17, 31, 19, 46, 50, 33, 45, 26, 26, 29, 31, 52, 33, 1, 45, 31, 22, 50, 50, 50, 50, 50, 31, 22, 50, 44, 26, 44, 49, 50, 49, 26, 45, 31, 30, 22, 44, 30, 31, 17, 50, 50, 50, 31, 43, 52, 50, 53, 31, 30, 17, 26, 31, 46, 41, 44, 26, 31, 52, 50, 30, 31, 26, 39, 31, 46, 33, 27, 1, 42, 50, 31, 30, 12, 26, 27, 52, 31, 30, 12, 31, 46, 26, 27, 14, 50, 31, 22, 52, 33, 31, 41, 50, 46, 31, 22, 23, 41, 31, 53, 26, 21, 31, 33, 30, 31, 19, 39, 51, 33, 30, 39, 51, 12, 58, 60, 31, 41, 33, 53, 31, 3, 17, 50, 31, 51, 26, 29, 52, 31, 33, 22, 26, 31, 41, 51, 54, 41, 29, 52, 31, 19, 23, 33, 30, 44, 26, 27, 38, 8, 50, 29, 15] # sha256s = [61, 44, 3, 14, 22, 41, 43, 30, 49, 59, 58, 30, 11, 3, 24, 35, 40, 46, 3, 42, 59, 36, 41, 41, 41, 40, 9, 59, 23, 36, 40, 33, 42, 42, 42, 42, 42, 40, 44, 42, 49, 24, 49, 28, 42, 33, 24, 36, 40, 24, 33, 10, 24, 40, 35, 42, 42, 42, 40, 39, 9, 42, 3, 40, 24, 35, 24, 40, 3, 61, 49, 24, 40, 9, 42, 24, 40, 41, 17, 40, 12, 57, 11, 23, 43, 42, 40, 24, 18, 41, 11, 9, 40, 24, 18, 40, 3, 41, 11, 12, 42, 40, 44, 9, 59, 40, 61, 42, 3, 40, 44, 13, 61, 40, 3, 24, 29, 40, 59, 24, 40, 19, 18, 6, 59, 24, 18, 6, 22, 0, 39, 40, 61, 57, 3, 40, 17, 35, 42, 40, 58, 24, 58, 9, 40, 59, 44, 24, 40, 61, 48, 52, 61, 58, 9, 40, 19, 13, 59, 24, 53, 41, 11, 55, 55, 42, 58, 18] 

It takes each character in the flag, encodes with md5, transfers hex to int, and modulo 64. Besides md5, it operates sha256 as well.

To solve this problem, I implement two lists containing md5 and sha256 of each character. We can get the flag back by comparing the encoded parts with these two lists.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  from hashlib import md5,sha256 cand = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPWRSTUVWXYZ1234567890@,- _{}' cand_md5s = [] cand_sha256s = [] FLAG = 'AIS3{' md5s = [41, 63, 46, 51, 6, 26, 42, 50, 44, 33, 29, 50, 27, 28, 30, 17, 31, 19, 46, 50, 33, 45, 26, 26, 29, 31, 52, 33, 1, 45, 31, 22, 50, 50, 50, 50, 50, 31, 22, 50, 44, 26, 44, 49, 50, 49, 26, 45, 31, 30, 22, 44, 30, 31, 17, 50, 50, 50, 31, 43, 52, 50, 53, 31, 30, 17, 26, 31, 46, 41, 44, 26, 31, 52, 50, 30, 31, 26, 39, 31, 46, 33, 27, 1, 42, 50, 31, 30, 12, 26, 27, 52, 31, 30, 12, 31, 46, 26, 27, 14, 50, 31, 22, 52, 33, 31, 41, 50, 46, 31, 22, 23, 41, 31, 53, 26, 21, 31, 33, 30, 31, 19, 39, 51, 33, 30, 39, 51, 12, 58, 60, 31, 41, 33, 53, 31, 3, 17, 50, 31, 51, 26, 29, 52, 31, 33, 22, 26, 31, 41, 51, 54, 41, 29, 52, 31, 19, 23, 33, 30, 44, 26, 27, 38, 8, 50, 29, 15] sha256s = [61, 44, 3, 14, 22, 41, 43, 30, 49, 59, 58, 30, 11, 3, 24, 35, 40, 46, 3, 42, 59, 36, 41, 41, 41, 40, 9, 59, 23, 36, 40, 33, 42, 42, 42, 42, 42, 40, 44, 42, 49, 24, 49, 28, 42, 33, 24, 36, 40, 24, 33, 10, 24, 40, 35, 42, 42, 42, 40, 39, 9, 42, 3, 40, 24, 35, 24, 40, 3, 61, 49, 24, 40, 9, 42, 24, 40, 41, 17, 40, 12, 57, 11, 23, 43, 42, 40, 24, 18, 41, 11, 9, 40, 24, 18, 40, 3, 41, 11, 12, 42, 40, 44, 9, 59, 40, 61, 42, 3, 40, 44, 13, 61, 40, 3, 24, 29, 40, 59, 24, 40, 19, 18, 6, 59, 24, 18, 6, 22, 0, 39, 40, 61, 57, 3, 40, 17, 35, 42, 40, 58, 24, 58, 9, 40, 59, 44, 24, 40, 61, 48, 52, 61, 58, 9, 40, 19, 13, 59, 24, 53, 41, 11, 55, 55, 42, 58, 18] for c in cand : cand_md5s.append(int(md5(c.encode()).hexdigest(), 16) % 64) cand_sha256s.append(int(sha256(c.encode()).hexdigest(), 16) % 64) for i in range(5, len(md5s)): for j in range(len(cand)): if md5s[i] == cand_md5s[j] and sha256s[i] == cand_sha256s[j]: FLAG += cand[j] break print(FLAG) 

And we can get the flag AIS3{0N_May_16th @Sead00g said Heeeee ReMEMBerEd tH4t heee UseD thE SAME set 0f On1iNe to01s to S01Ve Rsa AeS RCA DE5 at T-cat-cup, AnD 7he kEys aRE AlWAys TCat2019Key}.

## RSA101

In this challenge, the connection provides public key (N, e) and encrypted flag.

Then, it will provide a Phi oracle. In this oracle, user can input a number n, and the program will output ((n % phi) % 64). If we can get phi, we are able to get the flag.

In the observation, if n <= phi, it will output 0. So we can keep trying from the top. For instance, 2^2048 output non-zero, then try 2^2047, and output zero, then keep 2^2047, try 2^2047 + 2^2046 …

After we get phi, we can get d by doing modular multiplicative inverse. With d, we can decrypt the 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  from pwn import * from Crypto.Util.number import getPrime, isPrime, inverse import sys p = remote('pre-exam-chals.ais3.org', 10201) p.recvuntil('(e,N) : (', drop=True) e = p.recvuntil(',', drop=True) N = p.recvuntil(')', drop=True) p.recvuntil('Encrypted Flag : ') enc_flag = p.recvuntil('\n', drop=True) e = int(e) N = int(N) enc_flag = int(enc_flag) upper_bound = len(bin(N)[2:]) print(upper_bound) p.recvuntil('n = ? \n') phi = 0 feedback = -1 while upper_bound > 0: for i in range(2048): guess = upper_bound - 1 #print("guess: " + str(guess)) payload = phi + pow(2, guess) p.send(str(payload)) p.recvuntil(' = ') feedback = p.recvuntil('\n', drop=True) feedback = int(feedback) if feedback == 0: break upper_bound -= 1 if upper_bound == 0: break p.recvuntil('n = ? \n') if upper_bound != 0: phi += pow(2, guess) upper_bound = guess print("upper_bound: " + str(upper_bound)) p.recvuntil('n = ? \n') """ print("phi: " + str(phi)) print("e: " + str(e)) print("N: " + str(N)) print("Enc_flag: " + str(enc_flag)) """ d = inverse(e, phi) flag = pow(enc_flag, d, N) print(bytearray.fromhex(hex(flag)[2:]).decode()) 

And we can get the flag AIS3{RSA_L0L_01100110011101010110001101101011}.

## RSA202

In this challenge, we get lots of information after connection:

• e
• n1 : r * next_prime(r)
• n2 : p * q
• enc : pow(FLAG1, e, n1)
• enc : pow(FLAG2, e, n2)

And two hints:

• p, q, r are prime numbers.
• ((p - 1) % r)^2 + ((r^5 - 1) % p)^2 == 0

For n1:
I use the tool yafu to bruteforce to get r and next_prime(r), which is p and q.

For n2:

1. Since ((p - 1) % r)^2 + ((r^5 - 1) % p)^2 == 0, (p - 1) % r = 0 and (r^5 - 1) % p = 0.
2. Since r^5 - 1 = (r - 1) * (r^4 + r^3 + r^2 + r + 1), either (r - 1) % p = 0 or (r^4 + r^3 + r^2 + r + 1) % p = 0.
3. Since p and r are prime numbers, (r - 1) % p = 0 cannot be true.
4. That is, (r^4 + r^3 + r^2 + r + 1) = kp.
5. We already know r, we can calculate (r^4 + r^3 + r^2 + r + 1) and find out that it is a prime.
6. Regarding (r^4 + r^3 + r^2 + r + 1) = kp, k needs to be 1, and we get p. n2 / p = q.

With p and q, we can get phi = (p - 1) * (q - 1), and we can get d by doing the modular multiplicative inverse. And we get the flag.

However, it is a decimal number. We need to transfer the flag to hex and later transfer to ASCII code.

Finally, we get the flag AIS3{S0me7im3s_I_h4tE_factorDB}.