➜ ~

Playing Hacks and Stuffs!


Project maintained by h4ckyou Hosted on GitHub Pages — Theme by mattgraham

CyberStarters CTF '23 Qualification

Here are the challenges I was able to solve in the ctf which lasted from 28th April 2023 - 30th April 2023

P.S:- The scoreboard was dynamic

Challenges Solved

image

Sanity Check

Steg

Osint

Cryptography

Web

Blockchain

Sanity Check

Discord

image

After joining their discord channel I got this image

We can tell its base64 so i scripted it in python in order to decoded it

Here’s my script

Running it gives the flag image

Flag: DoHCTF{try_to_be_hacktive_on_discord_hehehehehehe}

DoHCTF{_colwSPs:(}

image

Looking at it we can tell its the flag already :D

Flag: DoHCTF{_colwSPs:(}

Twitter

image

After clicking on the link it redirects me to their twitter page

image

So i just clicked follow and then back on the ctf I inputted Yes

Flag: Yes

Steg

0K

image

We’re given a text file to download: image

Looking at it we can tell that there’s lot of space in the file

Also using xxd we can verify that image

Based on this we can tell its SnowSteg that’s used

Using stegsnow I got the values of those white spaces decoded image

Flag: DoHCTF{another_quite_simple_one}

OSINT

Rogue Agent

image

This was quite a very fun one i would say (i’m not really an osint person)

We are given this number +2348109439442 and a third name Mustapha

The task is to find his real linkedln account

This was nearly almost impossible cause there wasn’t any avaialble open source tool on the internet that gets a linkedln user account based on phone number

And attempting to search it manually was futile

Then after a while i remembered that a phone number was given! So the question is what can I do with it 🤔

If you use palmpay/opay well you should know that when a number is provided, It will bring out the person full names

So its worth a shot 💀

After trying it on palmpay i attempted to make cash transfer to the person then i saw his name 🤤 WhatsApp Image 2023-05-01 at 2 22 41 PM

Which was Adebayo Mustapha Ekeh !!

Searching it on linkedln gave this image

We can see the encoded text in the profile description

So I scripted a program to decoded it script

Running it gives the flag image

Cryptography

di_sease

image

We’re given an image file and here’s it metadata image

Checking it shows various flag in it image

At first I didn’t know what it is. So I checked Dcodefr for various image ciphers

And while looking through it I saw something similar to the image given image

Navy Signal Code looks promising xD

After using it and selecting the various flags from the image it decryped to this image

Flag: DoHCTF{The_flags_revealed_009}

Hensel’s Mystery

image

We’re given a python file (ring.py) and its output (output.txt)

First we get the parameters from ring.py and the polynomial from output.txt. With sagemath imported we can do the following.

from sage.all import *

# from ring.py
p = 35671
k = 100
N = p**k

# the polynomial from output.txt and its derivative
var('x')
with open('output.txt') as file:
    f = eval(file.read().replace('^', '**'))
df = f.derivative()

As can be seen from ring.py, the flag is a root of the polynomial:

assert poly(flag) == 0

However, calculating the roots of this polynomial in Z/NZ is too hard, so we cannot do that. After lots of Googling, I found the Hensel’s lifting lemma, which can be used to ‘lift’ the roots that were calculated in Z/pZ to Z/p^kZ = Z/NZ.

Calculating the roots in Z/pZ is easy and can even be bruteforced since p is small, lets calculate the roots as follows.

roots = []
for i in range(p):
    if Mod(f(x = i), p) == 0:
        roots.append(i)

There should be maximum of 4 roots now.

Now let’s implement the Hensel’s lifting lemma, and let’s lift the roots to k=100.

# https://www.geeksforgeeks.org/hensels-lemma/
# a_{k+1} = a_k-f(a_k)*f'(a_1)^(-1) mod p^{k+1}

# f'(a_1) for all roots
derivs = [df(x = r) for r in roots]

roots_old = roots
for n in range(1, k):
    roots = []
    for r_old,deriv in zip(roots_old, derivs):
        # f'(a_1)^(-1) mod p^{k+1}
        dinv = int(Mod(deriv,p**(n+1))**(-1))
        roots.append(int(Mod(r_old-int(f(x = r_old))*dinv, p**(n+1)))
    roots_old = roots

Now we should have the lifted roots, and the flag is one of them.

import string
for root in roots:
    flag = int.to_bytes(root, 500, 'big').lstrip(b"\x00")
    if set(flag).issubset(string.printable.encode()):
        print(flag)

Here’s the flag

Flag: DoHCTF{univariate_polynomial_ring_go_brrr}

I also made a solve script for it

Runing it on sagecell sagemath also gives the flag image

Web

None Shall Pass

image

We’re given the web server to connect to

After navigating to it on my web browser i see this image

Next thing is checking the source code but nothing really is interesting there image

So I refreshed the page again but this time intercepted the request in burp suite image

We can see a jwt token is in the request

Using jwt.io I decoded it to form image

This is the header:

{
  "alg": "HS256",
  "typ": "JWT"
}

The payload:

{
  "username": "guest"
}

We don’t currently know the signature

In cases like this I’d try brute forcing the signature key but it doesn’t work image

No we know that the algorithm used for signing the key is HS256 how about we set it to None 🤔

That’s a method to be tried for exploiting jwts

I made a script to create a new token and call the web server index page

Here’s the solve script

Running it gives the flag image

Flag: DoHCTF{jwt_has_a_none_algo_loll}

^_^

image

This challenge was really fun and easy but it took me a while to figure it out

First after navigating to the web server it shows this image

The text there are just Lorem Ipsum things

Checking the source code shows it has 3 web paths we can access image

And there are :

1. Index:- / which redirects to /GgoXAQ4QGxMCHA4ZA1JKDFlWAEFRG1YQGw/c2RzZHZ5dXdnZGd3ZzcyZTcyZTk4dTJ1Yw
2. Letter:- /HwEBBw0WGQ0HAQEaVBYcEAwHHw0QHRAaHxAdEAEQ/c2R1c2hkdWhzdWRoOHNoZGl1c2hkaXVoc3VpZGRi
3. About:- /ISdFLDRLKitfPDRKRT0SCRcHEBIIFwsTEg/QEUqWUAqSEQqSFUoKkhmaHVoZWZpdWRmZg

What you will notice is that this are not in its plain text

And there’s a hint that said No BruteForce hmmmmm 🤔

From this we have no option but to work with this

At first I didn’t really know what to do but i know that its base64 encoded

After a while of looking at it and noticing the challenge name I got this:

^_^ ---> the ^ 

What ^ means is a bitwise operation mathematically and xor in the programming aspect

So I then decided to base64 decode the directory and the subdirectory for each path then xor them together

Path: /GgoXAQ4QGxMCHA4ZA1JKDFlWAEFRG1YQGw/c2RzZHZ5dXdnZGd3ZzcyZTcyZTk4dTJ1Yw
Directory: /GgoXAQ4QGxMCHA4ZA1JKDFlWAEFRG1YQGw
SubDirectory: c2RzZHZ5dXdnZGd3ZzcyZTcyZTk4dTJ1Yw

Using python I acheived that and was able to decode it

But before that I was getting incorrect padding image

So adding == made it look more base64ish 😹 image

We get its xored value as indexindexindexindexindex and remember that path is for the Index page 🤔

Doing the same for other paths gives its decoded form image

Now this is getting interesting ⁉️

We can now conclude that the path are formed by xoring it with a key then base64 encoding its xored value

But what is that key 🤔

A property of xor is that it’s commutative i.e

A ⊕ B = B ⊕ A 

So that means:

A ⊕ B = C
A = B ⊕ C
B = A ⊕ C

We can get the key for each part now and we know that they will each be A || B

But here’s the problem:

1. Each path has it own key 

So if we’re to encode the value of the flag’s path (in this case i can guess flagflagflagflagflag) we won’t know the key

At this point i was stucked cause each of the directory and subdirectory has different values when base64 decoded

That means that they are likely formed from encoding:

flagflag with flagflagflag
flag with flagflagflagflag

Well basically i just assumed that it is formed from arranging 5 (flagflagflagflagflag) in 2 different places

And if we do the math it’s:

5 permutation 2:- 5P2 = 20 (so 20 different ways of arranging it)

Well that’s what I was thinking for some while 😭

Until after I then taught that hmmmm how about using the just the encoded form of flag*5 🤔 as a directory

But now here’s the problem 🙁

- Noticing the way the web server stores it paths it uses a directory and subdirectory

Then I taught again for a while on how to go about this path 😂

So I just said what if the subdirectory is just basically a null value so when we try access it the web server justs takes it as a non type value

Here’s the way I encoded it image

P.S: When you xor a value of the same kind it returns zero

Now we know that xoring 0 with 0 = 0000

But here’s another thing to notice from the web server

Each directory and subdirectory has the same length image

So that means our xored value should be equal to the lenth of the base64 encoded form of flag*5

Currently its length is just 4, while that of the encoded form of the flag is 28 image

Doing the basic math:

28 / 4 = 7 (so we need to multiply len(encoded(xored)) by 7

After doing that on my terminal I get this image

Now we can join the two string together seperated by a slash / image

Now trying to access it from the web server gives the flag image

Flag: DoHCTF{xor_rox_xor}

I made a solve script for it also

Running it also works image

Blockchain

Ask The Block

image

From the challenge description we’re asked to find the:

First block on Goerli with non-zero transaction

Since this is my first blockchain type of challenge I had to know what Goerli means


Goerli is a proof-of-authority (PoA) test network for Ethereum that was launched in 2019.
It is designed to provide a stable, secure, and reliable testing environment for Ethereum developers and users, 
allowing them to test their smart contracts and decentralized applications (DApps) without incurring the high costs associated with deploying on the Ethereum mainnet.

Goerli is named after a small town in Germany and is one of several test networks available for Ethereum development.
Unlike other test networks, such as Rinkeby or Ropsten, which use proof-of-work (PoW) or proof-of-stake (PoS) consensus algorithms, respectively, Goerli uses a PoA consensus algorithm.

In a PoA network, a group of trusted validators are responsible for validating transactions and adding new blocks to the blockchain.
This approach is less resource-intensive than PoW or PoS, making it ideal for test networks where transaction volumes are lower and security requirements are less stringent.

Goerli is fully compatible with the Ethereum mainnet, and developers can easily switch between Goerli and the mainnet to test and deploy their applications.

                                                                                                                         Source: ChatGPT

So basically its just A cross-client proof-of-authority testing network for Ethereum.

And they said we should get the first block with a non zero transaction (txn)

Searching for goerli shows this image

Clicking on it (the first link) shows this image

But since we need to know like the transaction history we need a block explorer and analytics platform and the one I got was Etherscan

Clicking on Goerli Blockchain on the Goerli domain gives this image

But we need the block so after looking around the site I saw this image

Now since we want the first non-zero block transaction it’s best to start from the bottom and luckily it can be done by clicking the Last button image

Doing that loads back to the last page image

From there we can see that most transaction values are just zero

After moving up and up and up and up 😂 I finally got a value that’s not zero image

So the flag is:

Flag: DoHCTF{5644}

Blockr

image

Another fun challenge I’d say 🙂

We’re given a zip file and after unzipping it, it contains two files abi, blockr.sol image

First from checking the content of blockr.sol it shows this image

pragma solidity ^0.8.0;

contract ABC {
    function DEF(string GHI) external view returns (string memory) {
        bytes32 JKL = blockhash(block.number - 5);
        require(GHI == JKL, ":D");
        return ""; // Flag//
    }
}

Here’s what this program does:

- It's a solidity program
- It creates a contract ABC which has a function called DEF
- The function takes in a parameter string GHI and also its set to it to be view only and the function is to return a value from memory (later called at the end of the code)
- It then sets a variable JKL which data type is bytes32 and it's set to be the value of the blockhash of the blocknumber before 5 (5 blocks before the blocknumber)
- A check is done to compare the value of the parameter called from the DEF function with the value of GHI 
- If its meet it returns the flag

Also here’s the abi image

[
    {
        "inputs": [
            {
                "internalType": "bytes32",
                "name": "GHI",
                "type": "bytes32"
            }
        ],
        "name": "DEF",
        "outputs": [
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    }
]

For this challenge I actually was trying something before I got an easier and likely unintended way

Likely Unintended

We are not given the test network the block chain is connected to so we are going to have to guess it 🤔

After some while I searched various networks and got it to be Sepolia Testnet Explorer image

Searching for the contract address 0xe4C9Dcc9ea468C9BaB4C7B2fe4bc3b9b97796055 shows this image

Now checking the contract shows this image

We can click on decompile code to get its decoded form image

Clicking on Decompile Bytecode gives this image

We can see the flag there 🤓

Flag: DoHCTF{interact_w_contract}
Intended

The intended way is going to be that we program it in solidity or python (basically any language that can be used to interact with smart contracts) and then call the DEF function passing the right value as parameter

We can achieve this using python (Thanks to one of the organisers @Lytes for verifying and correcting the mistake I made initially)

Here’s my solve script for it

#!/usr/bin/python3
# Author: Hack.You

from web3 import Web3

RPC = 'https://eth.getblock.io/[YOUR_API_KEY]/sepolia/' # https://account.getblock.io/ 

web3 = Web3(Web3.HTTPProvider(RPC))
print(f'Connected: {web3.is_connected()}')

address = web3.to_checksum_address("0xe4C9Dcc9ea468C9BaB4C7B2fe4bc3b9b97796055")
abi = [
    {
        "inputs": [
            {
                "internalType": "bytes32",
                "name": "GHI",
                "type": "bytes32"
            }
        ],
        "name": "DEF",
        "outputs": [
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    }
]
contract = web3.eth.contract(address=address, abi=abi)

blocknumber = web3.eth.block_number
blockhash = web3.eth.get_block(blocknumber - 5).hash

result = contract.functions.DEF(blockhash).call()
print(result)

Running it works :D image

Flag: DoHCTF{interact_w_contract}

Conclusion

- Learnt new lots of thing (blockchain, crypto, new type of vulnerability)
- Improved my reasoning skills 
- Had fun while partaking in the CTF

Till the final xD

And that’s all for today 👻



If by chance I made any mistake you can DM me here @Discord Hack.You#9120

Arigato