I participated in the CyberStarters CTF qualifier competition organized by the Diary of Hackers, took place between April 28th to April 30th 2023. For me personally I got to learn new things
This is a writeup of the challenges I solved during the event. Lets jump right into it
Challenges Solved
Sanity Check
- Discord (10 points)
- DoHCTF{_colwSPs:(} (10 points)
- Twitter (10 points)
Steg
- OK (46 points)
Web
- None Shall Pass (68 points)
- ^_^ (200 points)
Cryptography
- di_sease (100 points)
- Hensel’s Mystery (376 points)
Osint
- Rogue Agent (151 points)
BlockChain
- Ask The Block (100 points)
Sanity Check
Discord (10 points)
Clicking on the link takes us to the Disocrd Server
Well, scrolling down that channel we find a base64 code just sitting there
Let’s go ahead and crack this RG9IQ1RGe3RyeV90b19iZV9oYWNrdGl2ZV9vbl9kaXNjb3JkX2hlaGVoZWhlaGVoZX0K
since we already know it’s base64 hehe
command:echo RG9IQ1RGe3RyeV90b19iZV9oYWNrdGl2ZV9vbl9kaXNjb3JkX2hlaGVoZWhlaGVoZX0K | base64 --d
Cool, we got our flag hehe😎
FLAG:- DoHCTF{try_to_be_hacktive_on_discord_hehehehehehe}
DoHCTF{_colwSPs:(} (10 points)
Yeah, this challenge is just to check if your sanity is still intact lool. The flag is the name of the challenge.
FLAG:- DoHCTF{_colwSPs:(}
Twitter (10 points)
The link redirects you to their twitter page
Following them gives us the answer to this challenge.
FLAG:- yes
Steg
OK (46 points)
Lets download the file to our machine
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Steg]
└─$ ls
0cold_flag.txt
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Steg]
└─$ file 0cold_flag.txt
0cold_flag.txt: ASCII text
A text file, cool. Lets try to read the contents of the file
command:cat 0cold_flag.txt
oops, there seems to be some spacing after the word “Iceeeedddd”. I have once solved a similar challenge and I remember using stegnow
to solve it. To install stegsnow sudo apt install stegsnow
command:stegsnow -C 0cold_flag.txt
cool, we got our flag
FLAG:- DoHCTF{another_quite_simple_one}
Web
None Shall Pass (68 points)
Goint to the link provided should get you this
Who are you?? I am BlackAnon lool😂. There was nothing else asides the who are you?
. There was also nothing in the source page.
At this point I had to invite Burpsuite to join the party😎. Lets try to capture requests
Lets send this to repeater
We can see that the cookie uses a jwt token. Lets try to crack this token. You can do that here
Lets try changing the guest name to admin
Now, lets replace the jwt token
with this new one
oops, We got the Invalid Token error
Well, after a bit of research I found something interesting. I remember completing the owasptop10 2021
room on TryHackMe. Checking the notes I took down I saw this
Now, this vulnerability falls under the owasptop10, the name of the vulnerability is Data Integrity Failures
. You can learn more about it here.
At this point I just had to follow what I had in my note😎. Let’s go this webpage
This is my JWT Token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.iJ9U4tIUxxLbbOb_YXVkpvkBqtPsFtAxWIvmcakDfL0
. So the first part
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
is the header. The second part eyJ1c2VybmFtZSI6Imd1ZXN0In0
is the payload while the last part iJ9U4tIUxxLbbOb_YXVkpvkBqtPsFtAxWIvmcakDfL0
is the signature.
So, we’ll be modifying only the header and the payload. Lets start with the header
Lets go ahead and change the alg HS256
to none
. Then we encode in base64
cool we have modified the header eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0=
. Lets do the same for the payload
Lets go ahead and change the username guest
to admin
. Then we encode in base64
cool, we have also modified the payload eyJ1c2VybmFtZSI6ImFkbWluIn0=
.
Now, joining the header
, payload
and signature
together, we have eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0=.eyJ1c2VybmFtZSI6ImFkbWluIn0=.iJ9U4tIUxxLbbOb_YXVkpvkBqtPsFtAxWIvmcakDfL0
.
The last thing left to do is replacing the old jwt token
to the modified one
showing this response in the web browser
We got our flag😎
FLAG:- DoHCTF{jwt_has_a_none_algo_loll}
^_^ (200 points)
We were told not to bruteforce lool, this means we don’t need directory fuzzing tools. Lets navigate to the webpage
We get this, take note of the url
Now, those look like base64 code. Checking the source page
We get 2 more directories also looking like base64 code. Now, trying to crack this was giving me some weird strings.
What do I mean??
These are the directories that look base64 ish
/GgoXAQ4QGxMCHA4ZA1JKDFlWAEFRG1YQGw/c2RzZHZ5dXdnZGd3ZzcyZTcyZTk4dTJ1Yw
/HwEBBw0WGQ0HAQEaVBYcEAwHHw0QHRAaHxAdEAEQ/c2R1c2hkdWhzdWRoOHNoZGl1c2hkaXVoc3VpZGRi
/ISdFLDRLKitfPDRKRT0SCRcHEBIIFwsTEg/QEUqWUAqSEQqSFUoKkhmaHVoZWZpdWRmZg
For example, lets try to crack this ISdFLDRLKitfPDRKRT0SCRcHEBIIFwsTEg
command:echo ISdFLDRLKitfPDRKRT0SCRcHEBIIFwsTEg | base64 --d
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Web]
└─$ echo ISdFLDRLKitfPDRKRT0SCRcHEBIIFwsTEg | base64 --d
!'E,4K*+_<4JE=
base64: invalid input
Now, this is the weird string I was talking about.
Well, I had to sacrifice 20 points to unlock the hint so as to know the next course of action
Now, from the hint we got ^ bitwise operation
.
Taking a look at the directories you’ll observe they have the same length (i.e before and after the /).
For example,
We’ll be xoring HwEBBw0WGQ0HAQEaVBYcEAwHHw0QHRAaHxAdEAEQ
with c2R1c2hkdWhzdWRoOHNoZGl1c2hkaXVoc3VpZGRi
to see if we can get something.
I’ll be using this python script
import base64
# Example base64 encoded strings
encoded_str1 = "HwEBBw0WGQ0HAQEaVBYcEAwHHw0QHRAaHxAdEAEQ"
encoded_str2 = "c2R1c2hkdWhzdWRoOHNoZGl1c2hkaXVoc3VpZGRi"
# Base64 decode the encoded strings
decoded_str1 = base64.b64decode(encoded_str1)
decoded_str2 = base64.b64decode(encoded_str2)
# XOR the two decoded strings
xored_str = bytes([a ^ b for a, b in zip(decoded_str1, decoded_str2)])
# Print the result
print(xored_str)
This script demonstrates how to perform XOR operation between two base64-encoded strings
Lets run it
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Web]
└─$ ls
abeg.py
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Web]
└─$ python abeg.py
b'letterletterletterletterletter'
cool, I got this. Fortunately they gave a free hint which goes like this
indexindexindexindexindex
aboutaboutaboutaboutabout
letterletterletterletterletter
flagflagflagflagflag
From our script we ran earlier we can tell that we are on the right path. Now, what we have to do is to look for a way to encode the flagflagflagflagflag
to it’s base64 representation then we xor null byte with null byte which will give A. After we can make the length of the base64 encoded form of A to be equal to len of null byte which is 28.
The reason why we are using null byte is because when you xor something with zero you get that samme value being xored and when you xor two things that are the same you get zero.
For this we’ll be using a python script
from pwn import xor
import base64 as b
flag = b'flagflagflagflagflag'
encoded_flag = b.b64encode(flag)
null = b'0x0'
xored = xor(null, null)
second_ = b.b64encode(xored) * 7
print(encoded_flag+b'/'+second_)
Save this script and run it
We got the output we wanted, lets navigate to this directory, hopefully we get our flag
cool, we got our flag😎
FLAG:- DoHCTF{xor_rox_xor}
Cryptography
di_sease (100 points)
Lets download the file to our machine
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ ls
flag.png
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ file flag.png
flag.png: PNG image data, 814 x 156, 8-bit/color RGBA, non-interlaced
Okay,this is a PNG image. Lets try to use zsteg
on the image, we might find something interesting hehe
command:zsteg flag.png
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ zsteg flag.png
meta Software .. text: "gnome-screenshot"
meta Creation Time .. text: "Thu 27 Apr 2023 14:24:34"
b1,r,msb,xy .. file: Unicode text, UTF-32, big-endian
b1,rgba,lsb,xy .. text: ["w" repeated 8 times]
b1,abgr,msb,xy .. text: ["w" repeated 8 times]
b2,r,lsb,xy .. text: "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUP"
b2,rgba,lsb,xy .. text: ["?" repeated 17 times]
b2,abgr,msb,xy .. text: ["?" repeated 17 times]
b4,r,lsb,xy .. text: ["U" repeated 247 times]
b4,g,lsb,xy .. text: ["w" repeated 247 times]
b4,b,lsb,xy .. text: "333333337wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
b4,rgb,lsb,xy .. text: "5wWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwW"
b4,bgr,lsb,xy .. text: "uwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuwWuw"
oops, nothing
Lets try to check what the image is all about
hehe, this is a navy signal code
. We’ll be using dcode.fr for this.
We got something DOHCTFTHEFLAGSREVEALED009
, looks like the flag, but it is not the flag because that is not the right format.
Lets rearrange it
FLAG:- DoHCTF{The_flags_revealed_009}
Hensel’s Mystery (360 points)
Lets download the files to our machine
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ ls
flag.png output.txt ring.py
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ file output.txt
output.txt: ASCII text, with very long lines (884)
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ file ring.py
ring.py: Python script, ASCII text executable
We got ourselves an ASCII text and a Python script.
The content of both files
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ cat output.txt
45406770103725904509890104231914678754265961643298482440409237765195072368733672685631587979562241346*x^4 + 42764372489624602989152383173709795403796386376344802703066528962696589468564501897000324538498812883*x^3 + 37672731284607729155480237866218406485893919987814572486490754064498223292180995037432012350216544417*x^2 + 55462425449896168600390367564436787134741290054741525865807795492693442375757671549228298754153509613*x + 6778690755895128168751737959454411972187106669733266559106651743590246692689398562032067795146717162848413292299573013038367117575935673619248776925892672201933424467005517162118712395701681263279585553299544107860626811206695844212433182471614373859755499052750286667585910623259340579702249091680614010546399687179863049582625671630876108790555962058243905551470611736992489702159306356102118074450673803009393106039180751255185874156459283395261688861
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/CyberStarters_CTF/Cryptography]
└─$ cat ring.py
from sage.all import *
import codecs
def read_flag():
with open('flag.txt', 'r') as file:
return file.read().strip()
def encode_flag(flag):
encoded = codecs.encode(flag.encode(), 'hex')
return int(encoded, 16)
def generate_polynomial(flag):
ranges = int(log(flag, 2))
p = 35671
k = 100
N = p**k
d = 5
P = PolynomialRing(Zmod(N), names='x', implementation='NTL')
x = P.gen()
poly = 0
for c in range(d):
poly += ZZ.random_element(2**ranges, 2**(ranges+1))*x**c
remainder = poly(flag)
poly = poly - remainder
assert poly(flag) == 0
return poly
def main():
flag = read_flag()
encoded_flag = encode_flag(flag)
poly = generate_polynomial(encoded_flag)
print(poly)
if __name__ == '__main__':
main()
what does this script do??
This Python script uses the SageMath library to generate a polynomial with a specific property. The polynomial is generated based on an encoded flag read from a file called "flag.txt". The encoding of the flag is done by converting the flag string to its hexadecimal representation and then converting the hexadecimal representation to an integer.Well, I am not really a cryptography fanboy. Went online to read writeups and I found this
From the script it is clear that the output is the root of a polynomial, and the file output..txt
contains some polynomials. So, the challenge is to find the root of the polynomial.
To solve this challenge, we can first find a solution for the given polynomial over mod p
and then use Hensel’s lifting lemma to find a solution
I’ll be using this python script to solve the challenge
from sage.all import *
p = 35671
k = 100
N = p**k
P = PolynomialRing(Zmod(p), names='x', implementation='NTL')
x = P.gen()
pol = 45406770103725904509890104231914678754265961643298482440409237765195072368733672685631587979562241346*x**4 + 42764372489624602989152383173709795403796386376344802703066528962696589468564501897000324538498812883*x**3 + 37672731284607729155480237866218406485893919987814572486490754064498223292180995037432012350216544417*x**2 + 55462425449896168600390367564436787134741290054741525865807795492693442375757671549228298754153509613*x + 6778690755895128168751737959454411972187106669733266559106651743590246692689398562032067795146717162848413292299573013038367117575935673619248776925892672201933424467005517162118712395701681263279585553299544107860626811206695844212433182471614373859755499052750286667585910623259340579702249091680614010546399687179863049582625671630876108790555962058243905551470611736992489702159306356102118074450673803009393106039180751255185874156459283395261688861
# help polynomial
var('y')
f = 45406770103725904509890104231914678754265961643298482440409237765195072368733672685631587979562241346*y**4 + 42764372489624602989152383173709795403796386376344802703066528962696589468564501897000324538498812883*y**3 + 37672731284607729155480237866218406485893919987814572486490754064498223292180995037432012350216544417*y**2 + 55462425449896168600390367564436787134741290054741525865807795492693442375757671549228298754153509613*y + 6778690755895128168751737959454411972187106669733266559106651743590246692689398562032067795146717162848413292299573013038367117575935673619248776925892672201933424467005517162118712395701681263279585553299544107860626811206695844212433182471614373859755499052750286667585910623259340579702249091680614010546399687179863049582625671630876108790555962058243905551470611736992489702159306356102118074450673803009393106039180751255185874156459283395261688861
# derivative of f
fd = 4*45406770103725904509890104231914678754265961643298482440409237765195072368733672685631587979562241346*y**3 + 42764372489624602989152383173709795403796386376344802703066528962696589468564501897000324538498812883*3*y**2 + 37672731284607729155480237866218406485893919987814572486490754064498223292180995037432012350216544417*2*y + 55462425449896168600390367564436787134741290054741525865807795492693442375757671549228298754153509613
# First, find roots modulo p
sols = []
for i in range(p):
if Mod(pol(i),p) == 0:
sols.append(i)
derivs = [fd(y=s) for s in sols]
sols_old = sols
for n in range(k-1):
sols = []
for s_old,d in zip(sols_old, derivs):
sols.append(int(Mod(s_old-int(f(y=s_old))*int(Mod(d,p**(n+2))**(-1)), p**(n+2))))
sols_old = sols
print("The bytes for all roots:")
[print(i, int.to_bytes(s, 500, 'big').lstrip(b"\x00"), end="\n\n") for i,s in enumerate(sols)]
Save it, then run it
┌──(bl4ck4non㉿bl4ck4non)-[~/Downloads/CTF/cyberstarter_ctf/crypto]
└─$ python abeg.py
Traceback (most recent call last):
File "/home/bl4ck4non/Downloads/CTF/cyberstarter_ctf/crypto/abeg.py", line 1, in <module>
from sage.all import *
ModuleNotFoundError: No module named 'sage'
As you can see we got a ModuleNotFoundError which says No module named sage. Well, installing sage from my end was a drag. I went on to do a little research and I found this webpage
I definitely can run my script here without any No module named sage error.
Pasting our script to the web browser and running it
cool, we got our flag💆
FLAG:- DoHCTF{univariate_polynomial_ring_go_brrr}
Osint
Rogue (151 points)
So task is to look for a guy whose name is Mustapha
.
What information were we provided with?
- Third Name which is
Mustapha
- A phone number
+2348109439442
I tried lots of stuffs, downloaded lots of osint tools and still didn’t get anywhere😞. Not until I thought of PalmPay😂, and this is because PalmPay do use the phone number of their clients as their account numbers. In this case the account number will be 8109439442
. Lets try sending money to this account number, if we are lucky we’ll see his full name there.
Well Well Well, We found a name Adebayo Ekeh
, if you recall they provided us with a third name Mustapha
. Now, lets go over to LinkedIn to look for our rogue hacker.
fullname: Adebayo Mustapha Ekeh
cool we found our rogue hacker😎. Lets decode the base64 code
command:echo RG9IQ1RGe3RoYXRfd2FzX2Vhc3lfcmlnaHQ/X3JpZ2h0P30K | base64 --d
We found our flag
FLAG:- DoHCTF{that_was_easy_right?_right?}
BlockChain
Ask The Block (96 points)
I really don’t know much about Web3, so I used chatgpt for this chall. When I asked chatgpt what Goerli means and how I can identify the blocks, I got this response
Here are the steps you can follow:
- Go to a blockchain explorer website such as Etherscan or Blockchair.
- Search for the Goerli testnet.
- Look for the block explorer or block search function.
- Enter the block number that you want to check.
- Look for the list of transactions in that block.
- Check if there is at least one transaction with a non-zero value.
Doing further research I found this site.
change the show rows
to 100
, this made the search faster. Also, we’ll be starting from the last transactions
when the Txn
has the value 1
we are going to take note of that block. If you recall the task description was to get First block on Goerli with non-zero transaction.
After lots of clicking, I eventually found one
cool, we got our flag already😎
FLAG:- DoHCTF{5644}