Playing Hacks and Stuffs!
Here are the challenges I was able to solve in the ctf which took place on the 6th May, 2023 at lasted from 9A.M - 3P.M
P.S:- The scoreboard was dynamic
After downloading the flag.txt file checking its content shows this
Using DcodeFr I identified the cipher as DTMF Code
Then using its decoder I decoded it
On decoding it gives 681117267847012311910497116951001119511610410195110117109981011141159510910197110125
I then used DcodeFr to identify it as ASCII Code
Then using its decoder I decoded it to get the flag
Flag: DoHCTF{what_do_the_numbers_mean}
After downloading the python file and it’s output.txt I checked it out
Looking at the python code shows this
While it’s output shows this
Using cyberchef I got this
Encoded Flag: GrKFWI{LGDQ_WKH_GHFUBSWRRU}
Then using dcodefr i got the encoded text to be affine cipher
Decoding it forms this
Flag: DoHCTF{IDAN_THE_DECRYPTOOR}
After downloading the file keylog.txt and viewing its content it shows this
At first this looks weird lol but after arranging it well i got this
Here’s how i arranged it
Command: cat keylog.txt | cut -d ':' -f 2 | tr '\n' ' '
Now we can manually remove the spaces to form this
844339666777555555 344277777777 6666888337 33 366666
Then using dcodefr you know the drill I got the cipher it is which turns out to be Multi-tap Phone (SMS)
Decoding it forms this
THEWORLL DHASS OMVEP E DON
At this point it looks like readable English but somehow after a while of nobody solving it they gave this hint
From the hint we know that how the word should be arranged. I was able to arrange the first three words but the remaining last two were hard 😭
Then I told my team mate @cyberhajibi and immediately she got it 💀
It turned out to be: (Note the flag isn’t case sensitive)
TheWorldHasMovedOn
####
Unfortunately the challs are not more up
But TD;LR: The challenge involves a login and a register page. When we register we get directed to our account and the flag isn’t there. And the page was saying something about we are not admin then looking at the login page source code (CTRL + U) discloses the admin email address and what we will notice is that the login submit button is disabled. Trying to register another account using the admin email shows user already exists trying SQL Truncation works now we have access over the admin account. So we can login using it but we will need to inspect element and change the disabled field to enabled then after loggin in, we get the flag
For the second web challenge: We’re given a page and only one end point in it and that endpoint involves purchasing the flag. But we are only currently having about 18000 If i can remember. Now we are not actually given a specfic amount on how much the flag worths and trying to like buy the flag shows fails 🤔
Looking at the logic of the web app we can tell that it does something like this:
amount = 180000
price = 20000
buy_flag = price - amount
if buy_flag > $some_amount:
print('Purchased')
else:
print('Failed')
Another thing we should note is that the cookie is a jwt token which when decoded gives a json array of something like:
{
"username": "guest123321",
"flag": "0"
}
And it’s algorithm is HS256 . Since we don’t currently have the flag the flag variable of our cookie is just zero. But if we purchase the flag it should return the flag. But now how do we achieve purchasing the flag 🤔
From the logic proposed earlier if no form of sanitation is done to check the usage of a negative number what happens :
amount = -18000
price = 20000
buy_flag = price - amount
if buy_flag > $some_amount:
print('Purchased')
else:
print('Failed')
We can see that the buy_flag variable will return a huge number sweeeet 😅
After I tried that it showed purchased then on viewing the jwt decoded token gives the flag
During the CTF I was unable to solve this due to my lack of knowledge on algorithm (learnt few things recently so I decided to give this a go)
The source code wasn’t given but here it is
import random
def game():
remaining_tries = 32
answer = random.randint(1,1000000000)
while remaining_tries > 0:
try:
guess = int(input("Guess an integer btw 1 and 1 billion\n"))
if guess == answer:
print("You got it right! DoHCTF{??????????????????}\n")
return
elif guess < answer:
print("Higher\n")
else:
print("Lower\n")
remaining_tries -= 1
except ValueError:
print("Not a valid integer. Please try again.\n")
print("Out of tries. Game over!\n")
game()
From the python program we see that:
Initially what I was trying during the ctf was to narrow down the answer
I didn’t know that it was random number each time we connected to the server and that took my time lol i’m a bad ctf player
But anyways there’s no way of brute forcing it because of the number of trials we have and also it will take lot of memory if we are to brute force
So what’s the way here
Well the answer is using Binary Search Algorithm
What the algorithm basically does is to narrow down a target value in a sorted array by repeatedly dividing the search interval in half
The idea of binary search is to use the information that the array is sorted and reduce the time complexity to O(log N)
You can read more about it here
Here’s my solve script
# Implement Binary Search Algorithm
from pwn import *
context.log_level = 'warning'
io = remote('127.0.0.1', '1234')
def binary_search():
left = 0
right = 1000000000
while True:
mid = (right + left) // 2
io.sendline(str(mid).encode())
recv = io.recv(1024).decode().strip()
log.info(f'Flag: {recv}')
if 'Higher' in recv:
left = mid
continue
elif 'Lower' in recv:
right = mid
else:
return recv
result = binary_search()
print(result)
io.close()
Running it works and we get the flag
Flag: DoHCTF{automation_is_king_}
The CTF was really fun even tho the time was given to solve the challenges were quite not enough but overall I thank the organizers for hosting it and also @Lytes for his wonderful challenges
After the struggle my team took second 😅
Till another CTF Adios 👻