Here the random module of python can be predicted. If we know the seed value than all the next random int are same every time.
random.seed(time.time())
The seed is set to time.time() and we are given this value in challenge: 1678519928.9423187
know we can easily reverse this xor operation to get original image.
Click to see code :diamond_shape_with_a_dot_inside:
import time
import random
from PIL import Image
random.seed(1678519928.9423187)
flag_matrix = (img := Image.open('pixelite.png')).load()
w, h = img.size
for i in range(w):
for j in range(h):
flag_matrix[i, j] = tuple(
map(
lambda x: x ^ random.randint(0, 255),
flag_matrix[i, j]
)
)
img.save('flag.png')
flag.png:
GLUG{Y0u_4Re_noT_5o_w34k}
funwithrandom-1:
description: randcrack is fun or is it . let's see if you can create your own
output:
y ^= (y >> 43)
1111121111
y ^= (y << 12) & TemperingMaskB
1736326359
y ^= (y << 67) & TemperingMaskC
1736326359
y ^= (y >> 69)
1736326359
now we know that only y ^= (y << 12) & TemperingMaskB this operation is effective rest are not making any changes.
so now we have to reverse this tempering here is python code for that:
def untemper(y):
a = y << 12
b = y ^ (a & TemperingMaskB)
c = b << 12
d = y ^ (c & TemperingMaskB)
e = d << 12
f = y ^ (e & TemperingMaskB)
g = f << 12
h = y ^ (g & TemperingMaskB)
i = h << 12
final = y ^ (i & TemperingMaskB)
return final
now from output[] we can get mt[]. but the for loop was run 624 times so next time we call rand_gen() it will go inside if condition.
for kk in range(N - M):
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK)
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1]
for kk in range(N - M, N - 1):
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK)
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1]
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK)
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1]
we will apply the same changes to our recovered mt[].
now we can get the next 5 int by applying this operations to first 5 elements of mt[].
y = mt[mt_index]
y ^= (y >> 43)
y ^= (y << 12) & TemperingMaskB
y ^= (y << 67) & TemperingMaskC
y ^= (y >> 69)
mt_index += 1
now that we have the next 5 random element we can get the flag.
final python script:
Click to see code :diamond_shape_with_a_dot_inside:
import random
from pwnlib.tubes.remote import remote
N = 624
M = 397
MATRIX_A = 0x83a2b0c3
UPPER_MASK = 0x80000000
LOWER_MASK = 0x7fffffff
TemperingMaskB = 0x3f5663d0
TemperingMaskC = 0x56e90000
mag01 = [0, MATRIX_A]
def untemper(y):
a = y << 12
b = y ^ (a & TemperingMaskB)
c = b << 12
d = y ^ (c & TemperingMaskB)
e = d << 12
f = y ^ (e & TemperingMaskB)
g = f << 12
h = y ^ (g & TemperingMaskB)
i = h << 12
final = y ^ (i & TemperingMaskB)
return final
conn = remote('chall.foobar.nitdgplug.org', 30001)
conn.recvuntil("Generator\n\n".encode())
output = [int(i) for i in (conn.recvline().decode()[1:-2].split(','))]
print(output)
for i in range(len(output)):
output[i] = untemper(output[i])
# print(output)
mt = output
for kk in range(N - M):
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK)
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1]
for kk in range(N - M, N - 1):
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK)
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1]
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK)
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1]
# print(mt)
mt_index = 0
for i in range(5):
y = mt[mt_index]
y ^= (y >> 43)
y ^= (y << 12) & TemperingMaskB
y ^= (y << 67) & TemperingMaskC
y ^= (y >> 69)
mt_index += 1
conn.recvuntil(":".encode())
print(f'{i+1}= {y}')
conn.sendline(f'{y}'.encode())
print(conn.recvline().decode())
conn.close()
Description: Don't think too much. Just push to production http://chall.foobar.nitdgplug.org:30045/
Rest API was boring so I used modern technology.
Let's open this website
Hmn Cannot GET /
I tried robots.txt and checked http response headers but nothing, so I did directory bruteforce and got this endpoint: /graphql GraphQL is a query language developed by Facebook
Introspection is the ability to query which resources are available in the current API schema. Given the API, via introspection, we can see the queries, types, fields, and directives it supports.
GraphQL introspection payload:
{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}
response:
This secret field looks interesting let's extract this.
payload:
{
secret {
text
}
}
response:
when I saw the flag I immediately tried to submit it, but it was wrong then I realised that there are multiple flags.
75 in total.
first I thought it is rabbit hole, but I went through every flag and found this:
this makes sense inspect is challenge name and graphql is endpoint.