Typeracer
if we take a look at the page source, we can see obf.js, inside it was a very obfuscated code, using this tool we can see the code much clearer. Let's take a look at some interesting part of the code.
'_0x1ec2f5': _0x7379('0x26f', 'QvUT'),
'_0x1c2030': _0x7379('0x20', 'zyUu') + 'ou have be' + _0x7379('0x4c4', '9f2)') + _0x7379('0x570', 'Y@$M') + _0x7379('0x505', 'XVoV') + 'iQ1RGe3c0M' + _0x7379('0x649', '*a95') + _0x7379('0x55a', 'nB&s') + 'l80bm4weTF' + _0x7379('0x143', '&H2q'),
'_0x1e6fbe': function(_0x2a6b00, _0x43d36c) {
return _0x2a6b00 + _0x43d36c;
},
'_0x141f90': _0x7379('0x3cb', '*f#2') + _0x7379('0x4eb', '%7!)') + 'y keyboard' + _0x7379('0x22a', 'M9PA') + _0x7379('0x191', 'Y@$M') + 'em the fla' + 'g. Perhaps' + _0x7379('0x120', 'T2UE') + 'n?',
'_0x8fd743': 'wpm',
'_0x4ea8ac': _0x7379('0x566', 'I7*N'),
we can see there is some strings like em flag. Perhaps
that looks like the message that we got after we finished the typing challenge, we can confirm this by running it on the javascript console. As you continue running some part of the code around it that's actually the congratulations message.
_0x7379('0x20', 'zyUu') + 'ou have be' + _0x7379('0x4c4', '9f2)') + _0x7379('0x570', 'Y@$M') + _0x7379('0x505', 'XVoV') + 'iQ1RGe3c0M' + _0x7379('0x649', '*a95') + _0x7379('0x55a', 'nB&s') + 'l80bm4weTF' + _0x7379('0x143', '&H2q')
which translates to
Congrats you have beaten me! Here's your flag: cmdiQ1RGe3c0MHdfajR2NDJjcjFwN18xMl80bm4weTFuZ30=
decode the base64 and we got the flag.
flag : rgbCTF{w40w_j4v42cr1p7_12_4nn0y1ng}
Ralphie!
A stego challenge, using aperisolve, we can see there is a hidden qr code in it, scan it and we get the flag.
flag : rgbCTF{BESURETODRINKYOUROVALTINE}
Hallo?
First I convert it into a wav file, then I run this tool to detect the dtmf tones, it's not really accurate, so I need to listen it a few times until I found the flag.
flag : rgbctf#yeet#dtmf#tones#
Too Slow
Let's take a look at main:
int main(void)
{
uint uVar1;
puts("Flag Decryptor v1.0");
puts("Generating key...");
uVar1 = getKey();
win((ulong)uVar1);
return 0;
}
so far it looks pretty normal, let's take a look at getKey:
ulong getKey(void)
{
uint i;
uint c;
i = 0;
while (i < 0x265d1d23) {
c = i;
while (c != 1) {
if ((c & 1) == 0) {
c = (int)c / 2;
}
else {
c = c * 3 + 1;
}
}
i = i + 1;
}
return (ulong)i;
}
as you can see it looks like c
is operated a lot, but the function return i
, i
didn't affected by c
and only incremented by 1 every loop, so we know that getKey will return 0x265d1d23.
We can use GDB to change the value and skip the getKey function (btw I use gdb gef).
b main
r
set $eax = 0x265d1d23
jump *main+53
flag : rgbCTF{pr3d1ct4bl3_k3y_n33d5_no_w41t_cab79d}
Advanced Reversing Mechanics 1
let's take a look at encryptFlag() function:
void encryptFlag(char *flag)
{
char flag2;
flag2 = *flag;
if (flag2 == '\0') {
return;
}
do {
*flag = flag2 + -1;
flag = flag + 1;
flag2 = *flag;
} while (flag2 != '\0');
return;
}
it might be a little confusing for some people, but basically *flag
with *
is the value of the curent flag address, and flag
without *
is the the current index of the flag, so the code will looks something like this:
i = 0
flag2 = flag[0]
while True:
flag[i] = flag2 - 1
i = i + 1
try:
flag2 = flag[i]
except IndexError:
break
so basically the code lops through the flag and decrease all character by one, now let's write the solve script that increment all the character by one.
x = [0x71, 0x66, 0x61, 0x42, 0x53, 0x45, 0x7A, 0x40, 0x51, 0x4C, 0x5E, 0x30, 0x79, 0x5E, 0x31, 0x5E, 0x64, 0x59, 0x5E, 0x38, 0x61, 0x36, 0x65, 0x37, 0x63, 0x7C]
flag = ""
for i in x:
flag += chr(i+1)
print (flag)
flag : rgbCTF{ARM_1z_2_eZ_9b7f8d}
I Love Rainbows
We are given a file each line containing 32-64 characters, which looks like hashes, using crackstation we can see that each hash contains 1 to 2 characters from the flag, cracking all the hash and we got the flag.
flag : rgbCTF{4lw4ys_us3_s4lt_wh3n_h4shing}
e
For this challenge N is insanely large, because of that the the ciphertext did not reach N at this point, so we can just take eth root of c and get the flag
import gmpy2
from Crypto.Util.number import long_to_bytes as ltb
n = 0x5fb76f7f36c0d7788650e3e81fe18ad105970eb2dd19576d29e8a8697ebbd97f4fc2582bf1dc53d527953d9615439ca1b546b2fc1cd533db5fce6f72419f268e3182c0324a631a17d6b3e76540f52f2df51ca34983392d274f292139c28990660fa0e23d1b350da7aa7458a3783107a296dcd1720e32afb431954d8896f0587cd1c8f1d20701d6173b7cffe53679ebda80f137c83276d6628697961f5fcd39e18316770917338c6dc59a241dcdc66417fed42524c33093251c1d318b9dbeb6c3d0a69438b875958e8885d242d196e25bc73595e7f237c8124e07a79f7066f2dee393e2130306ba29e7ece1825798ff8b35416b3a0d96bcdc6eca5616ea2874954f8f88232450ddad3e109338bcc5d84e7b592a6b0871bd4130b84f81ed188e9d5495c8545aa8dea2b65e8605f5a49e3a1c221cbcc301665187658784a8f42a23c2ca2572477ba56ff19934019b48f5a1ab8a50626c85bdd476b11e8c1fb0b740c2370de3da5cc06371a7aa2c4e12eee3dc4cda07a8c84ba2bc3ee2017156468af95111d7ee5152ce35e66fa027a944b43c27fbd27faa5b4f9075be3526a7a5be8a533b523cd5c738c724e97597fc2e3666cfcad7c79d972ff8d9572100e860395cdc3761af3f4cc225a6df83a55802723f95cfba5918d83913f2cc9b219210249928c291310d449042772e2d0a50620d666a137f79770de6f10196b30cc756e1
e = 0b1101
c = gmpy2.mpz(0x6003a15ff3f9bc74fcc48dc0f5fc59c31cb84df2424c9311d94cb40570eeaa78e0f8fc2917addd1afc8e5810b2e80a95019c88c4ee74849777eb9d0ee27ab80d3528c6f3f95a37d1581f9b3cd8976904c42f8613ee79cf8c94074ede9f034b61433f1fef835f2a0a45663ec4a0facedc068f6fa2b534c9c7a2f4789c699c2dcd952ed82180a6de00a51904c2df74eb73996845842276d5523c66800034351204b921d4780180ca646421c61033017e4986d9f6a892ed649c4fd40d4cf5b4faf0befb1e2098ee33b8bea461a8626dd8cd2eed05ccd471700e2a1b99ed347660cbd0f202212f6c0d7ad8ef6f878d887af0cd0429c417c9f7dd64890146b91152ea0c30637ce503635018fd2caf436a12378e5892992b8ec563f0988fc0cebd2926662d4604b8393fb2000)
gmpy2.get_context().precision=200
x = int(gmpy2.root(c,e))
assert pow(x,e,n) == c
print ltb(x)[::-1]
flag : rgbCTF{lucky_number_13}
Occasionally Tested Protocol
Classic OTP with time as the seed, we can just get time the same time as we connect to the server, and test the seed locally. You can see the script that I used to find the approximate time on the commented code below.
from random import seed, randint as w
from time import time
# import pwn
# j = int(time())
# print (j)
# r = pwn.remote("167.172.123.213", 12345)
# print (r.recv())
# r.close()
try_seed = 1594516169
result = [2327,5113,7373,8967,5424,9245,9867,7147,7924,723]
found = False
while not found:
seed(try_seed)
for i in range(10):
if w(5,10000) == result[i]:
found = True
else:
found = False
try_seed+=1
break
b = bytearray([w(0, 255) for _ in range(40)])
flag = int.to_bytes(9756397644136381438199947801771447561151891907369603561251869566720,999,'little').rstrip(b"\x00")
n = bytearray([l ^ p for l, p in zip(flag, b)])
print (n)
flag : rgbCTF{random_is_not_secure}
Shakespeare Play, Lost (and found!)
It's a book cipher,the first number correspond to the nth line of the book, and the second number correspond to the nth character of the line.
keys = [[33, 20],[71, 5],[43, 142],[60, 150],[73, 312],[78, 66],[15, 22],[12, 115],[29, 18],[51, 147],[45, 68],[34, 14],[54, 126],[15, 48],[3, 4],[60, 126],[45, 77],[13, 69]]
text = open("play").read().split("\n")
flag = ''
for key in keys:
flag += (text[key[0]])[key[1]]
print "rgbCTF{" + flag + "}"
flag : rgbCTF{itsanrgbtreeeeeee!}
A Basic Challenge
This challenge is a decoding challenge from various base, starting from binary(base 2),hex(base 16), and so on. I wrote a simple python script that you can hopefully understand
import base64
cipher = open("basic_chall.txt").read().split(" ")
flag = ""
# binary decode
for each in cipher:
flag += chr(int(each,2))
cipher = flag.split(" ")
flag = ""
# hex decode
for each in cipher:
flag += chr(int(each,16))
# base 64 decode
flag = base64.b64decode(flag).decode()
cipher = flag.split(" ")
flag = ""
# octal decode
for each in cipher:
flag += chr(int(each,8))
print (flag)
flag : rgbCTF{c0ngr4ts_0n_b3ing_B4SIC}
Joke Check!
Given this ciphertext crmNEQ{l_nstnvpy_nlpdlc_dlwlo}
it looks like it's already on the flag format, decoding using caesar cipher with the amount of 15 gives us the flag.
flag : rgbCTF{a_chicken_caesar_salad}
A Fine Day
This time we are given a larger ciphertext with something that looks like the flag at the end, this time because there's a lot of character it is feasible to do a substitution cipher, although affine cipher is the intended solution.
flag : rgbCTF{a_fine_affine_cipher}
r/ciphers
This time the intended solution is to do a substitution cipher
flag : rgbCTF{just_4sk_th3_int3rn3t_t0_d3crypt_it}
Simple RSA
This is where things starts to get real, we are given [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem) public keys, where public keys are used to encrypt a message, to decrypt the message, we have to factor n
, and then perform some calculations stated in wikipedia, RSA security heavily relies on how large the number is, however in this case n
is relatively small, we can find it's factor at the database
from Crypto.Util.number import long_to_bytes as ltb
n= 5620911691885906751399467870749963159674169260381
e=65537
c=1415060907955076984980255543080831671725408472748
p = 255097177
q = 22034393943473183756163118460342519430053
phi = (p-1)*(q-1)
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
d = modinv(e,phi)
print (ltb(pow(c,d,n)).decode())
we get a flipped flag but we can just flip it back.
flag : rgbCTF{brut3_f0rc3}
Pieces
In this challenge we have to reverse the divide() function to get the flag back, we can see the divide function divide our input by 2, and then added it to variable ans, and then compared with something, so we can simply multiply the characters they used to compare and get the flag, however it's not that easy,
61 / 2 = 30
60 / 2 = 30
In above example we can see two different numbers have the same result when divided by 2 because of rounding, but we see that they also added /
or |
in variable ans so we can know whether or not the character supposed to be even, or odd numbers.
cipher = "9|2/9/:|4/7|8|4/2/1/2/9/"
flag = ''
for i in range(0,len(cipher),2):
if cipher[i+1] == "|":
flag += chr(ord(cipher[i])*2)
else:
flag += chr(ord(cipher[i])*2 + 1)
print (flag)
flag: rgbCTF{restinpieces}
Shoob
For this challenge we gonna use a very nice stego tool, after uploading the image, we can see the very first superimposed image has some red text in it which is the flag.
flag : rgbCTF{3zier_4haN_s4n1ty}
Quirky Resolution
Using aperisolve, we can see a large qrcode, scanning it with a mobile qrcode scanner gives us the flag.
flag : rgbCTF{th3_qu1rk!er_th3_b3tt3r}