PHP-Session利用總結

2020-12-16 湖南蟻景

0x00 前言

最近刷題碰到好幾個關於php代碼審計中session相關的問題,之前沒有做過系統的總結,在此補一下鍋。

0x01 Session基礎知識

這裡主要講講傳統的PHP中的「服務端Session」。至於什麼是服務端Session,什麼是客戶端Session,可以看看P神的**客戶端 session 導致的安全問題https://www.leavesongs.com/PENETRATION/client-session-security.html

Session概念:在計算機中,尤其是在網絡應用中,稱為「會話控制」。Session 對象存儲特定用戶會話所需的屬性及配置信息。這樣,當用戶在應用程式的 Web 頁之間跳轉時,存儲在 Session 對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。當用戶請求來自應用程式的 Web 頁時,如果該用戶還沒有會話,則 Web 伺服器將自動創建一個 Session 對象。當會話過期或被放棄後,伺服器將終止該會話。

Session機制:session內容一般以文件的形式存儲於伺服器中,而本地瀏覽器會存儲一個與伺服器中session文件對應的Cookie值,Cookie存儲的是鍵值為「PHPSESSID」的Seeion_id值,用戶在訪問web應用時,每次跳轉發生http請求時,會自動把這個存儲session_id的Cookie值發送過去,因此web應用的所有頁面都可以獲取到這個SESSION_ID值,也就可以通過session_id獲取伺服器中存儲的session值,當用戶關閉瀏覽器後,cookie存儲的session_id自動清除,一般伺服器存儲的session文件也會在30分鐘後自動清除。

比如在wamp環境下,index.php如下:

<?php

session_start();

phpinfo();

?>

首先理解一下session_start()

當會話自動開始或者通過 session_start() 手動開始的時候, PHP 內部會依據客戶端傳來的PHPSESSID來獲取現有的對應的會話數據(即session文件), PHP 會自動反序列化session文件的內容,並將之填充到 $_SESSION 超級全局變量中。如果不存在對應的會話數據,則創建名為sess_PHPSES SID(客戶端傳來的)的文件。如果客戶端未發送PHPSESSID,則創建一個由32個字母組成的PHPSESSID,並返回set-cookie。

可以看到請求中對應的PHPSESSID:ifrvi9r7ui81r0fjq569b06862

在伺服器端,即/wamp/tmp下我們就可以發現一個生成的記錄Session的文件,因為也沒有記錄什麼會話信息,因此該文件是一個空文件。

補充一下關於php-Session相關配置的說明

在php.ini中對Session存在許多配置,這裡我們通過phpinfo來說明幾個重要的點。

說明如下:

session.save_path="" --設置session的存儲路徑

session.save_handler="" --設定用戶自定義存儲函數,如果想使用PHP內置會話存儲機制之外的可以使用本函數(資料庫等方式),默認files以文件存儲

session.auto_start boolen --指定會話模塊是否在請求開始時啟動一個會話,默認為0不啟動

session.serialize_handler string --定義用來序列化/

常見的php-session存放位置

/var/lib/php5/sess_PHPSESSID/var/lib/php7/sess_PHPSESSID/var/lib/php/sess_PHPSESSID/tmp/sess_PHPSESSID/tmp/sessions/sess_PHPSESSED0x02 Session可能導致的攻擊面

Session序列化攻擊Session文件包含Session偽造用戶登錄Session邏輯漏洞0x03 Session序列化攻擊

Serialize_handler

要了解Session序列化攻擊,先來了解一下Session機制中對序列化是如何處理的。

在php中存在三種序列化處理引擎

本地測試如下:

Session文件內容分別對應結果為

test|s:7:"CoCo1er";

<0x04>tests:7:"CoCo1er";

a:1:{s:4:"test";s:7:"CoCo1er";}

攻擊利用原理

payload千萬條,原理第一條。

(這裡補充說一點,PHP中的Session的實現是沒有的問題,危害主要是由於程式設計師的Session使用不當而引起的。如下)

使用不同引擎來處理session文件

如果在PHP在反序列化存儲的$_SESSION數據時使用的引擎和序列化使用的引擎不一樣,會導致數據無法正確第反序列化。通過精心構造的數據包,就可以繞過程序的驗證或者是執行一些系統的方法。例如:

在這麼一種情況下:

假如我們使用php_serialize引擎時進行數據存儲時的序列化,可以得到內容

