Looks like there are a bunch of whitespace and we see some readable code in the end of the HTML
We can see that there is eval(f) in the end, so my assumption is it will exec the javascript code. To get the executed code we can try to change eval to console.log then take a look on console browser.
Yet another crackme. To begin, download the attachment and install it on your android device.
Solution
Given APK file, decopmile it using JADX-GUI.
Looking at the directory structure we found "xamarin", so i assume that it use xamarin as the tech stack. In directory resources from JADX-GUI export, i found that there is assemblies directory that we can utilize to get the Xamarin DLL. Tool that i used to do the unpack is https://github.com/jakev/pyxamstore.
Through the out directory we found that there is CrackMe.dll, open it using dnspy.
In MainPage class there is function onCounterClicked that will call checkFlag function. If the return True it will shows correct flag, so lets take a look on checkFlag function.
privateboolcheckFlag(string f) {int[] array =newint[] {9,10,11,12,13,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,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126 };int[] array2 =newint[] {58,38,66,88,78,39,80,125,64,106,48,49,98,32,42,59,126,93,33,56,112,120,60,117,111,45,87,35,10,68,61,77,11,55,121,74,107,104,65,63,46,110,34,41,102,97,81,12,47,51,103,89,115,75,54,92,90,76,113,122,114,52,72,70,50,94,91,73,84,95,36,82,124,53,108,101,9,13,44,96,67,85,116,123,100,37,43,119,71,105,118,69,99,79,86,109,62,83,40,57 }; ulong[] array3 = new ulong[] { 16684662107559623091UL, 13659980421084405632UL, 11938144112493055466UL, 17764897102866017993UL, 11375978084890832581UL, 14699674141193569951UL };
ulong num =14627333968358193854UL;int num2 =8;Dictionary<int,int> dictionary =newDictionary<int,int>();for (int i =0; i <array.Length; i++) {dictionary[array[i]] =array2[i]; }StringBuilder stringBuilder =newStringBuilder();foreach (char c in f) {stringBuilder.Append((char)dictionary[(int)c]); }int num3 = num2 -f.Length% num2;string text =stringBuilder.ToString() +newstring('\u0001', num3);List<ulong> list =newList<ulong>();for (int k =0; k <text.Length-1; k += num2) {ulong num4 =BitConverter.ToUInt64(Encoding.ASCII.GetBytes(text.Substring(k, num2)),0);list.Add(num4); }List<ulong> list2 =newList<ulong>();foreach (ulong num5 in list) {ulong num6 = num ^ num5;list2.Add(num6); }for (int l =0; l <array3.Length; l++) {if (array3[l] !=list2[l]) {returnfalse; } }returntrue; }
Above code do the following steps
Create dictionary using static values
Add padding to the input
Map the input (char) and append it to a string builder.
Convert the input string to integer 8 bytes
Xor each 8 bytes and compare it
All the process above can be reversed, so the solution is by reversing the algorithm. Below is the script we use to solve the challenge
from Crypto.Util.number import*array = [9,10,11,12,13,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,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126]array2 = [58,38,66,88,78,39,80,125,64,106,48,49,98,32,42,59,126,93,33,56,112,120,60,117,111,45,87,35,10,68,61,77,11,55,121,74,107,104,65,63,46,110,34,41,102,97,81,12,47,51,103,89,115,75,54,92,90,76,113,122,114,52,72,70,50,94,91,73,84,95,36,82,124,53,108,101,9,13,44,96,67,85,116,123,100,37,43,119,71,105,118,69,99,79,86,109,62,83,40,57]array3 = [16684662107559623091, 13659980421084405632, 11938144112493055466, 17764897102866017993, 11375978084890832581, 14699674141193569951 ]
num =14627333968358193854dictionary ={}for i inrange(len(array)): dictionary[array2[i]]= array[i]dictionary[1]=0tmp = []for i in array3: tmp.append(long_to_bytes(i ^ num)[::-1])flag =b""for i in tmp:for j in i: flag +=bytes([(dictionary[j])])print(flag)
Flag: hkcert24{f0r3v3r_r3m3mb3r_x4m4r1n_2024-5-1}
Baby Cracker (100 pts)
Description
For those who never tried even the simplest reverse, this is for you! Check the guide to experiment how simple reverse works!
For experience player, this is just a simple crackme, not worth your attention, maybe go to solve some 5-stars :)
Solution
Given ELF file, open it using IDA.
We can see that there is two validation. First validation is by using arithmetic operator (addition and multiplication) and the second validation is using logic operator (xor). The details of each validation are as follows
First validation
4 bytes validation, can be solved using z3 or bruteforce
Second validation
28 bytes validation (flag value after hkcert24{, we know it from the strstr function and haystack[i+9])
Can be solved by reversing the flow (just do the xor)
from z3 import*import stringdefall_smt(s,initial_terms):defblock_term(s,m,t): s.add(t != m.eval(t, model_completion=True))deffix_term(s,m,t): s.add(t == m.eval(t, model_completion=True))defall_smt_rec(terms):if sat == s.check(): m = s.model()yield mfor i inrange(len(terms)): s.push()block_term(s, m, terms[i])for j inrange(i):fix_term(s, m, terms[j])yield fromall_smt_rec(terms[i:]) s.pop()yield fromall_smt_rec(list(initial_terms))a = bytes.fromhex("CE21DB64D150E01B0D3EFB0A522F949DAFB1586B8AEEC1F0FC190AE3E91ED04A62F247A8200BD36C1C1C565B9BB34D3DCE8380C0E67EE809BD14C447A1F62FD1315C1E10D12AE05345FE8558A6AD03CC104BD394FE62854E4A2735E2940F499186D780354C67C3AA3C67E83FE46723DE8E2D462536E1F3907D0FB9148CE7B6A61A9080798535FD518C10E93F32CC4BB542DEF55713C8099B4D1984915F9D773031C7288D1DF471E4D1A30C0759AA0DAD163540B9286AB54C245A8DA6A6C456DDC09BBFCCDE0C5BC175DD77BBF62B431D1303AD73A3AC4DEAA52FC23E4A1AF56572E54A10108CFB100A4D7971F6C7805464B002AAD87C3953ECADB44E2FEBE04700")
b = bytes.fromhex("BD10B650BD35BF787F0A98611F1CCBA9F0D96C05EEACB8989D773CBC812EA0793D8B77DD7F6FE3022B433868A8D7120AA1DCF5F38321DC67DA669B77D3A955E26E3A2E628E5E886236A1E72D91F23293677BBDF0CD10DA7F2C78568AA0382EE1B188B0471304F7C46314DB0CBB134BEFBB722414598390A40969CC7AE29E8C8F69A1ED4DE950A232FE248A547FFF14811DB6C139778A70F32C77B2CE37AD07036EBE18F84290418AE6FC62346ACE529A796A358A4D3581224328D296D49B2CEE9FFD8FBE817833F0068215CEC17472426433C31790DE12DBC370A1567E2D921545BA7A624FEFCF7E553E4A42A9B3E86551EF609BB71E5A6798CBC1204192DA6E00")
flag =b"hkcert24{"for i inrange(28): flag +=bytes([a[i] ^ b[i]])haystack = [BitVec("x{}".format(i), 8)for i inrange(5)]s =Solver()list_char = string.printable[:-6]for i in haystack: s.add(z3.Or(*[ord(j) == i for j in list_char]))v6 =5s.add(haystack[v6 -1] ==ord('}'))s.add(haystack[v6 -2] ==ord('1'))s.add(haystack[v6 -5] + haystack[v6 -4] + haystack[v6 -3] ==300)s.add(2* haystack[v6 -5] + haystack[v6 -4] +2* haystack[v6 -3] ==496)s.add(haystack[v6 -5] +3* haystack[v6 -4] + haystack[v6 -3] ==508 )for model inall_smt(s, haystack): tmp_flag =b""for i in haystack:try: tmp_flag +=bytes([model[i].as_long()])exceptExceptionas e: tmp_flag +=b"?"print(flag + tmp_flag)
There are so many valid solution but we still able to guess the actual one.
Flag: hkcert24{s1m4le_cr4ckM3_4_h4ndByhan6_cha1}
Cyp.ress (200 pts)
Description
You will get sser.pyc when you reverse the title. Now reverse it back for me.
Solution
Solution
Given pyc file, tried to decompile using pycdc but it failed. Lets use pycdas instead
The algorithm is not complex, so we can easility understand it. The program tried to send nonce to the server then the nonce will be used as the base value for generating key and iv same as in client side. The generated key and iv will be used to do encryption with AES MODE_CFB and in the end the ciphertext will be validated with the value from server. So the easy way we can hook the data in request function and AES function.
First, modify code in requests library to printout the ciphertext (flag)
python3.12/site-packages/requests/api.py
defpost(url,data=None,json=None,**kwargs):r"""Sends a POST request. :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the :class:`Request`. :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. :param \*\*kwargs: Optional arguments that ``request`` takes. :return: :class:`Response <Response>` object :rtype: requests.Response """ res =request("post", url, data=data, json=json, **kwargs)print(res.text)return res
Wonton noodles are called 'small minced', rice is called 'handsome', so what was the flag called? Don't worry, I've written a program to help you check if it's right.
Solution
Given ELF file, open it using IDA.
Another flag checker, the algorithm should be in sub_1392.
The important function is on sub_12EF, because it will process our input then the return value will be processed by modulo then comparation. Lets take a look on sub_12EF
It looks like multiplication function, we can validate it by changing the argument during debugging.
Now we know the logic, the next step just recreate the algorithm then brute it. Because it is only 4 bytes so it will not take long times to do bruteforce.
If you haven't tried our last year's ISA challenges, they are back this year with some changes here and there!
This is a challenge to help you get along with the web interface debug environment, which combines as an debugger, an interpreter and challenge connections!
Check the step by step guide to see how to use the frontend and explanation of what this really is! You will try out one of the hardcore reversing method: dealing with assembly and understand them directly!
Given custom asm file, open it using text editor. We can use the playground to debug the program
The objective of this challenge is executing flag binary. From the syscall table, we know which one the instruction that receive our input.
Set breakpoint on 87 (after syscall input), then analyze until XOR instruction that processed our input.
From the debugger we can see that our input (stored at R6) will be xored with R7. R7 values originated from R5, lets take a look on value on R5
We can also see those values in push instruction on the assembly.
So our input will be xored with those static keys and then will be executed as a command. To generate valid command we just need to do the xor with those static keys, below is our script to generate the valid commands.
from Crypto.Util.number import*from pwn import xora = [0xb146f66e,0x2fd8b7c1,0x95e11585,0xcf39fb28,0xb3accf4c,0xdb22a8cb,0xe21f60cd,0xb660d0fe,0x8be89ec9,0x241bd185,0x161d7e99,0xbf3a7f64,0xea7454ee,0x2e04ce47,0x18b25e16,0x2295643e,0x49f8d91f,0x3f541ea6,0x113d8a6f,0x38726ccc,0x2e27be68,0xd4e398ea,0x7fcba040,0xeec775f5,0x478ff266,0x718a3507,0x536edeba,0xf0efb119,0x9efdd1c2,0x977b4203,0x2ceeda0d,0xfdc086ff,0x2303c15a,0x3c9d30a1,0x193f231b,0x1a06a63f,0x5c829f5,0x49c872b8,0x92bcbdad,0xa9a5a84e,0xb16969c,0xb58b3659,0x642069c9,0x9c37ba69,0x623277a4,0x17b6f65c,0xa6a21506,0x15881c76,0x96ed9c50,0x21226b56,0xd8890218,0xca6eddde,0x9a18e395,0x936f6277,0xaf23d230,0x88d9666a,0xff591d2f,0xce454872,0xf3391e9f,0x4ddd147f,0x404bcc99,0x5becacfd,0x1d9f2f1,0xc833a241]
a = a[::-1]key =b""for i in a: key +=long_to_bytes(i)[::-1]command =b"ls\x00\x00"print(xor(command, key[:len(command)]).hex())
from Crypto.Util.number import*from pwn import xora = [0xb146f66e,0x2fd8b7c1,0x95e11585,0xcf39fb28,0xb3accf4c,0xdb22a8cb,0xe21f60cd,0xb660d0fe,0x8be89ec9,0x241bd185,0x161d7e99,0xbf3a7f64,0xea7454ee,0x2e04ce47,0x18b25e16,0x2295643e,0x49f8d91f,0x3f541ea6,0x113d8a6f,0x38726ccc,0x2e27be68,0xd4e398ea,0x7fcba040,0xeec775f5,0x478ff266,0x718a3507,0x536edeba,0xf0efb119,0x9efdd1c2,0x977b4203,0x2ceeda0d,0xfdc086ff,0x2303c15a,0x3c9d30a1,0x193f231b,0x1a06a63f,0x5c829f5,0x49c872b8,0x92bcbdad,0xa9a5a84e,0xb16969c,0xb58b3659,0x642069c9,0x9c37ba69,0x623277a4,0x17b6f65c,0xa6a21506,0x15881c76,0x96ed9c50,0x21226b56,0xd8890218,0xca6eddde,0x9a18e395,0x936f6277,0xaf23d230,0x88d9666a,0xff591d2f,0xce454872,0xf3391e9f,0x4ddd147f,0x404bcc99,0x5becacfd,0x1d9f2f1,0xc833a241]
a = a[::-1]key =b""for i in a: key +=long_to_bytes(i)[::-1]command =b"exec printflag_19876bc2\x00"print(xor(command, key[:len(command)]).hex())
Flag: hkcert24{x0r_1n_isa_r04d_t0_fullch41n!!!}
Morph (300 pts)
Description
Binary sometimes mixed together, just like fried rice or bibimbap.
Solution
Given ELF file, open it using IDA.
From code above we can see that there is decompress function and verify_* function. Lets take a look on decompress function
Then take a look on verify_0 function
So decompress function will do xor with key and size based on the argument. After the function has been decompressed it will be called to verify our input. Lets try to apply decryption to verify_0 to take a look on the logic of input validation.