“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


Web

The Flag Dispenser

“Your first step is to fool our Flag Dispenser into thinking you’re an admin. http://flagdispenser.0d.al/ Good luck!”


By navigating to the provided URL we can see that a cookie is present with the value of plebeian.

image

After changing that value to admin I got the flag.

flag{welcome_admin_pls_take_flag_uwu}

Recon All The Things

“The purpose of recon is to gather insights that can be used to identify weaknesses and better understand the target environment for potential attack surfaces.” “Gather your tools and search for some hidden gems. http://20.185.41.52/”


After reading the challenge description I immediately decided to use nuclei.

$ ./nuclei -u http://20.185.41.52/

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v2.9.10

                projectdiscovery.io

[INF] nuclei-templates are not installed, installing...
[INF] Successfully installed nuclei-templates at /home/brun0/nuclei-templates
[INF] Current nuclei version: v2.9.10 (latest)
[INF] Current nuclei-templates version: v9.6.0 (latest)
[INF] New templates added in latest release: 33
[INF] Templates loaded for current scan: 6461
[INF] Targets loaded for current scan: 1
[INF] Templates clustered: 1178 (Reduced 1119 Requests)
[php-detect] [http] [info] http://20.185.41.52/ [5.6.40]
[openssl-detect] [http] [info] http://20.185.41.52/ [OpenSSL/1.0.2q]
[apache-detect] [http] [info] http://20.185.41.52/ [Apache/2.4.38 (Win64) OpenSSL/1.0.2q PHP/5.6.40]
[tech-detect:php] [http] [info] http://20.185.41.52/
[http-trace:trace-request] [http] [info] http://20.185.41.52/
[http-missing-security-headers:permissions-policy] [http] [info] http://20.185.41.52/
[http-missing-security-headers:x-frame-options] [http] [info] http://20.185.41.52/
[http-missing-security-headers:x-content-type-options] [http] [info] http://20.185.41.52/
[http-missing-security-headers:x-permitted-cross-domain-policies] [http] [info] http://20.185.41.52/
[http-missing-security-headers:referrer-policy] [http] [info] http://20.185.41.52/
[http-missing-security-headers:clear-site-data] [http] [info] http://20.185.41.52/
[http-missing-security-headers:strict-transport-security] [http] [info] http://20.185.41.52/
[http-missing-security-headers:content-security-policy] [http] [info] http://20.185.41.52/
[http-missing-security-headers:cross-origin-embedder-policy] [http] [info] http://20.185.41.52/
[http-missing-security-headers:cross-origin-opener-policy] [http] [info] http://20.185.41.52/
[http-missing-security-headers:cross-origin-resource-policy] [http] [info] http://20.185.41.52/
[waf-detect:apachegeneric] [http] [info] http://20.185.41.52/
[docker-compose-config] [http] [medium] http://20.185.41.52/docker-compose.yml
[rdp-detect:win2016] [tcp] [info] 20.185.41.52:3389

Nuclei detected a yml file in http://20.185.41.52/docker-compose.yml.

The presented yml file contained a “private repo”.

version: '3.6'

services:
  webapp:
    build:
      context: ./.client
      dockerfile: Dockerfile
    entrypoint: 
    env_file:
      - ./.private_file_do_not_change
    volumes:
      - "./.client:/app"
      - "nodedata:/app/node_modules"
    ports:
      - "3000:3000"
  
  uid-sku-api:
    build:
      context: ./
      dockerfile: Dockerfile
    entrypoint:
      - npx 
      - babel-node 
      - --presets 
      - "@babel/preset-env" 
      - server
    volumes:
      - "./:/app"
    ports:
      - "3001:3001"

volumes:
  nodedata:

By navigating to http://20.185.41.52/.private_file_do_not_change I got the flag.

flag{pr1v4t3_d0cker_f1l3}

The Poor Man Proxy

“A proxy is an intermediary server that acts as a bridge between a client and a destination server. When a client sends a request to access a resource on the internet, it first goes through the proxy server, which then forwards the request to the destination server on behalf of the client. The response from the destination server is then relayed back to the client through the proxy. URL: http://notes.0d.al/"


Looking at the website we got what its seems like a static page with a TODO list.

image

After enumerating for a while, I couldn’t find anything useful with gobuster and nuclei so I checked the challenge description again and I immediately though about X-Forwarded-For. When a client connects directly to a server, the client’s IP address is sent to the server. But if a client connection passes through any forward or reverse proxies, the server only sees the final proxy’s IP address. So X-Forwarded-For is a common method for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or load balancer.

Knowing this I first verified the length in bytes of the response when doing a normal request.

image

Then when adding the X-Forwarded-For header with the value 127.0.0.1 the response length increased and then I got the flag.

image

flag{HTTP_XFF_FOR_THE_WIN!}

Whois?