$_SESSION[『key』] = 『Boby』;

a:1:{s:3:」key」;s:4:」Boby」;}

這時我們的解析採用了另一種引擎:php

思考一下這時會發生什麼情況?(php引擎中以豎線來分隔鍵和值)

如果像上面我們的payload換一下,傳入內容以及得到的存儲內容如下:

$_SESSION['key'] = '|O:4:"User":0:{}';

a:1:{s:3:"key";s:16:"|O:4:"User":0:{}";}

這時候a:1:{s:3:"key";s:16:"被當作了key,而後續的O:4:"User":0:{}";}被當作了value從而被反序列化。這裡可能有人會問了,為什麼會被反序列化?

看看官方文檔

這裡可能還會有人問?那串value不符合"正常"的被反序列化的字符串規則。這個也不用擔心,這裡提到一個unserialize的特性,之前也做題也遇到過。在執行unserialize的時候,如果字符串前面滿足了可被反序列化的規則即後續的不規則字符會被忽略。

如果不太好理解不如直接來看一個在線測試用例:

總結一下,在php以php_serialize引擎生成session,然而又以php引擎來解析時,我們通過傳入類似

$_SESSION[『name』] = |序列化內容

這種形式的payload即有可能觸發反序列化漏洞。當然這裡只是提到了能夠找到反序列化利用的點,至於能不能真正觸發反序列化漏洞還需要結合當前環境以及一些魔術函數中是否存在可利用點。這就涉及到php反序列化漏洞的利用知識點了,這裡也就不詳細講了。關於Session反序列化攻擊的複雜利用方式,可以參考2018LCTF中的bestphp’s revenge一題。

沒有$_SESSION變量賦值

從上面的情況中我們可以發現我們對session的賦值可控。那如果代碼中不存在對$_SESSION變量賦值的情況下如何利用呢?來看下面一個點。

php還存在一個upload_process機制,即自動在$_SESSION中創建一個鍵值對,值中剛好存在用戶可控的部分。

寫入的方式主要是利用PHP中Session Upload Progress來進行設置,具體為,在上傳文件時,如果POST一個名為PHP_SESSION_UPLOAD_PROGRESS的變量,就可以將filename的值賦值到session中。

//上傳表單

<form action="http://xx.xxx.xx.xx/index.php" method="POST" enctype="multipart/form-data">

<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />

<input type="file" name="file" />

<input type="submit" />

</form>

既然filename欄位能夠寫入session中那麼就滿足了session可控條件,後續的利用條件同上面所述的情景一致,兩種不同引擎先後作用導致了惡意的序列化字符串被解析。

0x04 Session文件包含

這個也是一個比較舊的知識點了,其實不僅是Session文件包含,仔細想想,理論上只要能夠在文件中寫入php代碼,再被include包含進來不都可以實現getshell嘛?只不過在這裡我們的可控點是Session文件,如果能向其中寫入php代碼,也是可以實現文件包含漏洞利用的。

作為文件包含的利用這裡就不展示了,網上關於這個的基礎資料早就爛大街了。

值得一提的是,往往現在的CTF出題不會僅限於文件包含這一個點來出題,而是利用諸如session+lfi的形式來入題獲取源碼等。而且可能加入open_basedir來限制路徑,此時就需要熟悉了解session的機制,通過函數來改變save路徑來利用。這個思路是在XCTF Final中出現的bestphp一題中的考點。感興趣的同學可以去找到環境復現一波。

0x05 Session偽造用戶登錄

前幾天正好3CTF出了一個這個考點,這裡以那個題目來說明一下利用方式。(由於沒有提供復現環境,此處也只能限於「紙上談兵」,希望大家能夠理解一下利用原理即可。)

**利用前提:**session可控;知道session存儲格式。

這裡的考題是多個攻擊面的組合。題面index.php下提示要以admin登錄。

