Playing Hacks and Stuffs!
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
After joining their discord channel I got this
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
Flag: DoHCTF{try_to_be_hacktive_on_discord_hehehehehehe}
Looking at it we can tell its the flag already :D
Flag: DoHCTF{_colwSPs:(}
After clicking on the link it redirects me to their twitter page
So i just clicked follow and then back on the ctf I inputted Yes
Flag: Yes
We’re given a text file to download:
Looking at it we can tell that there’s lot of space in the file
Also using xxd
we can verify that
Based on this we can tell its SnowSteg that’s used
Using stegsnow
I got the values of those white spaces decoded
Flag: DoHCTF{another_quite_simple_one}
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 🤤
Which was Adebayo Mustapha Ekeh
!!
Searching it on linkedln gave this
We can see the encoded text in the profile description
So I scripted a program to decoded it script
Running it gives the flag
We’re given an image file and here’s it metadata
Checking it shows various flag in it
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
Navy Signal Code looks promising xD
After using it and selecting the various flags from the image it decryped to this
Flag: DoHCTF{The_flags_revealed_009}
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
We’re given the web server to connect to
After navigating to it on my web browser i see this
Next thing is checking the source code but nothing really is interesting there
So I refreshed the page again but this time intercepted the request in burp suite
We can see a jwt token is in the request
Using jwt.io I decoded it to form
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
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
Flag: DoHCTF{jwt_has_a_none_algo_loll}
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
The text there are just Lorem Ipsum
things
Checking the source code shows it has 3 web paths we can access
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
So adding ==
made it look more base64ish 😹
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
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
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
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
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
Now we can join the two string together seperated by a slash /
Now trying to access it from the web server gives the flag
Flag: DoHCTF{xor_rox_xor}
I made a solve script for it also
Running it also works
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
Clicking on it (the first link) shows this
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
But we need the block so after looking around the site I saw this
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
Doing that loads back to the last page
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
So the flag is:
Flag: DoHCTF{5644}
Another fun challenge I’d say 🙂
We’re given a zip file and after unzipping it, it contains two files abi, blockr.sol
First from checking the content of blockr.sol it shows this
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
[
{
"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
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
Searching for the contract address 0xe4C9Dcc9ea468C9BaB4C7B2fe4bc3b9b97796055 shows this
Now checking the contract shows this
We can click on decompile code to get its decoded form
Clicking on Decompile Bytecode gives this
We can see the flag there 🤓
Flag: DoHCTF{interact_w_contract}
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
Flag: DoHCTF{interact_w_contract}
- 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