奥运会网球比分规则|雪缘网网球比分直播|
歡迎來到 黑吧安全網 聚焦網絡安全前沿資訊,精華內容,交流技術心得!

從PHP底層看open_basedir bypass

來源:本站整理 作者:佚名 時間:2019-04-15 TAG: 我要投稿


有國外的大佬近日公開了一個php open_basedir bypass的poc,正好最近在看php底層,于是打算分析一下。
poc測試
首先測試一下:

我們用如上源碼進行測試,首先設置open_basedir目錄為/tmp目錄,再嘗試用ini_set設置open_basedir則無效果,我們對根目錄進行列目錄,發現無效,返回bool(false)。
我們再嘗試一下該國外大佬的poc:

發現可以成功列舉根目錄,bypass open_basedir。
那么為什么一系列操作后,就可以重設open_basedir了呢?我們一步一步從頭探索。
ini_set覆蓋問題探索
為什么連續使用ini_set不會對open_basedir進行覆蓋呢?我們以如下代碼為例:
運行后結果如下:
string(0) ""
string(4) "/tmp"
string(4) "/tmp"
string(4) "/tmp"
默認的open_basedir值本來是空,第一次設置成/tmp后,以為設置將不會覆蓋。
我們來探索一下原因。首先找到php函數對應的底層函數:
ini_get : PHP_FUNCTION(ini_get)
ini_set : PHP_FUNCTION(ini_set)
這里我們主要看的是ini_set的流程,ini_get作為信息輸出函數,我們不太關心。
我們先對ini_set下斷點,然后再run程序:
b /php7.0-src/ext/standard/basic_functions.c 5350
r c.php
程序跑起來后,首先是3個初始值:
zend_string *varname;
zend_string *new_value;
char *old_value;
然后進入詞法分析,得到3個變量值:
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &varname, &new_value) == FAILURE) {
return;
}
我們可以看到
pwndbg> p *varname
$45 = {
  gc = {
    refcount = 0,
    u = {
      v = {
        type = 6 '\006',
        flags = 2 '\002',
        gc_info = 0
      },
      type_info = 518
    }
  },
  h = 15582417252668088432,
  len = 12,
  val = "o"
}
這是zend_string的結構體,也是php7的新增結構:
struct _zend_string {
    zend_refcounted_h gc; /*gc信息*/
    zend_ulong        h;  /* hash value */
    size_t            len; /*字符串長度*/
    char              val[1]; /*字符串起始地址*/
};
我們可以看到varname.val為:
pwndbg> p &varname.val
$46 = (char (*)[1]) 0x7ffff7064978
pwndbg> x/s $46
0x7ffff7064978:"open_basedir"
然后new_value.val為:
pwndbg> p &new_value.val
$48 = (char (*)[1]) 0x7ffff7058ad8
pwndbg> x/s $48
0x7ffff7058ad8:"/tmp"
即我們最開始傳入的兩個參數。
然后程序拿到原來的open_basedir的value:


然后會進入php_ini_check_path:

由于第一次沒有設置過open_basedir,所以直接跳出判斷,進入下一步:
if (zend_alter_ini_entry_ex(varname, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
zval_dtor(return_value);
RETURN_FALSE;
}
我們跟進FAILURE,找到定義:
typedef enum {
  SUCCESS =  0,
  FAILURE = -1,/* this MUST stay a negative number, or it may affect functions! */
} ZEND_RESULT_CODE;
當zend_alter_ini_entry_ex的返回值不為-1時,即代表更新成功,否則則會進入if,返回false。
而經過比對發現:第一次設置open_basedir和第二次設置時候,正是這里的返回值不一樣,第一次設置時,這里為SUCCESS,即0,而第二次設置為FAILURE,即-1,我們跟入zend_alter_ini_entry_ex進行比對:
b /php7.0-src/Zend/zend_ini.c:330
發現兩次不同的點在于如下判斷:
if (!ini_entry->on_modify
|| ini_entry->on_modify(ini_entry, duplicate, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage) == SUCCESS)
第一次時:
ini_entry->on_modify = 0x5d046e
ini_entry->on_modify(ini_entry, duplicate, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage) = 0

[1] [2] [3]  下一頁

【聲明】:黑吧安全網(http://www.nddver.tw)登載此文出于傳遞更多信息之目的,并不代表本站贊同其觀點和對其真實性負責,僅適于網絡安全技術愛好者學習研究使用,學習中請遵循國家相關法律法規。如有問題請聯系我們,聯系郵箱[email protected],我們會在最短的時間內進行處理。
  • 最新更新
    • 相關閱讀
      • 本類熱門
        • 最近下載
        奥运会网球比分规则
        广东11选5计算器 v8彩票安卓 长期精准单双中特 3d组六分类杂6 上海时时乐开奖号码 360竞彩足球比分即时比分 重庆快乐10分钟吧 创业板好股票推荐 贵州十一选五开奖结果走势图贵 安徽时时彩快三