HacktivityCon 2021
crypto
Hexahedron
Solved by: Taz34
- We are give values of n,e and c.
-
Decode them into simple numeric form using python.
- it looks like RSA, we used RsaCtfTool to decipher it.
: https://github.com/Ganapati/RsaCtfTool
python3 RsaCtfTool.py -n 112339816301925396926211289689793745814213925314273886071305785874178028552510482239036537066616690493241410015435402110525284201411608164205573122430898583517515498250410244592963132324072861567753086739636553410154316180827724708002409356129254383468446158145079982391991062389788544378839486986385137994309 -e 3 --uncipher 2217344750798178599616518881851238192046537371134831984828894413752520937378161486880269974456574131502921272953104454680926482208357166098075344508240480152890914678813031666242202555794691235412837030045499161787224264164243336308650477343133919653356349913604131486721125
here we have the flag.
N1TP
Solved By : choco
We are given an encrypted flag with randomized key. The hint is that this uses a one time pad encryption
The general gist of one pad encryption: You have a plain text: P = “HELLO” (8 5 12 12 15) We are given a key: K = “DREFX” (4 18 5 6 24)
The encryption comes in when we add both P and K to get encryption C = “L W Q R M” (12 23 17 18 13(39%26))
So P + K = (C%N) where N is the letter range To get the decipher text we simple subtract C with K P = “HELLO” (8 5 12 12 15(11%26)
So (P%N) = C - K
The vulnerability comes in if the same key K is used to encrypt another plain text provided we know the range of text used along with the length
Suppose P1 = “AAAAA” (1 1 1 1 1) P1 + K = C1 C1 = “ETFGY” (5 19 6 7 25)
We could easily get the key if it is within the modulus range C1 - P1 = K K = “DREFX” (4 18 5 6 24)
We can now use this to get P with the given C
But another way to find P is using simple logic
C1 - P1 = C - P So P = C - C1 + P1 All we need to do is find C - C1 to 0 and we can guess P
Using this logic we will find the flag The code for difference C - C1 is given below and difference is added to P1 and manually repeated until we get C - C1 as 0
import binascii
A = "dc0de91facbe90ee6f652167906ee0d17123cf9e746a63db4b4e7d93040f59331ead9be0b2fe"
Ahex = binascii.unhexlify(A)
B = "dc0de91facbe90ee6f652167906ee0d17123cf9e746a63db4b4e7d93040f59331ead9be0b2fe"
Al = list(bytearray(Ahex))
Bl = list(bytearray(binascii.unhexlify(B)))
C = "flag{00000000000000000000000000000000}"
Chex = list(bytearray(C))
print(Chex)
d = []
for i in range(len(Al)):
d.append(Al[i] - Bl[i])
print(d)
k = []
c = []
for i in range(len(Al)):
k.append(Chex[i] + d[i])
if((48 <= k[i] <= 57) or (97 <= k[i] <= 102) or k[i] == 108 or k[i]==103 or k[i]==123 or k[i]==125):
c.append(chr(k[i]))
else:
c.append("#")
print(k)
print(c)
flag: flag{9276cdb76a3dd6b1f523209cd9c0a11b}
TRIFORCE
Solved By : choco
This is a CBC AES encryption (Chained Block Cipher)
Suppose the plain text P is 64 bits long It is then split into 4 parts (16 bit each)
There is an initializer iv that is 16 bits long and key k (16 bits long) The cipher text for first part of P is
C0 = E(P0 ^ iv,k) and following chain goes like this Ci = E(Pi ^ Ci-1,k) i > 0
The decryption does like this
Where P0 = D(C0,k) ^ iv and following decryption goes Pi = D(Ci,k) ^ Ci-1
If the key k and vi are same, a vulnerability arises During decryption, P0 = D(C0,k) ^ k P1 = D(C1,k) ^ C0 P2 = D(C2,k) ^ C1
if we replace C2 with C0 P2 = D(C0,k) ^ C1
xor the result with any of the two inputs will give the other input D(C0,k) = P2 ^ C1 P0 = D(C0,k) ^ k k = D(C0,k) ^ P0 therefore, k = P2 ^ C1 ^ P0 so since we know P0,P2 and C1, we can easily find k
Hence all we need to do is to replace the 3rd block of ciphertext with the first block of cipher text, Xor the result of 3rd plain text block with 2nd cipher text block and xor that result with 1st plaintext block to get the key
Do this three times with the different keys above to get the flag
input: 616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161
Code for replacing ciphertext:
def listToString(s):
str1 = ""
for ele in s:
str1 += ele
return str1
def chunk(in_string,num_chunks):
chunk_size = len(in_string)//num_chunks
if len(in_string) % num_chunks: chunk_size += 1
iterator = iter(in_string)
for _ in range(num_chunks):
accumulator = list()
for _ in range(chunk_size):
try: accumulator.append(next(iterator))
except StopIteration: break
yield ''.join(accumulator)
string = "e5cc7f05f279ca152d3fbd32d899b55fec8de5d9ae3d62bac51195ddedc0863462021d3c51a4a56555ca95ff4303b764a02a2f44327cb2007d46de117900720a"
l = list(chunk(string,4))
l[2] = l[0]
print(l)
out = listToString(l)
print(out)
code for getting hex for part of flag:
def chunk(in_string,num_chunks):
chunk_size = len(in_string)//num_chunks
if len(in_string) % num_chunks: chunk_size += 1
iterator = iter(in_string)
for _ in range(num_chunks):
accumulator = list()
for _ in range(chunk_size):
try: accumulator.append(next(iterator))
except StopIteration: break
yield ''.join(accumulator)
string = "6227616161616161616161616161616161616161616161616161616161616161e8c6e5dfb46432e2c2499084e899d462e6af4534aed0627d75f825c096970f36"
l = list(chunk(string,4))
c = "ec8de5d9ae3d62bac51195ddedc08634"
print(hex(int(l[2],16)))
d = int(l[2],16) ^ int(c,16)
print(hex(d))
e = d ^ int(l[0],16)
print(hex(e)) ![](https://i.imgur.com/TgyoAnU.jpg)
do this and replace each cipher for each key
each keys in hex = 666c61677b3831396639643864383337
32316163346334343262313635396633
36646632647d20202020202020202020
flag: **flag{819f9d8d83721ac4c442b1659f36df2d}**
misc
Shelle
Solved by : nigamelastic
on starting the shell u see that u can only use the 7 commands
cat
, ls
, pwd
, whoami
, ps
, id
, echo
as mentioned in the txt file present
Dear Students, here are the questions for your next assignment, please finish them..
If you don't wanna do the assignment you can simply submit the flag which is in the /opt directory, but hah that would be impawsible
1) What is Linux?
2) What is the difference between UNIX and LINUX?
3) What is BASH?
4) What is Linux Kernel?
5) What is LILO?
6) What is a swap space?
7) What is the advantage of open source?
8 ) What are the basic components of Linux?
9) Does it help for a Linux system to have multiple desktop environments installed?
10) What is the basic difference between BASH and DOS?
Also do learn about following linux commands.
> whoami - Prints the user name associated with the current effective user ID.
> pwd - Prints the name of current working directory
> ls - List information about the FILEs (the current directory by default)
> ps - Displays information about a selection of the active processes.
> id - Print user and group information for the specified USER, or (when USER omitted) for the current user.
> echo - display a line of text (sometimes useful to print emotes)
> cat - concatenate files and print on the standard output
most of the
using the research from the previous integrity challenge I tried using a hex decoding via
echo -e
however everything including``(backticks) and
/ are filtered.
luckily
$()` isn’t so i crafted the payload and got the flag:
cat $(echo -e "\x2f\x6f\x70\x74\x2f\x66\x6c\x61\x67\x2e\x74\x78\x74")
flag{82ad133488ad326eaf2120e03253e5d7}
WORD CHURCH
Solved By : choco
the whole program is about solving 30 crossword puzzles with unspecified words to find. We have to use a script to find the words and a separate script to execute and get inputs of the crossword and words then output that position to the script
The program might encounter forkbombs or slow down but it works after a while
the crossword script :
import re
from itertools import islice
def find_in_list_of_list(mylist, char):
for sub_list in mylist:
if char in sub_list:
return (mylist.index(sub_list), sub_list.index(char))
raise ValueError("'{char}' is not in list".format(char = char))
def topright(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if( (i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
i-=1
j+=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def right(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if( (i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
j+=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def bottomright(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if( (i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
j+=1
i+=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def top(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if( (i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
i-=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def bottom(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if( (i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
i+=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def topleft(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if( (i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
i-=1
j-=1
print(str(i) +" "+str(j))
else:
return "nope"
st = st + "]"
return st
def left(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if((i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
j-=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def bottomleft(chara,lis,i,j):
st = "["
for k in range(len(chara)):
if((i > 15) or (j > 15)):
return "nope"
if(chara\[k]==lis[i\][j]):
st = st + "(" + str(j)+", "+str(i) + "), "
j-=1
i+=1
print(str(i) +" "+str(j))
else:
return "nope"
st =st + "]"
return st
def find(chara,lis,i,j):
st = ""
if(chara\[1] == lis[(i-1)%15\][(j+1)%15]):
st = topright(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[i\][(j+1)%15]):
st = right(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[(i+1)%15\][(j+1)%15]):
st = bottomright(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[(i-1)%15\][j]):
st = top(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[(i+1)%15\][j]):
st = bottom(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[(i-1)%15\][(j-1)%15]):
st = topleft(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[i\][(j-1)%15]):
st = left(chara,lis,i,j)
if(st != "nope"):
return st
if(chara\[1] == lis[(i+1)%15\][(j-1)%15]):
st = bottomleft(chara,lis,i,j)
if(st != "nope"):
return st
return "nope"
def maind(arg0,arg1):
content = arg1
#l = list(re.sub(r'[^a-zA-Z]', '', content))
#l1 = [l[x:x+16] for x in range(0, len(l), 16)]
l1 = arg1
strr = arg0
for i in range(len(l1)):
for j in range(len(l1[i])):
if(strr\[0]==l1[i\][j]):
print("found in " +str(i) +" "+str(j))
ans = find(strr,l1,i,j)
if(ans!="nope"):
ans1 = ans[0:(len(ans)-3)]+"]"
return ans1
return " "
if __name__ == "__main__":
maind(sys.argv[1], sys.argv[2], sys.argv[3])
The execution script:
import crossword
from pwn import *
host = 'challenge.ctf.games'
port = 30567
counter = 0
r = remote(host, port)
if __name__ == "__main__":
data = r.recvuntil('> ')
r.send(b'play')
data = r.recvuntil('> ')
wor = data.decode('ascii')
l3 = []
print(wor[20])
while True:
try:
if wor != None and '0' in wor:
s2 = "0 |"
l = list(re.sub(r'[^a-zA-Z]', '', wor[wor.index(s2) + len(s2):]))
l2 = [l[x:x+16] for x in range(0, len(l), 16)]
l3 = l2[:len(l2)-1]
print(l3)
str1 = ""
for ele in l2\[len(l2)-1\][1:]:
str1 += ele
print(str1)
ans = crossword.maind(str1,l3)
print(ans)
r.sendline(ans)
data = r.recvuntil('> ')
wor = data.decode('ascii')
print(wor)
else:
stre = re.sub(r'[^a-zA-Z]', '', wor)
print(stre)
ans = crossword.maind(stre,l3)
print(ans)
r.sendline(ans)
data = r.recvuntil('> ')
print(data)
wor = data.decode('ascii')
print(wor)
except EOFError:
print(r.recv(4096).decode())
exit()
flag{ac670e1f34da9eb748b3f241eb03f51b}
Bad Words
Solved By : bobbysox
This challenge was interesting. 99% of characters that I entered were flagged as “Bad Words” After some trial and error, i got the first message down below “bash: fg: no job control”
I tried to implement some job control with no luck. However, when trying this, I noticed it processed “#! /bin/bash” without throwing errors. It processes the “/” character!!!! This made me take a step back and think about what were in. We’re in a custom restricted shell. In the past ive usually used native binaries to escape such situations. We have two options here: prefix our commands with “/”, or, try and call native binaries since we know we can just call any path. The latter seemed like the best solution. Call /bin/bash and see what happens. It worked!!! yay!
mobile
To do
Solved by: Starry-lord
De-compile the app
I personally used https://www.decompiler.com/jar/62e31f7faaf148b1b1c4fd143e5480c1/todo.apk/sources/com/congon4tor/todo/LoginActivity.java
Find password “testtest”
Login to the app and find to do list along with the flag
Reactor
Solved by: Starry-Lord
Flag gets more and more unscrambled with correct digits. Basically 4 digit Pin probabilities plus dynamic deobfuscating made the total of possibilities go down to less than 40, like an Eval situation, where you would have result if your first characters are correct.
A. Input 1 digit, 0 to 5, (5) B. Input second digit 0-9(9) C. Input third digit 0-2(2) D. Input fourth digit 0-7(flag!)
27 tries on /40
I agree it’s most likely not the intended way but 4 digits pin plus Eval like function is vulnerable enough 😉
5 was the only one starting with letter f, four characters and a promising { like in other flags.
osint
Challenge Jed Sheeran
Solved by: Starry-lord
Google jed sheeran music and find a soundcloud account
https://m.soundcloud.com/user-836083929-176777888/beautiful-people
pwn
Butter Overflow
Solved by: Taz34
- As the name suggested it’s a buffer overflow challenge
- So I started by giving huge inputs
- And further narrowed it down and found the offset
- The offset is 520 so we need 521 characters to do a buffer overflow to read the flag
scripting
UHAHA
Solved By : ava and thewhiteh4t
We are given a file called uhaha, upon checking the file using the file
command, we come to know that it is type of archive called UHARC, fairly rare one that is. Obvious conclusion seems like extracting it but oh, look it is password protected, and the description of challenge did mention we might need to use rockyou, so it looks like it is time for bruteforcing. Looks like we are going to need a terminal tool and write a script for bruteforcing, apparently we couldn’t find a linux tool to extract UHARC archive, running it under wine was a possibility but that would just complicate the whole thing, so we got a windows tool for it linked here - https://sam.gleske.net/uharc/
just installing it and locating uharc.exe
will do the job
and it looks like it is archive inside a archive….archiveception!
So the following script extracts it repeatedly until we get flag.
from os import rename, remove
import subprocess as subp
filename = 'uhaha.uha'
wordlist_path = 'rockyou.txt'
def extract(filename):
counter = 0
with open(wordlist_path, 'r') as wordlist:
for line in wordlist:
counter += 1
word = line.strip()
#print(f'Trying {word}')
proc = subp.Popen(['uharc.exe', 'e' , f'-pw{word}', filename], stdout=subp.PIPE)
subp.call(['taskkill', '/F', '/PID', str(proc.pid)], stdout=subp.PIPE, stderr=subp.PIPE)
stdout = proc.stdout.read()
output = stdout.decode()
if 'ERROR' in output:
pass
elif 'successfully' in output:
print(f'PASSWORD : {word}')
break
else:
print('Unknown error occured, weird tool...')
print(output)
break
if counter > 200:
break
extract(filename)
while True:
try:
rename('uhaha', 'uhaha2.uha')
except FileNotFoundError:
print('Extracted -> flag.png')
exit()
extract('uhaha2.uha')
remove('uhaha2.uha')
warmups
Target Practice
Solved By : ava
We are given a GIF file, which actually works, and after opening we can see it has some sort of code on it, which changes pretty quick, so we need to split GIF into frames, I used https://ezgif.com/split to split and then downloaded all frames, and did a quick google re-image search on one of them, which result us in knowing that it is called MAXICODE, used by UPS. then I found i MAXICODE decoder - https://products.aspose.app/barcode/recognize/maxicode# and i had to manually check every image, which seems like not the intended way, but okie. The 15th frame (if you started counting from 0) has the flag
flag{385e3ae5d7b2ca2510be8ef4}
2EZ
Solved By : thewhiteh4t
- We are given a file named
2ez
- the file format is not known when I tested it with
file
command
- next I tried
binwalk
to look for any hidden files but the output was blank - next I checked the MAGIC of the file i.e. the header
- file magic is responsible for the correct file format
- file command checks magic and file footer to determine correct file type
- JFIF header means a jpeg file
- correct header for JFIF in hex is :
FF D8 FF
- but if we look at the file given to us its different, so I fixed it using a hex editor
- Saved it as a new file and solved
TSUNAMI
Solved by: Taz34
- We are given a .wav audio file
- at the end of the audio we can here sum disturbances
- so i checked the audio file with sonic visualizer
- checked with spectrograms
here is the flag.
Six Four Over Two
Solved by: Taz34
we have a cipher text give, run it through cyber chef and decode it to get the flag.
Pimple
Solved By : thewhiteh4t
- We are given a gimp project file in this challenge
- there are multiple layers
- each layer contains an image
- to see the flag I started hiding the layers one by one from top and eventually saw the flag
Bass64
Solved By : thewhiteh4t
- We are given a text file in this challenge
- file contains letters and numbers in ASCII art
- it’s actually a base64 string
- converting it gives the flag
flag{35a5d13da6a2afa0c62bfcbdd6301a0a}
ODDBALL
Solved By : choco
the given file is an octal dump
0000000 067531 020165 067165 067543 062566 062562 020144 064164
0000020 020145 062563 071143 072145 066440 071545 060563 062547
0000040 035440 005051 072516 061155 071145 020163 067151 071040
0000060 067141 062547 030040 033455 020077 066510 066555 020041
0000100 067510 020167 062157 005041 063012 060554 075547 060462
0000120 031065 061462 033062 034143 060467 031546 034461 061062
0000140 031064 031543 063064 031544 033062 034063 061065 005175
0000160
All we need to do is to convert this octal to hex dump that is split into 16 parts in each line
def octtodec(decnum):
i = 0
octdecnum = 0
while decnum != 0:
rem = decnum % 10
octdecnum += rem * 8**i
decnum = decnum // 10
i += 1
return octdecnum
my_file = open("oddball", "r")
content = my_file.read()
content = content.replace('\n',' ')
content_list = content.split(" ")
print(content_list)
num = []
res = ""
j = 0
for i in range(len(content_list)-1):
if(i%9!=0):
res1 = hex(octtodec(int(content_list[i])))
if(len(res1)<6):
res1 = res1[0:2]+'0'+ res1[2:]
print(res1)
res = res + res1[4:6] + " " + res1[2:4] + " "
print(res)
else:
num = str(j*10)
j += 1
res = res + "\n" + num.zfill(8) + " "
print(num)
#x = 9
#res = [content_list[i:i+x] for i in range(0, len(content_list), x)]
#print(res)
output will be this
00000000 59 6f 75 20 75 6e 63 6f 76 65 72 65 64 20 74 68
00000010 65 20 73 65 63 72 65 74 20 6d 65 73 73 61 67 65
00000020 20 3b 29 0a 4e 75 6d 62 65 72 73 20 69 6e 20 72
00000030 61 6e 67 65 20 30 2d 37 3f 20 48 6d 6d 6d 21 20
00000040 48 6f 77 20 6f 64 21 0a 0a 66 6c 61 67 7b 32 61
00000050 35 32 32 63 32 36 63 38 37 61 66 33 31 39 32 62
00000060 34 32 63 33 34 66 64 33 32 36 33 38 35 62 7d 0a
you’ll get the flag when converting this hexdump
You uncovered the secret message ;)
Numbers in range 0-7? Hmmm! How od!
flag{2a522c26c87af3192b42c34fd326385b}
web
Titanic
Solved By : thewhiteh4t
- In this challenge we were given a website of a company
- Two things which instantly caught attention were
URL Capture
andAdmin
buttons - URL capture service accepts a URL and takes screenshot of the webpage
- Admin page got a login
- First idea was to try
http://localhost
and it worked
- This is same as the loading splash screen I saw while loading the challenge website
- Next I checked
robots.txt
and got 200 and this revealed a new path/server-status
- Next I obviously tried to access
/server-status
and got 200 again
- And in the logs you can see the login credentials!
SWAGGY
Solved by: Taz34
-
Change the server to the testing server
-
now authorize using the admin:admin credentials
-
now try and execute the request to get the flag
here we have the flag.
Confidentiality
Solved by: Taz34
- here we have a service which lists all the items in the mentioned dir
- so i simply started looking for flag, look for elements in the /home dir
- here we have a user dir and in that we have the flag.txt
now to red the file
/home/user & cat /home/user/flag.txt ![](https://i.imgur.com/G0AlZ6s.png)
here we have the flag