“The “whois” is used to query the WHOIS database to retrieve information about domain names, IP addresses, and other network resources. http://whois.0d.al:1341/"


I am not going to lie, I’ve spent some time in this challenge since I had no clue what to do here. After attempting some basic injections (SSTI,SQLi,…) I got nothing.

Then I tried looking at the request in Burp and it looked like a custom shell command.

Running a random whois with the following URL http://whois.0d.al:1341/?host=whois.ripe.net&query=something got something like the image below.

image

After a couple of minutes I started to realize that this could be command injection, however there must be two args. With that I assumed the following:

  • host=
    • probably the whois command with the given API
  • query=
    • probably the second arg , appended to the first arg

With this in mind I tried to inject a command in the first argument and see the output (http://whois.0d.al:1341/?host=whois.ripe.net|id&query=something whois|id something)

image

This did not worked like I was expecting and after a couple of tries I started to think that the flag is probably inside a file so maybe I needed to first enumerate that file and then cat the content.

I injected a ls in the first arg and a dot in the second one (http://whois.0d.al:1341/?host=whois.ripe.net|ls&query=. whois|ls .) and got the following output.

image

Nice! Now that I now what is the file name containing the flag, I can just cat and finish the challenge (http://whois.0d.al:1341/?host=whois.ripe.net|cat&query=59bcc3ad6775562f845953cf01624225 whois|cat 59bcc3ad6775562f845953cf01624225).

flag{CMD_INJ_NINJA!}

Now that the challenge was finished, I wanted to deep dive into the .php file present.

<?php
error_reporting(0);

$output = null;
$host_regex = "/^[0-9a-zA-Z][0-9a-zA-Z\.-\|]+$/";
$query_regex = "/^[0-9a-zA-Z\. ]+$/";

if (isset($_GET["query"]) && isset($_GET["host"]) && is_string($_GET["query"]) && is_string($_GET["host"]))
{
    $query = $_GET["query"];
    $host = $_GET["host"];

    if (!preg_match($host_regex, $host) || !preg_match($query_regex, $query))
    {
        $output = "Invalid query or whois host.";
    }
    else
    {
        $output = shell_exec("/usr/bin/whois -h ${host} ${query}");
    }
}
else
{
    $output = "host and query are required.";
}

?>

As shown above , the function shell_exec is executing the whois command and looks like the only user validation they are doing is with a regex that can easily be bypassed The host regex matches a single character in the range between . (index 46) and | (index 124) (case sensitive) when using \.-\|. This way its possible to use , | to inject a command.

This Looks Familiar

“The security team noticed a few security problems with the Flag Dispenser and made it much more secure! http://protectedflagdispenser.0d.al/"


This was a similar to The Flag Dispenser, however now a JWT is being used.

image

I then tried tampering the jwt:

  • change the alg to none
  • change the role to admin
  • change the alg type to another one

But none of this worked and since this was a simple jwt that didn’t contained more details I started googling ways of breaking this.

Then I came across a realy cool post that defines various ways of attacking a JWT.

Looking at the section of JWT Secret Brute Forcing I saw an important note: A key of the same size as the hash output (for instance, 256 bits for "HS256") or larger MUST be used with this algorithm. Shorter keys can be brute forced..

So I started this approach by using jwt cracker to try to crack the jwt key. This tool worked like a charm and I got the secret(1337).

$ ./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoicGxlYmVpYW4ifQ.Ab5jOyoJQOrpl96XvMwqmqKJrDGIryCbzqt7483yow4
Secret is "1337"

Note that this could also be done using hashcat

$ hashcat -a 0 -m 16500 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoicGxlYmVpYW4ifQ.Ab5jOyoJQOrpl96XvMwqmqKJrDGIryCbzqt7483yow4 /usr/share/wordlists/rockyou.txt

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoicGxlYmVpYW4ifQ.Ab5jOyoJQOrpl96XvMwqmqKJrDGIryCbzqt7483yow4:1337

After finding out the secret, I added the role admin by signing the JWT.

image

flag{wym_a_4_digit_secret_is_not_enough?}

Crypto

Healthy

“I’ve been on a journey to improve body and mind. I do exercise, I eat salads, and yet I have not been able to lose any weight! I found a website claiming that Caesar, the Roman Emperor, had a special secret to make any diet work. I thought I had found the solution to my weight problem, but Caesar’s diet trick is encoded: qbabgrngqbahgf. Can you help me?”


This was clearly an easy challenge for the Caesar’s cipher with a twist.

We didn’t knew what was the shift number to decode the respective message. Don’t get me wrong, this is not a problem as we could just brute-force the 26 possible shifts and gather the flag.

image

donoteatdonuts

Kadabra used Substitute!

“Ctsy sy i ylpycsclcsdo asktmf. Tmfm, miat zmccmf dn ctm izktipmc sy fmkziamj ph iodctmf. Ifm hdl fmijh ndf ctm nziq? Zmc’y qd: nziq{s_tdkm_hdl_ycszz_tibm_i_nmx_gsolcmy_zmnc}”


The challenge name already provide a little bit of info that this must be a substitute cipher. Adding to this we know that the format of the flag is flag{} meaning that nziq = flag.

Using an alphabet mapping website I got the following output.

this is a substitution cipher. here, each letter of the alphabet is replaced by another. are you ready for the flag? let's go: flag{i_hope_you_still_have_a_few_minutes_left}

flag{i_hope_you_still_have_a_few_minutes_left}

It Is All About Magic

“Can you guess the secret for this encrypted file xor not?”


We got what it looks like an encripted jpg file. Reading the challenge description I can assume it was encripted using XOR.

To reverse a XOR cipher, I would need to perform the XOR operation again with the same key that was used to encrypt the original file. This happens because the XOR operation is a bitwise operation that takes two inputs and outputs a new value that is the result of applying the operation to each bit in the inputs.

So I need to:

  • obtain the key that was used to encrypt the file
  • apply the xor operation to the encrypted file using the same key

To obtain the key I used a script that takes an input file and tries to find the key.

$ python3 xor-decrypt/xor-decrypt.py -i "magic_image.jpg.enc" -m 32 -f 32
Probable key lengths: 
   5 - 4.9%
Found a key: M4GIC

The key made sense since the name of the challenge has the “magic” word in it, so the next thing to do would be to use the known key and XOR the input file again to get the decrypted file.

$ python3 xor-decrypt/xor-decrypt.py -i "magic_image.jpg.enc" -o "output.jpg" -k M4GIC -d

image

flag{Y0u-kN0w-S0m3-Tr1Cks}

I Forgot My Phone Number

“Please, help me. I forgot my phone number. Thankfully, I found a hash of it (sha256) in some application logs. dd007cb8341261d248a87c58d7013b0f7bbe8e0b4172d34d561e0f5b0c84634d Can you help me recover my phone number? Note: Don’t forget the country prefix! It’s a portuguese number. The whole number should look like:+351XXXXXXXXX”


This was the perfect challenge to show hashcat power while using masks. They gave us the hash and we know that the format is a sha256 and we also know that the pattern has to contain +351 and numbers. With this information, the scope starts to decrease making it possible to brute-force the hash.

$ echo "dd007cb8341261d248a87c58d7013b0f7bbe8e0b4172d34d561e0f5b0c84634d" > hash
$ echo "+351?d?d?d?d?d?d?d?d?d" > mask
$ hashcat -m 1400 -a 3 hash mask

dd007cb8341261d248a87c58d7013b0f7bbe8e0b4172d34d561e0f5b0c84634d:+351968210943
+351968210943

Misc

A Different Kind of Flag

image


Searching for AACS hex in Google i’ve found that this is AACS encryption key controversy.

According to wikipedia:

A controversy surrounding the AACS cryptographic key arose in April 2007 when the Motion Picture Association of America and the Advanced Access Content System Licensing Administrator, LLC (AACS LA) began issuing cease and desist letters[7] to websites publishing a 128-bit (16-byte) number, represented in hexadecimal as 09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0[8][9] (commonly referred to as 09 F9), a cryptographic key for HD DVDs and Blu-ray Discs. The letters demanded the immediate removal of the key and any links to it, citing the anti-circumvention provisions of the United States Digital Millennium Copyright Act (DMCA).

In order to complete this challenge I used a color picker extractor tool to gather the hex values of the image. That gave me the following output:

  • 666c61677b5f4f685f4e316e455f6546665f4e694e655f7d

After converting from hex to ascii I got the flag.

flag{_Oh_N1nE_eFf_NiNe_}

No One Can Read This!

“Obfuscation can provide some level of protection against reverse-engineering and unauthorized access to sensitive code or algorithms. It makes it harder for attackers to understand the inner workings of the code and extract valuable information. Are you up for the challenge of breaking this highly secure code? https://pastebin.com/XLQJGZd8"


Opening the pastebin link we got javascript code obfuscated.

function _0x18d3(){var n=["986812zTyGkV","7564912lJTdqw","ZmxhZ3tUaGlzSXN","1218535gGCsbz","58236qqPWAI","3190257ERjObe","19843bqzMoy","26gIYNza","1330485xEwykw"];return(_0x18d3=function(){return n})()}function _0x58e0(n,r){var t=_0x18d3();return(_0x58e0=function(n,r){return t[n-=358]})(n,r)}function _0x414243(){var n=_0x58e0;console.log(n(366)+"KU09iZnVzY2F0aW9uIX0")}!function(n,r){for(var t=_0x58e0,e=_0x18d3();;)try{if(668689===parseInt(t(361))/1*(-parseInt(t(362))/2)+parseInt(t(363))/3+parseInt(t(364))/4+-parseInt(t(358))/5+-parseInt(t(359))/6+-parseInt(t(360))/7+parseInt(t(365))/8)break;e.push(e.shift())}catch(n){e.push(e.shift())}}();

After some minutes manualy deobfuscating the given code I came to the following better looking code.

function _0x18d3() {
  var n = ["986812zTyGkV", "7564912lJTdqw", "ZmxhZ3tUaGlzSXN", "1218535gGCsbz", "58236qqPWAI", "3190257ERjObe", "19843bqzMoy", "26gIYNza", "1330485xEwykw"];
  return (_0x18d3 = function () {
    return n;
  })();
}
function _0x58e0(n, r) {
  var t = _0x18d3();
  return (_0x58e0 = function (n, r) {
    return t[n -= 358];
  })(n, r);
}
function _0x414243() {
  var n = _0x58e0;
  console.log(_0x58e0(366) + "KU09iZnVzY2F0aW9uIX0");
}
!function (n, r) {
  var t = _0x58e0;
  for (var e = _0x18d3();;) {
    try {
      if (668689 === parseInt(_0x58e0(361)) / 1 * (-parseInt(_0x58e0(362)) / 2) + parseInt(_0x58e0(363)) / 3 + parseInt(_0x58e0(364)) / 4 + -parseInt(_0x58e0(358)) / 5 + -parseInt(_0x58e0(359)) / 6 + -parseInt(_0x58e0(360)) / 7 + parseInt(_0x58e0(365)) / 8) {
        break;
      }
      e.push(e.shift());
    } catch (n) {
      e.push(e.shift());
    }
  }
}();

Looking at the code, I can see that the function _0x414243() is acting like the main function. After running that I got what it looked like a base64 string.

$ node a.js
ZmxhZ3tUaGlzSXNKU09iZnVzY2F0aW9uIX0

Decoded the string and got the flag.

$ echo "ZmxhZ3tUaGlzSXNKU09iZnVzY2F0aW9uIX0" | base64 -d
flag{ThisIsJSObfuscation!}

Note that there is a cool website that helps deobfuscating.

Are You a Good Scientist?

“Scientists have discovered an unknown DNA sequence that may belong to a new species, but they are stuck. Can you help them to proceed with the investigation?” “CGCGCGTACGACCGCTCTGTCATCATCACACGATCACACTATCACACGATAACTTC”


This challenge took me a while to solve since I was looking at genetic stuff. However this was easy because DNA sequence can be represented in binary data:

  • A = 00
  • C = 01
  • G = 10
  • T = 11

Using this information I represented the given DNA sequence in binary.

0110011001101100011000010110011101111011010011010011010001000110001101000100011100110100010001100011000001111101

Then I transformed the binary data to text and got the flag.

image

flag{M4F4G4F0}

Trivia

Thirty-Two

“I was born way before NTFS. What is my maximum file size (in bytes)?”


Since they are saying that they were born way before NFTS and the challenge name is thirty two I assumed that they were refering to FAT32.

I know for a fact that FAT32 maximum file size is 4,294,967,295 bytes being that the flag.

4294967295

No Google

“I hold the power to shape what search engines see, Controlling the content that’s indexed, that’s me. With authority over visibility, I dictate the view, Influencing which parts of the website come through. What am I?”


Hmmm if you are not google you must be robots.txt.

robots.txt

The Most Beautiful Woman in Film

“In films I mesmerized with my grace and my charm, But behind the scenes, my intellect caused alarm. So tell me, who am I, this star with brains and flair? A beauty and an inventor, a name quite rare.”


This was an easy one since Google was my friend. I only copied the part “A beauty and an inventor, a name quite rare” and that led me to an article.

Reading the article I could find that “Hollywood actress Hedy Lamarr, ’the Angelina Jolie of her day,’ was also an avid inventor and the person behind advances in communication technology in the 1940s that led to today’s Wi-Fi, GPS, and Bluetooth” and TIL.

Hedy Lamarr

Java Nightmare!

“In the realm of Java’s coding sphere, A silent menace, a danger unclear. A library’s flaw, a vulnerability deep, Unleashing havoc, causing systems to weep. With its loggers and appenders, it sneaks through, Exploited by those with malicious view. What am I, this weak link in the chain?”


Another easy challenge refering to log4j. However the flag was not that but log4shell

Log4Shell refers to a critical vulnerability discovered in the Apache Log4j library. Attackers exploited the vulnerability by injecting malicious code into log messages or by exploiting the library’s JNDI (Java Naming and Directory Interface) lookup feature.

log4shell

Conclusion

This year I was not able to finish all challenges as I was busy during summer. However I placed 10th which is not bad at all since I had only 2 or 3 days to explore the challenges. Excited to the Christmas challenge 2023!

image