I wonder what this really is... enc''.join([chr((ord(flag[i]) << 8) + ord(flag[i + 1])) for i in range(0, len(flag), 2)])
Solution
The encoding scheme acts on two characters from the flag each time. The first character is used as higher 8 bits, while the second character is used as lower 8 bits. Together, the 2-character pair is transformed into a 16-bit binary number and this binary number is converted to ASCII character.
Implementation
#!/usr/bin/env python3withopen('enc', 'r')as f: encoded = f.read() flag =''for ch in encoded: binary ="{0:016b}".format(ord(ch)) first_half, second_half = binary[:8], binary[8:] flag +=chr(int(first_half, 2)) flag +=chr(int(second_half, 2))print(flag)
defcheck_key(key,username_trial):global key_full_template_trialiflen(key)!=len(key_full_template_trial):returnFalseelse:# Check static base key part --v i =0for c in key_part_static1_trial:if key[i]!= c:returnFalse i +=1# TODO : test performance on toolbox container# Check dynamic part --vif key[i]!= hashlib.sha256(username_trial).hexdigest()[4]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[5]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[3]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[6]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[2]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[7]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[1]:returnFalseelse: i +=1if key[i]!= hashlib.sha256(username_trial).hexdigest()[8]:returnFalsereturnTrue
Solution
According to the global variables declared at the beginning of the source code, the flag is picoCTF{1n_7h3_|<3y_of_xxxxxxxx} where x stands for a "dynamic" character. Our objective is to reverse engineer the check_key function and pass the check.
Note that check_key is not fully implemented and there are eight if statements checking if a certain character is valid. We could simply write a script and recover each character.
# Hiding this really important number in an obscure piece of code is brilliant!# AND it's encrypted!# We want our biggest client to know his information is safe with us.bezos_cc_secret ="A:4@r%uL`M-^M0c0AbcM-MFE055a4ce`eN"# Reference alphabetalphabet ="!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+\"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"defdecode_secret(secret):"""ROT47 decodeNOTE: encode and decode are the same operation in the ROT cipher family. """# Encryption key rotate_const =47# Storage for decoded secret decoded =""# decode loopfor c in secret: index = alphabet.find(c) original_index = (index + rotate_const) %len(alphabet) decoded = decoded + alphabet[original_index]print(decoded)defchoose_greatest():"""Echo the largest of the two numbers given by the user to the program Warning: this function was written quickly and needs proper error handling """ user_value_1 =input("What's your first number? ") user_value_2 =input("What's your second number? ") greatest_value = user_value_1 # need a value to return if 1 & 2 are equalif user_value_1 > user_value_2: greatest_value = user_value_1elif user_value_1 < user_value_2: greatest_value = user_value_2print( "The number with largest positive magnitude is "+str(greatest_value) )choose_greatest()
Solution
Modify the source code to call the decode_secret function.
What integer does this program print with arguments 1765227561 and 1830628817? File: chall.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
The main function calls atoi twice to convert the arguments to integers and then calls func1 to compare those two integers. Since 1765227561≤1830628817, the control flow goes to .L2. Now w0 = [sp+8] = 1830628817 = x0.
Eventually, when printf is called, the value stored in x0 will be printed (calling convention). Hence this program prints 1830628817, which is 0x6d1d2dd1 in hex.
speeds and feeds
Challenge
There is something on my shop network running at mercury.picoctf.net:53740, but I can't tell what it is. Can you?
For what argument does this program print win with variables 85, 6 and 3? File: chall_1.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
lsl: Logical Shift Left. It provides the value of a register multiplied by a power of two, inserting zeros into the vacated bit positions
sdiv: Signed Divide
Note that the x29 register is the frame pointer in ARM64. It is equivalent to the RBP register in Intel x86-64. The function func is just doing math:
385⋅26=arg
Hence arg = 1813, which is 0x715 in hex.
ARMssembly 2
Challenge
What integer does this program print with argument 3848786505? File: chall_2.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
Solution
b: Branch. This is the uncoditional branch
bcc: Branch on Carry Clear. This is the conditional branch
Note that the wzr register is equivalent to 0. The instruction str wzr, [sp, 24] zeros out the content of [sp+24].
Here [sp+24] is the result and [sp+28] is the counter. The loop keeps increment [sp+24] by 3 and compares the counter [sp+28] with 3848786505. In the end, the result [sp+24] is printed out. In other word, the program computes 3848786505 * 3 = 11546359515, which is 0x2b03776db in hex. Since the flag requires 32-bit hex, this hex number is truncated as 0xb03776db.
Hmmm this is a weird file... enter_password. There is a instance of the service running at mercury.picoctf.net:35862.
Solution
ARMssembly 3
Challenge
What integer does this program print with argument 3350728462? File: chall_3.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
The program computes and w0, w0, 1, where w0 is the argument. If the w0 & 1 = 1, it increments the counter by 3. Otherwise, it does nothing and continues. After each round of testing, the program divides w0 by 2 and repeats this test until w0 = 0.
Since PIE is enabled, all the addresses here are just offsets. We need to run the program for the correct addresses to load:
pwndbg> r
...
pwndbg> disass main
The memcmp function compares our input with the flag. Set a breakpoint on memcmp and run the program again:
pwndbg> b *0x00005555555552f6
pwndbg> r
The flag is located in RSI at this moment:
Easy as GDB
Challenge
The flag has got to be checked somewhere... File: brute
Solution
Take a look at the pseudocode:
Here unk_2008 is the encrypted flag:
This is a nice use case for the angr template. What we have to do here is:
Figure out the flag length
Find the address of the "Correct!" state
Find the address of the "Incorrect." state
The length of the encrypted flag is 30, so the flag in clear should be 30-byte long as well.
The call puts instruction for "Correct!":
The call puts instruction for "Incorrect.":
Implementation
#!/usr/bin/env python3import angrimport claripyFLAG_LEN =30STDIN_FD =0base_addr =0x100000# To match addresses to Ghidraproj = angr.Project('brute', main_opts={'base_addr': base_addr})flag_chars = [claripy.BVS('flag_%d'% i, 8)for i inrange(FLAG_LEN)]flag = claripy.Concat( *flag_chars + [claripy.BVV(b'\n')])# Add \n for scanf() to accept the inputstate = proj.factory.full_init_state( args=['brute'], add_options=angr.options.unicorn, stdin=flag,)# Add constraints that all characters are printablefor k in flag_chars: state.solver.add(k >=ord('!')) state.solver.add(k <=ord('~'))simgr = proj.factory.simulation_manager(state)find_addr =0x100a72# the address of "call puts" for SUCCESSavoid_addr =0x100a86# the address of "call puts" for FAILUREsimgr.explore(find=find_addr, avoid=avoid_addr)if (len(simgr.found)>0):for found in simgr.found:print(found.posix.dumps(STDIN_FD))
Start an angr Docker environment:
docker run -it angr/angr
Run this script and wait. The script will take some time to finish, so be patient.
ARMssembly 4
Challenge
What integer does this program print with argument 3964545182? File: chall_4.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
arg = 3964545182
1. func1: 3964545182 + 100 = 3964545282
2. func2: 3964545282 + 13 = 3964545295
3. func5: do nothing
4. func8: 3964545295 + 2 = 3964545297
5. func1: do nothing
6. func3: do nothing
7. func7: do nothing
result = 3964545297 = 0xec4e2911
Powershelly
Someone, solve it!
Challenge
It's not a bad idea to learn to read Powershell. We give you the output, but do you think you can find the input? rev_PS.ps1output.txt
Solution
Todo!
Rolling My Own
Someone, solve it!
Challenge
I don't trust password checkers made by other people, so I wrote my own. It doesn't even need to store the password! If you can crack it I'll give you a flag. remotenc mercury.picoctf.net 17615
Solution
Todo!
Checkpass
Someone, solve it!
Challenge
What is the password? File: checkpass Flag format: picoCTF{...}