sql盲注可以跑sqlmap拿到執行shellsql root用戶存在file權限,但是往站點直接寫shell無法成功(猜測應該是站點根目錄有限制,但是可以猜測/tmp可寫掃後臺發現test.php,訪問發現回顯了session的數據結構Array([username]=>test),知道了session的格式。key為username,至於採用了哪種序列化引擎?三種都測一下就完事。這裡滿足了兩個利用前提。通過sqlmap-shell往/tmp寫入文件偽造adminpayload:select 'username|s:5:"admin";' into outfile '/tmp/sess_PHPSESSID'最後修改成對應設計的PHPSESSID即可偽造admin登錄拿到flag。0x06 Session邏輯漏洞

很遺憾這個點也沒有可以復現的環境。(官方買斷...)這個是上兩周unctf中出現的一道web題考點。這個邏輯漏洞處在重置密碼處。過程大致如下。

密碼重置分為三個步驟。

填寫需要重置的用戶名用戶名綁定的郵箱中收到驗證碼填寫驗證碼,進入重置密碼頁面,填寫完新密碼完成重置。這裡存在的邏輯漏洞在於第一個頁面的填寫用戶名處,猜測後臺有設置session。類似:$_SESSION[『name』] = $_POST['name'];

利用方式:重置admin密碼。

打開一個正常頁面完整流程走到最後一步,填寫完驗證碼通過後,填寫新密碼,此時並不提交。新開另外一個頁面完成第一步,重置用戶填寫admin,此時Session不再是我們之前自己的用戶,而變成了admin。這時完成之前頁面的提交。成功重置admin密碼。這裡邏輯漏洞產生的原因在於對填寫驗證碼後沒有對相關用戶綁定做記錄,在最後一步重置密碼時沒有對Session的可靠性進行檢查就直接執行了功能。而我們都知道Session存儲在伺服器端,因此我們再開一個頁面即可完成對單一session文件內容的修改(保證在同一個PHPSEEID下)。

0x07 總結

這裡僅僅是記錄了自己關於PHP的session機制相關的學習,舉的都是自己最近在CTF題中接觸到的點,但關於session的利用點怎麼可能只有這幾個?遇到了再補充學習吧。限於篇幅沒有展開講拓展利用,但是說白了,拓展利用就是多個複雜知識點的綜合。我認為只有把原理性的問題搞清楚了才有可能去理解複雜的組合攻擊。另外如果文中有什麼理解表達錯誤的地方還望師傅們指正。

相關焦點

  • php session 會話(專題)
    所有在php.ini默認是關閉通過地址欄傳遞phpsessionid的,如果沒開啟就不能使用session,所以需要php.ini配置支持才行。$_GET['SESSION_ID'] : session_create_id();session_id($session_id);session_start();$_SESSION['user'] = 'user01';echo $session_id;3、瀏覽計數器利用 session 機制可以實現 記錄用戶的訪問頁面的次數
  • PHP文件包含漏洞利用思路與Bypass總結手冊(完結)
    那麼該怎麼去繞過這個限制呢,一般做法是逆過程,既然他選擇了編碼或加密,我們就可以嘗試著利用解碼或解密的手段還原真實session,然後再去包含,這個時候就能夠將惡意的session信息包含利用成功。很多時候伺服器上的session信息會由base64編碼之後再進行存儲,那麼假如存在本地文件包含漏洞的時候該怎麼去利用繞過呢?下面通過一個案例進行講解與利用。
  • PHP文件包含漏洞利用思路與Bypass總結手冊(二)
    PHP文件包含漏洞利用思路與Bypass總結手冊(一)可以通過phpinfo查看session.save_path的值知道session的存儲後,總結常見的php-session默認存放位置是很有必要的,因為在很多時候伺服器都是按照默認設置來運行的,這個時候假如我們發現了一個沒有安全措施的session包含漏洞就可以嘗試利用默認的會話存放路徑去包含利用。
  • 原理+實踐掌握(PHP反序列化和Session反序列化)
    所以我們利用這個漏洞點便可以獲取web shell了phpini_set('session.serialize_handler', 'php');//ini_set("session.serialize_handler", "php_serialize");//ini_set("session.serialize_handler", "php_binary");session_start();$_SESSION['lemon'] = $_GET['a
  • php中Session使用方法詳解
    phpsession_start();$_SESSION["username"]="skygao";$_SESSION["uid"]=1;?phpif(isset($_COOKIE[session_name()])){        setcookie(session_name(),'',time()-3600,'/');}?>通過前面的介紹可以總結出,Session的註銷過程共需要4個步驟。
  • Php常見問題總結
    3:如何使用session凡是與session有關的,之前必須調用函數session_start();為session付值很簡單,如 phpsession_start();session_unset();session_destroy();?> 取消某個session變量在php4.2以上還有BUG.取消某個session變量在php4.2以上還有BUG.
  • PHP禁止Cookie之後Session還能用嗎?
    設置php.ini配置文件中的「session.use_trans_sid = 1」,或者編譯時打開打開了「--enable-trans-sid」選項,讓PHP自動跨頁傳遞Session ID。途徑2舉例說明:index.php內容如下:session_start();$_SESSION['name'] = '貓巷';
  • 跟我來學PHP5:session會話的使用和分析
    >Warning:Cannotsendsessioncachelimiter-headersalreadysent(outputstartedat/usr/local/apache/htdocs/cga/member/1.php:2)………… 你可以在php.ini裡啟動session.auto_start=1,
  • PHP技巧:關於cookie和session的分析
    phpvalue = 'something from somewhere'; setcookie("TestCookie", value); /* 簡單cookie設置 */setcookie("TestCookie", value, time()+3600); /* 有效期1個小時 */setcookie("TestCookie", value
  • PHP 文件包含漏洞姿勢總結
    利用條件:session 文件路徑已知,且其中內容部分可控。/tmp/sess_tnrdo9ub2tsdurntv0pdir1no7session 文件一般在 /tmp 目錄下,格式為 sess_[your phpsessid value],有時候也有可能在 /var/lib/php5 之類的,在此之前建議先讀取配置文件。
  • PHP文件包含漏洞利用思路與Bypass總結手冊(三)
    :1、php >= 5.3.02、已知限制利用姿勢:依據限制構造特定zip包利用測試代碼,依據限制構造特定壓縮包:利用phar協議:>LFI-長度截斷利用條件:php < 5.2.8LFI-零字節截斷利用條件:利用姿勢:
  • SESSION與COOKIE的區別是什麼?-PHP面試題
    目前可以通過使用redis來保存SESSION信息,SESSION保存在伺服器端的文件或資料庫中,默認保存在文件中,文件路徑由php配置文件的session.save_path指定。SESSION文件是公有的。4、COOKIE的存儲量有限、只允許存入4KB,而SESSION是無限量的。COOKIE可以通過javscript來操作,使用起來比較方便。
  • php反序列化
    session.serialize_handler存儲格式這裡主要是php_serialize和php兩種,默認是php設定一下session,然後去查看session文件phpini_set('session.serialize_handler','php_serialize');session_start();$_SESSION['name']="luoke";?><script>alert(document.cookie)</script>
  • PHP反序列化筆記
    phpini_set("session.serialize_handler", 'php_serialize');session_start();$_SESSION['a'] = $_GET['a'];?><?
  • PHP實例程序:用PHP製作登錄頁面程序
    /include/config.inc.php3");    session_start();    $right_enter='0';    $query="select * from user_define where user_login='$user_login' and user_pass=password('$user_pass')";    $result
  • Session是怎麼實現的?存儲在哪裡?
    如果你比較了解http協議,那麼答案一目了然,就是cookie,如果你想為用戶建立一次會話,可以在用戶授權成功時給他一個cookie,叫做會話id,它當然是唯一的,比如PHP就會為建立會話的用戶默認set一個名為phpsessid,值看起來為一個隨機字符串的cookie,如果下次發現用戶帶了這個cookie,伺服器就知道,哎呀,剛剛這位顧客來了。
  • PHP 垃圾回收機制詳解
    在默認情況下,session.gc_probability=1, session.gc_divisor =100也就是說有1%的可能性啟動GC(也就是說100個請求中只有一個gc會伴隨100個中的某個請求而啟動).
  • PHP實例:用PHP實現表單驗證碼登陸校驗
    php session_start(); if($act  ==  "init") {         Header("Content-type:  image/png");         srand(microtime()  *  100000);         $login_check_number  =  strval(rand("1111"
  • PHP代碼審計四
    file=http://127.0.0.1/phpinfo.txthttps://test.com/1.txt會話劫持遇到的比較多的就是出現在cookie驗證上面,通常是沒有使用session來認證,直接將用戶信息保存在cookie中Session劫持攻擊是指黑客劫持目標用戶的session id來獲取網站伺服器上未經許可的存取信息,特別是竊取目標用戶等的
  • PHP零基礎入門
    ;// print_r($keys);// print_r($vals);$sql="INSERT user({$keys}) VALUES({$vals})";echo $sql;什麼是session?為啥使用session?session的工作原理,與session相關的函數,php配置中的session片段。