Table of Contents
Hello ctfian's! I played JerseyCTF 2023 which was happened from 15 Apr to 16 Apr. I played it with the team Invaders0x1. This time I scored 2600+ points. And our Team secured 125th place in CTF.
This time I solved 6 challs in crypto which is my fav category.
Crypto Challs
missing employee-1
TGltYSBBbHBoYSBLaWxvIEVjaG8gTWlrZSBJbmRpYSBDaGFybGllIEhvdGVsIEluZGlhIEdvbGYgQWxwaGEgTm92ZW1iZXI=
Decoded this text from base64
mj0ln1r@Linux:~JerseyCTF/crypto/missing_employe_done$ echo "TGltYSBBbHBoYSBLaWxvIEVjaG8gTWlrZSBJbmRpYSBDaGFybGllIEhvdGVsIEluZGlhIEdvbGYgQWxwaGEgTm92ZW1iZXI=" | base64 -d
Lima Alpha Kilo Echo Mike India Charlie Hotel India Golf Alpha November
Submitted this in flag format, but it doesn't worked for me. The did a quick google search these words. And i found that these are the NATO phonetic alphabets. And decoded it by following the representations of this words.
Lima - l
Alpha - a
Kilo - k
Echo - e
and so on.
Flag: jctf{lake-michigan}
jack-and-jill
Ciphertext is given : pgQVJFCohpccuyBSbwxcxpVZCAATRT
. A 2x2 matrix is given [[3,9],[4,7]].
By observing the description i found that this is a hill cipher
. I quickly searched for the hill cipher decoder online. I used this site to decipher the text.
The deciphered text is hiTHEREwelcomeTOlinearALGEBRAZ
Flag : jctf{hiTHEREwelcomeTOlinearALGEBRAZ}
space-dust
The challenge have this attachment message_from_tom.txt
First of all, I observed a ==
at the end of the content of the file. Immediated I decoded it from base64 and stored in other file. And the file size is a bit suspicious so I observed its hexdump. It contains a PNG header. So, I renamed the image image into decoded.png. Then i opened the image it has the flag in it.
mj0ln1r@Linux:~/space-dust$ cat message_from_tom.txt | base64 -d >> decoded
mj0ln1r@Linux:~/space-dust$
mj0ln1r@Linux:~/space-dust$ xxd decode | head
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
00000010: 0000 0a00 0000 05a0 0806 0000 0092 001a ................
00000020: df00 0000 0173 5247 4200 aece 1ce9 0000 .....sRGB.......
00000030: 0004 6741 4d41 0000 b18f 0bfc 6105 0000 ..gAMA......a...
00000040: 0009 7048 5973 0000 0ec3 0000 0ec3 01c7 ..pHYs..........
00000050: 6fa8 6400 00ff a549 4441 5478 5ee4 fd67 o.d....IDATx^..g
00000060: 776c 3b92 a609 1a35 e9d4 fae8 2b43 6556 wl;....5....+CeV
00000070: 5677 4fcf 879e 5933 ffad fe5d d7a8 55d5 VwO...Y3...]..U.
00000080: 5599 1915 1157 9c7b 34b5 763a f5bc cf6b U....W.{4.v:...k
mj0ln1r@Linux:~/space-dust$ mv decoded decoded.png
The decoded image is decoded.png .
Flag : jctf{th1s_1s_n0t_a_game}
roko-cipher-in-the-console
We can see this is a transpositional cipher. f1stg}th10_ej{s__act_nam
. I observed that the flag is plaintext but it was transposed. We can observe that the jctf{}
letters in the ciphertext.
I wrote this ciphertext in different deapths. Like writing it in 4 columns, 5 columns and so on . I observed a standard format when I write this in 6 columns.
We can get the flag by reading column by column and in every column the order of reading letters is row-3,row-4,row-2,row-1.
That is first column should be taken as jctf
. Second column is {th1
and so on.
Flag : jctf{th1s_1s_n0t_a_game}
supply-stash
This is medium level challenge in crypto. The challenge has a java file name numericalEncoder.java
//Encoding program originally by Logan DesRochers
import java.lang.Math;
import java.util.ArrayList;
import java.util.Scanner;
public class numericalEncoder{
public static void main(String[] args){
String alphabet = "abcdefghijklmnopqrstuvwxyz";
Scanner sc = new Scanner(System.in);
System.out.println("Enter string to be encoded: ");
String m = sc.nextLine();
m = m.toLowerCase();
System.out.println("Enter int block size: ");
int r = sc.nextInt();
//padding to variable block size
if(m.length() % r != 0){
while(m.length() % r != 0){
m = m + "x";
}
}
System.out.println("M after padding: " + m);
//Variable block size
ArrayList<Integer> encodedBlocks = new ArrayList<Integer>();
int numBlocks = m.length() / r;
for(int i = 0; i < numBlocks; i++){
String block = m.substring(i * r, r + i * r);
System.out.println(block);
int power = block.length() - 1;
int representation = 0;
for(int j = 0; j < block.length(); j ++){
String currentLetter = block.substring(j,j+1);
int letterValue = alphabet.indexOf(currentLetter);
representation += letterValue * Math.pow(26, power);
power--;
}
encodedBlocks.add(representation);
}
System.out.println("Encoded blocks are as follows: ");
for(int num : encodedBlocks){
System.out.println(num);
}
}
}
The output of the above code is SUPPLIES: 6639182 5837362 7923517 8463981 3588695 8358510"
and this is the encoded vesion of our flag. So analyzed the code and reversed the encoding program.
My observations are, the above code is doing generating a integer for for a block of characters. That is 6639182
is on encoded version of a block of characters. This is generated by accessing the index of the character from alphabet string and this is multiplied pow(26,power)
where power=len(block)-1
and this power is decreased for every new character in the block.
Okay, lets have some math. lets assume block size = 4
power = 3
the initial encoded block value will become
index(char)x26^3 + index(char)x26^2 + index(char)x26^1 + index(char)x26^0
Simply it is doing a base26
operation. So, in the decode program, we have to perform decoding of base26.
This is the solution script which can give the decoded message from encoded blocks.
import string
alphabet = string.ascii_lowercase
input_str = input("Enter numerical blocks to be decoded (separated by spaces): ")
# split input into individual numerical blocks
input_blocks = input_str.split(" ")
decoded_blocks = []
for block in input_blocks:
num = int(block)
decoded = ""
while num > 0:
remainder = num % 26
decoded_letter = alphabet[remainder]
decoded = decoded_letter + decoded
num //= 26
decoded_blocks.append(decoded)
# combine decoded blocks into original message
decoded_message = "".join(decoded_blocks)
print("Decoded message: " + decoded_message)
#6639182 5837362 7923517 8463981 3588695 8358510
# onthemuddyriversnorthwestshore
# jctf{onthemuddyriversnorthwestshore}
Flag : jctf{onthemuddyriversnorthwestshore}
play-reasonably
This one is a special challenge. I spent more than an hour to solve this. And at the end of the ctf play-reasonably has only 11 solves.
Okay coming to challenge, I searched many keywords online but I havent find any thing positive. By observing carefully the ciphertext looks like it is from an old cipher. And I know about play-fair cipher. And they said play-reasonably and it matched with it. So, i started deciphering this playfair ciphertext.
Ciphertext : WTATRHABWKYKACBMWD
I tried it with the key THEBOYSAREBACKINTOWN
as the description highlighted it. I solved it with pen and paper as i know the working of playfair. Tried evry possible 5x5 key matrix.
THEBOYSARCKINWDFGLMPQUVXZ (-J)
THEBOYSARCKINWDFGJLMPQUXZ (-V)
THEBOYSARCKINWDFGJLMPUVXZ (-Q)
THEBOYSARCKINWDFGJLMPQUVX (-Z)
None of them are worked. So, I read the description again, They said theboysarebackintown
are playing in reverse.
So, I tried the key matrix in reverse order.
NWOTIKCABERSYH
And the key matrix will be NWOTIKCABERSYHDFGLMPQUVXZ (-J)
And I got the plaintext : NOBODYCANCRACKTHIS
Here is my paper work might help you out.
You can use this site to decrypt or learn more about playfair ciper here.
Flag : jctf{NOBODYCANCRACKTHIS}
Web - Look-Im-Hacking
A simple web challenge. The challenge url has the login page. I looked at the source code of it. And found this script.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="text/html">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript">
var passkey = '';
function createPass() {
const valids = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$#@!&%"
for (let i = 0; i < 20; i++) {
passkey += valids.charAt(Math.floor(Math.random() * valids.length))
}
passkey = btoa(passkey);
}
function checkPass() {
console.log(passkey)
if (document.getElementById("un1").value == "admin" && document.getElementById("pw2").value == atob(passkey)) {
loadFlag();
}
}
function loadFlag() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function () {
document.getElementById("reveal").innerHTML = this.responseText;
}
xhttp.open("GET", "./flag.txt")
xhttp.send();
}
</script>
</head>
Found that there is a /flag.txt
end point. And simply curling it results the flag.
mj0ln1r@Linux:~/web$ curl https://www.jerseyctf.online/flag.txt
$Hacker&?r3@L$
Flag : jctf{$Hacker&?r3@L$}
Forensics - unknown-origin
The challenge have this attached Photo.jpg.
Simple strings does the job.
mj0ln1r@Linux:~/forensics$ strings Photo.jpg | grep jctf
jctf{0gre$_h@ve_l@yers}
Flag : jctf{0gre$_h@ve_l@yers}
Forensics - firefox-history
Attached file : places.sqlite
So, i quickly searched for sqlite viewer online (I dont want to install additionally :) )
Found this site to view sqlite file.
As the file name hints places. So selected moz_places
table to view.
As the description said, i looked for the jerseyctf.com entry in the table. It was on 137th row.
I copied the last time visited value of the 137th entry. As the flag format is jctf{YYYY-MM-DD-HH-MM-SS}
of this time, I used a seconds to epoch converter to get this format.
1674907264007000
to epoch on this site
And the correct format is the date in GMT that is 2023-01-28-12-01-04
Flag : jctf{2023-01-28-12-01-04}
bin - plain
The challenge has bin executable named plain
strings done the job for us again.
mj0ln1r@Linux:~/forensics$ strings plain | grep jctf
jctf{i_<3_5tr1Ng5_59af0c0ed}
Flag : jctf{i_<3_5tr1Ng5_59af0c0ed}
OSINT - record-me
The challenge is highlighting record
and jerseyctf.com
. So, I search for all the DNS records of jerseyctf.com.
I search all the whois
records of the jerseyctf.com. And in there a string pw-d714d7aa25df63925ec2b3893928671b
. As they are talking about password pw
tempts me to submit it as flag.
But afer many unsuccesful tries I tried dig
to fetch DNS records
of jerseyctf.com.
And finally the flag is available at TXT records
of jerseyctf.com. I used dig
to do it.
mj0ln1r@Linux:~/osint$ dig jerseyctf.com txt
; <<>> DiG 9.18.12-0ubuntu0.22.04.1-Ubuntu <<>> jerseyctf.com txt
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48664
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;jerseyctf.com. IN TXT
;; ANSWER SECTION:
jerseyctf.com. 3600 IN TXT "jctf{hop_OFF_TIKTOK_and_GET_s0me_SUN_OUTSID3!}"
;; Query time: 732 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Apr 21 12:14:36 IST 2023
;; MSG SIZE rcvd: 101
Flag : jctf{hop_OFF_TIKTOK_and_GET_s0me_SUN_OUTSID3!}
OSINT - geo-guess
So, its clear that we have to find the name of the building given in the picture.
I did a quick google image search and found the building name right on the top of result.
Flag: jctf{west-edmonton-mall}
Misc - pits-of-tartarus
The attached file : file834.tar.gz
This tar is a hundrends of recompressions of tar.gz
So, I run this command to loop over all the compressions in it and extract the files.
mj0ln1r@Linux:~/misc$ for i in {834..1}; do tar -xf file$i.tar.gz; rm file$i.tar.gz; done
mj0ln1r@Linux:~/misc$ ls
file0.tar.gz
The above command will extract the zips and deletes it prior zip to make directory clean. As we can see now file0.tar.gz
is the last one left.
Again this file0.tar.gz
contains zips from file-1.tar.gz, and so on. So i extracted file0.tar.gz just one time then modified above command lil bit to extract this sequece of tars.
mj0ln1r@Linux:~/misc$ tar -xf file0.tar.gz
mj0ln1r@Linux:~/misc$ ls
file-1.tar.gz
mj0ln1r@Linux:~/misc$ for i in {1..833}; do tar -xf file-$i.tar.gz; rm file-$i.tar.gz; done
tar: file-390.tar.gz: Cannot open: No such file or directory
tar: Error is not recoverable: exiting now
mj0ln1r@Linux:~/misc$ ls
file.txt
mj0ln1r@Linux:~/misc$ cat file.txt
jctf{N0t_$tuck_in_tHe_t@r}
I assumed that there will be again 834 zips so I tried the above loop. But actually there were only 389
tars. Eventhough the above command extracted the file that we want but returned some error. The flag is present in file.txt
Flag : jctf{N0t_$tuck_in_tHe_t@r}
Misc - crack-keepass
Attached file : Databse.kdbx
This time I installed keepassx
on my machine.
mj0ln1r@Linux:~/misc$ sudo apt install keepassx
And I Opened the Database.kdbx with kepassx GUI app. It prompts me for a master password. As the challenge hints that crack, I cracked it with JOHN
and rockyou.txt
.
mj0ln1r@Linux:~/misc$ keepass2john Database.kdbx >> database_hashes_new.hash
mj0ln1r@Linux:~/misc$ john --wordlist=/usr/share/wordlists/rockyou.txt -format:keepass databse_hashes_new.hash
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64])
Cost 1 (iteration count) is 60000 for all loaded hashes
Cost 2 (version) is 2 for all loaded hashes
Cost 3 (algorithm [0=AES, 1=TwoFish, 2=ChaCha]) is 0 for all loaded hashes
Press 'q' or Ctrl-C to abort, almost any other key for status
1jersey (?)
1g 0:01:57:04 DONE (2023-04-16 16:24) 0.000142g/s 53.41p/s 53.41c/s 53.41C/s 1jersey
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Master key of the database is 1jersey
.
So, I opened it the database file with master key. When I am navigating through the database file in keepassx app. I found a file named flag
in General category.
Flag : jctf{pr073c7_y0ur_v4ul7}