戰(zhàn):從原理到繞過(guò)技巧的完整指南)
1. 從解題到理解為什么CTF中的SQL注入是絕佳的入門路徑如果你剛開(kāi)始接觸CTFCapture The Flag奪旗賽尤其是Web安全方向那么“SQL注入”這個(gè)名詞幾乎會(huì)出現(xiàn)在每一份新手推薦列表里。很多人會(huì)告訴你這是基礎(chǔ)是必學(xué)項(xiàng)。但你可能會(huì)有疑問(wèn)為什么偏偏是它網(wǎng)上教程那么多從哪開(kāi)始才不走彎路我最初也有同樣的困惑直到真正上手做了幾十道題才發(fā)現(xiàn)SQL注入之所以被奉為CTF Web入門的“第一課”絕不僅僅因?yàn)樗R?jiàn)更因?yàn)樗褚话讶f(wàn)能鑰匙能幫你串起Web安全最核心的思考邏輯如何與應(yīng)用程序“對(duì)話”并讓它說(shuō)出不該說(shuō)的秘密。在真實(shí)的CTF賽題中SQL注入的考察點(diǎn)早已超越了簡(jiǎn)單的“ or 11 --”萬(wàn)能密碼。它是一面鏡子映射出開(kāi)發(fā)者對(duì)用戶輸入的態(tài)度也考驗(yàn)著你作為攻擊者解題者的想象力。從最基礎(chǔ)的聯(lián)合查詢到基于時(shí)間盲注的“猜”數(shù)據(jù)再到各種匪夷所思的過(guò)濾繞過(guò)每一步都逼迫你去理解后端代碼的執(zhí)行邏輯、數(shù)據(jù)庫(kù)的結(jié)構(gòu)以及HTTP協(xié)議的細(xì)節(jié)。這個(gè)過(guò)程正是安全研究員思維的雛形。因此這篇筆記不會(huì)是一份冷冰冰的語(yǔ)法大全而是結(jié)合我踩過(guò)的坑和刷過(guò)的題帶你走一遍從“看到注入點(diǎn)”到“拿到flag”的完整心路歷程。我們會(huì)繞過(guò)那些枯燥的理論直接聚焦于CTF場(chǎng)景下最高頻、最實(shí)用的技巧和思維模式。無(wú)論你是完全零基礎(chǔ)還是學(xué)過(guò)理論但一做題就懵希望這篇“接地氣”的筆記能幫你把知識(shí)點(diǎn)串聯(lián)起來(lái)真正入門。2. 環(huán)境搭建與第一道“墻”認(rèn)識(shí)你的戰(zhàn)場(chǎng)在真正開(kāi)始“注入”之前你得先有一個(gè)安全的、可以隨意折騰的練習(xí)環(huán)境。直接在網(wǎng)上找存在漏洞的真實(shí)網(wǎng)站是絕對(duì)違法的也是極不道德的。因此本地靶場(chǎng)是我們的唯一選擇。2.1 靶場(chǎng)選擇從DVWA到CTFshow對(duì)于純新手我強(qiáng)烈推薦從DVWA開(kāi)始。別被它的老界面迷惑它的價(jià)值在于將漏洞難度分為“Low”、“Medium”、“High”、“Impossible”四檔。你可以清晰地看到隨著開(kāi)發(fā)者安全意識(shí)的提高代碼防護(hù)增強(qiáng)同一種攻擊手段需要如何進(jìn)化才能生效。在“Low”級(jí)別你幾乎可以原封不動(dòng)地使用教科書上的Payload到了“High”級(jí)別你就得開(kāi)始思考如何繞過(guò)轉(zhuǎn)義、如何利用二次注入。這種漸進(jìn)式的體驗(yàn)是無(wú)價(jià)的。當(dāng)你用DVWA把基礎(chǔ)的聯(lián)合注入、報(bào)錯(cuò)注入、布爾盲注和時(shí)間盲注都過(guò)了一遍之后就可以轉(zhuǎn)向更接近實(shí)戰(zhàn)CTF的在線靶場(chǎng)或集成環(huán)境。CTFshow平臺(tái)這是近年非?;鸬腃TF練習(xí)平臺(tái)它的Web入門系列如“web8”題目設(shè)計(jì)精巧層層遞進(jìn)專門針對(duì)CTF考點(diǎn)。題目通常會(huì)模擬比賽環(huán)境給你一個(gè)目標(biāo)URL你需要自己尋找注入點(diǎn)、判斷數(shù)據(jù)庫(kù)類型、構(gòu)造Payload。它的好處是“開(kāi)箱即用”無(wú)需本地配置。SQLi-Labs這是一個(gè)專注于SQL注入的靶場(chǎng)包含了超過(guò)75種不同類型的注入關(guān)卡從GET注入到POST注入從字符型到數(shù)字型從各種繞過(guò)技巧到堆疊查詢非常全面。適合用來(lái)做專項(xiàng)突破。本地Docker環(huán)境如果你喜歡一切盡在掌控的感覺(jué)可以用Docker一鍵部署像“Vulhub”或“PentesterLab”這樣的漏洞環(huán)境集合。它們通常包含了多種漏洞的復(fù)現(xiàn)環(huán)境SQL注入只是其中之一但配置稍顯復(fù)雜。我的踩坑經(jīng)驗(yàn)一開(kāi)始不要貪多牢牢綁定一個(gè)靶場(chǎng)比如DVWA把每一個(gè)難度級(jí)別的每一種注入類型都徹底吃透。很多人東做一道西做一道結(jié)果基礎(chǔ)不牢遇到稍微變化的過(guò)濾就束手無(wú)策。DVWA的“Impossible”級(jí)別代碼本身就是最好的安全編程教材。2.2 核心工具瀏覽器與Burp Suite的“雙劍合璧”你的武器庫(kù)不需要很復(fù)雜但兩樣?xùn)|西必須精通瀏覽器開(kāi)發(fā)者工具這是你的“眼睛”。F12打開(kāi)后重點(diǎn)看“網(wǎng)絡(luò)”和“控制臺(tái)”標(biāo)簽頁(yè)。網(wǎng)絡(luò)查看每一次點(diǎn)擊、每一次表單提交發(fā)出的HTTP請(qǐng)求。你要清晰地看到請(qǐng)求是GET還是POST參數(shù)是什么Cookie里有沒(méi)有隱藏信息。這對(duì)于判斷注入點(diǎn)類型至關(guān)重要??刂婆_(tái)有時(shí)題目會(huì)涉及前端JavaScript驗(yàn)證你需要在這里調(diào)試或繞過(guò)它。Burp Suite這是你的“雙手”和“大腦”。社區(qū)版就足夠用于CTF學(xué)習(xí)。它的核心模塊是Proxy和Repeater。Proxy設(shè)置瀏覽器代理后所有流量都經(jīng)過(guò)Burp。你可以攔截、查看、修改任何一個(gè)請(qǐng)求再發(fā)送出去。這是手工測(cè)試注入點(diǎn)的標(biāo)準(zhǔn)流程。Repeater當(dāng)你找到一個(gè)可疑的參數(shù)時(shí)把它發(fā)送到Repeater。在這里你可以對(duì)這一個(gè)參數(shù)進(jìn)行反復(fù)的、精細(xì)的修改和測(cè)試而無(wú)需在瀏覽器里來(lái)回刷新頁(yè)面。你可以方便地增刪單引號(hào)、注釋符觀察每一次請(qǐng)求的響應(yīng)差異頁(yè)面內(nèi)容、響應(yīng)時(shí)間、錯(cuò)誤信息。操作意圖解析為什么一定要用Burp因?yàn)镃TF中的注入往往是“盲注”即頁(yè)面不會(huì)直接回顯數(shù)據(jù)庫(kù)錯(cuò)誤或查詢結(jié)果。你需要通過(guò)對(duì)比不同Payload下頁(yè)面返回的細(xì)微差別比如一個(gè)單詞的存在與否、響應(yīng)時(shí)間的長(zhǎng)短來(lái)判斷注入是否成功。用瀏覽器手動(dòng)修改URL或表單效率極低且難以進(jìn)行精細(xì)對(duì)比。Burp Repeater的“差異對(duì)比”功能能高亮顯示兩次響應(yīng)體的不同是盲注的“神器”。3. 注入攻擊的“靈魂四問(wèn)”建立系統(tǒng)性排查思路面對(duì)一個(gè)CTF題目新手最容易犯的錯(cuò)誤就是拿到URL就盲目地輸入‘ and 11 --。沒(méi)有前期的信息收集你的攻擊就像蒙著眼睛扔飛鏢。我總結(jié)了一個(gè)“靈魂四問(wèn)”的流程在每次測(cè)試前按順序過(guò)一遍能極大提高效率。3.1 第一問(wèn)哪里可以輸入尋找注入點(diǎn)注入的本質(zhì)是將用戶輸入作為代碼的一部分執(zhí)行。所以所有用戶能控制輸入的地方都值得懷疑URL參數(shù)/page.php?id1搜索框/search.php?qkeyword登錄表單用戶名、密碼框HTTP請(qǐng)求頭Cookie、User-Agent、Referer、X-Forwarded-For等。這在CTF中越來(lái)越常見(jiàn)題目會(huì)提示“只有來(lái)自特定瀏覽器的用戶才能訪問(wèn)”其實(shí)就是考察你能否在User-Agent里注入。文件上傳點(diǎn)文件名有時(shí)會(huì)被存入數(shù)據(jù)庫(kù)也可能構(gòu)成注入。實(shí)操技巧用Burp攔截一個(gè)正常請(qǐng)求把所有參數(shù)值包括Cookie都嘗試替換成一個(gè)單引號(hào)‘觀察響應(yīng)。如果頁(yè)面報(bào)錯(cuò)出現(xiàn)SQL語(yǔ)法錯(cuò)誤、數(shù)據(jù)庫(kù)錯(cuò)誤或者頁(yè)面布局出現(xiàn)異常少了某些元素這里就可能存在注入點(diǎn)。3.2 第二問(wèn)它被如何“處理”了判斷注入類型與過(guò)濾規(guī)則找到可疑點(diǎn)后不要急著上復(fù)雜Payload。先進(jìn)行“探針”測(cè)試目的是理解后端對(duì)輸入做了什么。數(shù)字型還是字符型測(cè)試id1 and 11和id1 and 12如果第一個(gè)返回正常第二個(gè)返回異?;驘o(wú)數(shù)據(jù)很可能是數(shù)字型注入。因?yàn)閍nd 12為假導(dǎo)致整個(gè)查詢條件為假。測(cè)試id1‘ and ‘1’‘1和id1‘ and ‘1’‘2如果出現(xiàn)類似情況則是字符型注入。你需要用單引號(hào)來(lái)閉合原SQL語(yǔ)句中的引號(hào)。有沒(méi)有過(guò)濾嘗試輸入select,union,or,and,空格,注釋符(--, #)等關(guān)鍵詞。如果頁(yè)面返回統(tǒng)一錯(cuò)誤如“非法輸入”或關(guān)鍵詞消失了說(shuō)明存在過(guò)濾。你需要開(kāi)始思考繞過(guò)方案大小寫變形雙寫繞過(guò)用/**/代替空格用||代替or3.3 第三問(wèn)它在和誰(shuí)“說(shuō)話”判斷數(shù)據(jù)庫(kù)類型不同的數(shù)據(jù)庫(kù)MySQL、PostgreSQL、SQLite、Microsoft SQL Server的語(yǔ)法函數(shù)有差異。猜對(duì)數(shù)據(jù)庫(kù)才能用對(duì)函數(shù)。MySQL非常常見(jiàn)。特征函數(shù)有version() 注釋可以用#或--后面有個(gè)空格字符串連接用concat()。PostgreSQL在CTF中也很多。特征函數(shù)有version() 但注釋只用--字符串連接用||。它的系統(tǒng)信息表是pg_catalog.pg_tables。SQLite輕量級(jí)常用于小型CTF題目。沒(méi)有version()函數(shù)常用sqlite_version()。它的元數(shù)據(jù)表是sqlite_master。MSSQL相對(duì)少一些。特征函數(shù)有version 注釋用--。判斷方法利用數(shù)據(jù)庫(kù)特有的函數(shù)或語(yǔ)法構(gòu)造一個(gè)必然成立或必然錯(cuò)誤的Payload觀察響應(yīng)。對(duì)于MySQLid1‘ and sleep(2) --如果頁(yè)面延遲2秒返回很可能是MySQL。對(duì)于PostgreSQLid1‘ and pg_sleep(2) --同理。通用方法id1‘ union select 1, database() --如果回顯位能顯示當(dāng)前數(shù)據(jù)庫(kù)名也能判斷。3.4 第四問(wèn)我想讓它“說(shuō)”什么確定目標(biāo)與構(gòu)造Payload這是最終步驟。根據(jù)題目要求通常是找到flag結(jié)合已知信息構(gòu)造最終的注入語(yǔ)句。目標(biāo)是什么是flag表中的flag字段還是users表中的admin密碼題目描述往往有提示。有多少個(gè)回顯位使用order by子句來(lái)猜測(cè)查詢結(jié)果的列數(shù)直到報(bào)錯(cuò)。例如id1‘ order by 5 --不報(bào)錯(cuò)order by 6報(bào)錯(cuò)說(shuō)明有5列。哪幾列可以顯示使用union select 1,2,3,4,5 --這樣的語(yǔ)句看頁(yè)面上哪些數(shù)字被顯示出來(lái)這些位置就是我們可以用來(lái)輸出查詢結(jié)果的位置。只有系統(tǒng)性地回答完這四個(gè)問(wèn)題你的注入攻擊才是有的放矢的。下面我們就深入到最常見(jiàn)的幾種注入技術(shù)中看看具體如何操作。4. 聯(lián)合查詢注入當(dāng)頁(yè)面直接“告訴”你答案這是最“幸?!钡淖⑷腩愋?。通常發(fā)生在數(shù)據(jù)查詢結(jié)果會(huì)直接顯示在網(wǎng)頁(yè)上的場(chǎng)景比如新聞詳情頁(yè)、用戶信息頁(yè)。核心原理利用SQL的UNION操作符將我們精心構(gòu)造的查詢語(yǔ)句的結(jié)果附加到原始查詢結(jié)果之后并一起顯示在頁(yè)面上。完整攻擊鏈?zhǔn)纠?假設(shè)存在一個(gè)漏洞URLhttp://target.com/news.php?id1判斷注入點(diǎn)與類型news.php?id1‘頁(yè)面可能報(bào)錯(cuò)提示SQL語(yǔ)法錯(cuò)誤說(shuō)明是字符型注入。news.php?id1 and 11頁(yè)面正常。news.php?id1 and 12頁(yè)面異常新聞內(nèi)容消失。確認(rèn)存在注入。判斷列數(shù)news.php?id1‘ order by 1 --正常news.php?id1‘ order by 2 --正常news.php?id1‘ order by 3 --正常news.php?id1‘ order by 4 --報(bào)錯(cuò) 結(jié)論原始查詢返回3列。探測(cè)回顯點(diǎn)news.php?id1‘ union select 1,2,3 --觀察頁(yè)面發(fā)現(xiàn)原本顯示新聞標(biāo)題的地方變成了數(shù)字“2”顯示新聞內(nèi)容的地方變成了數(shù)字“3”。這說(shuō)明第2和第3列是回顯位。獲取關(guān)鍵信息利用回顯位查詢數(shù)據(jù)庫(kù)信息news.php?id1‘ union select 1, database(), version() --在2、3號(hào)位顯示當(dāng)前數(shù)據(jù)庫(kù)名和版本。news.php?id1‘ union select 1, table_name, 3 from information_schema.tables where table_schemadatabase() --爆出當(dāng)前數(shù)據(jù)庫(kù)的所有表名。MySQL假設(shè)發(fā)現(xiàn)一個(gè)名為flag的表。爆flag表的結(jié)構(gòu)和內(nèi)容news.php?id1‘ union select 1, column_name, 3 from information_schema.columns where table_name‘flag‘ --爆出flag表的列名假設(shè)為id,value。news.php?id1‘ union select 1, id, value from flag --最終flag的內(nèi)容就會(huì)顯示在頁(yè)面上了。避坑指南UNION查詢有一個(gè)硬性要求前后兩個(gè)SELECT語(yǔ)句的列數(shù)必須相同。這就是為什么第二步“判斷列數(shù)”如此關(guān)鍵。如果列數(shù)不對(duì)整個(gè)語(yǔ)句會(huì)報(bào)錯(cuò)。此外UNION通常要求前后查詢的列數(shù)據(jù)類型也兼容但在CTF中用數(shù)字或字符串去占位通常都能混過(guò)去。5. 盲注在黑暗中“摸索”flag絕大多數(shù)CTF題目不會(huì)這么“仁慈”。更多時(shí)候你的注入不會(huì)產(chǎn)生任何直接的錯(cuò)誤信息或數(shù)據(jù)回顯。頁(yè)面只有兩種狀態(tài)正常或異常比如404或者一個(gè)通用的錯(cuò)誤頁(yè)面。這就是“盲注”。你需要像一個(gè)偵探通過(guò)詢問(wèn)“是或否”的問(wèn)題從應(yīng)用程序的反饋中一點(diǎn)點(diǎn)擠出信息。盲注主要分為兩種布爾盲注和時(shí)間盲注。5.1 布爾盲注玩一場(chǎng)“猜猜看”游戲原理通過(guò)構(gòu)造一個(gè)布爾條件真或假的SQL語(yǔ)句根據(jù)頁(yè)面返回內(nèi)容是否“正?!眮?lái)判斷條件是否成立。經(jīng)典場(chǎng)景一個(gè)搜索功能輸入存在注入。當(dāng)搜索到結(jié)果時(shí)頁(yè)面會(huì)顯示“找到X條結(jié)果”當(dāng)無(wú)結(jié)果時(shí)顯示“未找到”。這就是一個(gè)典型的布爾狀態(tài)。攻擊步驟以猜解數(shù)據(jù)庫(kù)名第一個(gè)字符為例 假設(shè)數(shù)據(jù)庫(kù)名是ctf。猜長(zhǎng)度1‘ and length(database())1 --頁(yè)面正常顯示結(jié)果說(shuō)明長(zhǎng)度大于1。繼續(xù)2,3... 直到3時(shí)頁(yè)面異常說(shuō)明長(zhǎng)度等于3。猜第一個(gè)字符的ASCII碼1‘ and ascii(substr(database(),1,1))100 --頁(yè)面正常說(shuō)明第一個(gè)字符的ASCII碼大于100即字母‘d’之后。繼續(xù)二分法110正常115異常... 最終鎖定ASCII碼為116對(duì)應(yīng)字母‘t’。用同樣的方法猜第二個(gè)、第三個(gè)字符。這個(gè)過(guò)程極其繁瑣必須依賴工具自動(dòng)化。Sqlmap這個(gè)神器就是為此而生。你只需要告訴它一個(gè)存在布爾盲注的URL和一個(gè)判斷真假的“條件”它就能自動(dòng)完成所有猜解工作。 例如在Burp中找到一個(gè)請(qǐng)求保存為req.txt然后運(yùn)行sqlmap -r req.txt --level 3 --risk 1 --batch --dbs--dbs參數(shù)就是讓它去爆出所有數(shù)據(jù)庫(kù)名。之后還可以-D 數(shù)據(jù)庫(kù)名 --tables爆表-T 表名 --columns爆列-C 列名 --dump下載數(shù)據(jù)。心得分享布爾盲注是手工練習(xí)理解原理的絕佳方式但比賽或做題時(shí)一旦確認(rèn)存在布爾盲注請(qǐng)毫不猶豫地使用Sqlmap。時(shí)間是寶貴的把重復(fù)勞動(dòng)交給工具把你的精力留給更復(fù)雜的邏輯分析和繞過(guò)。但務(wù)必理解Sqlmap背后的原理否則當(dāng)工具失效時(shí)比如遇到非常規(guī)的過(guò)濾你將毫無(wú)辦法。5.2 時(shí)間盲注當(dāng)應(yīng)用程序“沉默”時(shí)這是最隱蔽的注入。頁(yè)面無(wú)論你的Payload是對(duì)是錯(cuò)返回的內(nèi)容都一模一樣沒(méi)有任何區(qū)別。布爾盲注失效了。原理我們讓數(shù)據(jù)庫(kù)“忙”一會(huì)兒。通過(guò)構(gòu)造一個(gè)條件如果為真就執(zhí)行一個(gè)耗時(shí)的操作如sleep(2)如果為假則立即返回。通過(guò)測(cè)量頁(yè)面響應(yīng)時(shí)間的長(zhǎng)短來(lái)判斷條件真假。攻擊步驟同樣以猜數(shù)據(jù)庫(kù)名第一個(gè)字符為例數(shù)據(jù)庫(kù)為MySQL猜長(zhǎng)度1‘ and if(length(database())3, sleep(2), 1) --如果頁(yè)面響應(yīng)延遲了大約2秒說(shuō)明數(shù)據(jù)庫(kù)名長(zhǎng)度等于3。猜字符1‘ and if(ascii(substr(database(),1,1))116, sleep(2), 1) --如果延遲說(shuō)明第一個(gè)字符是‘t’。工具使用時(shí)間盲注更是離不開(kāi)自動(dòng)化。Sqlmap同樣支持需要指定--techniqueT時(shí)間盲注技術(shù)和--time-sec2定義睡眠時(shí)間。sqlmap -r req.txt --techniqueT --time-sec2 --batch --dbs關(guān)鍵技巧時(shí)間盲注的準(zhǔn)確性受網(wǎng)絡(luò)波動(dòng)影響很大。在本地靶場(chǎng)測(cè)試沒(méi)問(wèn)題但打遠(yuǎn)程比賽時(shí)網(wǎng)絡(luò)延遲可能導(dǎo)致判斷失誤。因此設(shè)置一個(gè)合理的sleep時(shí)間至關(guān)重要通常2-5秒比較穩(wěn)妥。另外可以多次請(qǐng)求取平均值以減少偶然誤差。Sqlmap內(nèi)部有重試和超時(shí)機(jī)制比自己寫腳本要可靠得多。6. 繞過(guò)過(guò)濾與WAF和開(kāi)發(fā)者的“斗智斗勇”CTF題目的精華和難點(diǎn)往往在于各種過(guò)濾和限制。直接輸入標(biāo)準(zhǔn)Payload會(huì)觸發(fā)防護(hù)WAF或被后端代碼過(guò)濾掉。這時(shí)就需要“繞過(guò)”。6.1 常見(jiàn)過(guò)濾與繞過(guò)手法被過(guò)濾項(xiàng)常見(jiàn)繞過(guò)手法原理與示例空格使用注釋符/**/、括號(hào)()、制表符%09、換行符%0aunion/**/select或union(select)關(guān)鍵詞select, union, or, and大小寫混合SeLeCt雙寫繞過(guò)selselectect過(guò)濾函數(shù)只刪除一次select等價(jià)替換引號(hào)如果過(guò)濾了單引號(hào)但需要字符串參數(shù)可使用十六進(jìn)制表示字符串。where table_name‘users‘可變?yōu)閣here table_name0x7573657273注釋符--, #利用邏輯閉合而不使用注釋。字符型注入‘ or ‘1‘‘1代替‘ or 11 --等號(hào)使用like,rlike,regexp或不等于的否定形式?!?or 1 like 1猜解時(shí)substr(database(),1,1) like ‘t‘內(nèi)聯(lián)注釋利用MySQL特有的/*!...*/語(yǔ)法其中的代碼只有在特定版本以上的MySQL才會(huì)執(zhí)行。/*!50000union*/ select可以用來(lái)繞過(guò)一些簡(jiǎn)單的關(guān)鍵詞檢測(cè)。6.2 實(shí)戰(zhàn)中的組合拳以一道經(jīng)典CTF題為例假設(shè)題目過(guò)濾了所有空格和union、select關(guān)鍵詞我們?nèi)绾文玫綌?shù)據(jù)信息收集id1‘||‘1‘‘1頁(yè)面正常id1‘||‘1‘‘2頁(yè)面異常確認(rèn)布爾盲注存在。繞過(guò)關(guān)鍵詞使用雙寫注釋符繞過(guò)。union寫成ununionionselect寫成selselectect。但空格也被過(guò)濾了所以用/**/連接。構(gòu)造Payload我們需要猜解數(shù)據(jù)。但substr、ascii這些函數(shù)名可能也被過(guò)濾??梢韵葴y(cè)試id1‘||length(database())1||‘1‘‘1。這里用||代替or并且沒(méi)有使用注釋符而是通過(guò)||‘1‘‘1來(lái)保證整個(gè)語(yǔ)句語(yǔ)法正確。自動(dòng)化這種復(fù)雜的過(guò)濾手工會(huì)累死??梢跃帉慞ython腳本或者更高效地使用Sqlmap的tamper腳本。Sqlmap自帶很多tamper腳本如space2comment.py用/**/替換空格也可以自己編寫。通過(guò)--tamper參數(shù)指定Sqlmap會(huì)在發(fā)送Payload前自動(dòng)進(jìn)行編碼和變形。經(jīng)驗(yàn)之談繞過(guò)的最高境界是理解后端過(guò)濾的邏輯。它是簡(jiǎn)單的字符串替換是正則表達(dá)式匹配還是調(diào)用了某些安全函數(shù)通過(guò)FUZZ模糊測(cè)試輸入各種變形Payload觀察響應(yīng)可以反推出過(guò)濾規(guī)則。例如輸入SELSELECTECT如果返回正常但SELECT被攔截那很可能就是簡(jiǎn)單的字符串刪除過(guò)濾雙寫繞過(guò)就有效。7. 不止于SELECT堆疊注入與二次注入在CTF中有時(shí)你會(huì)遇到更“強(qiáng)大”的注入點(diǎn)能讓你執(zhí)行任意SQL語(yǔ)句而不僅僅是查詢。7.1 堆疊注入原理利用數(shù)據(jù)庫(kù)支持多語(yǔ)句執(zhí)行的特性在注入點(diǎn)后使用分號(hào);分隔執(zhí)行多條SQL命令。場(chǎng)景PHP中的mysqli_multi_query()函數(shù)或PDO的某些配置下可能允許。Payload示例id1‘; update users set password‘hacked‘ where username‘a(chǎn)dmin‘; --危害可以直接增刪改數(shù)據(jù)危害極大。CTF中的應(yīng)用題目可能讓你通過(guò)堆疊注入創(chuàng)建一個(gè)新表或者向某個(gè)表插入包含flag的數(shù)據(jù)然后再通過(guò)常規(guī)查詢?nèi)プx取。7.2 二次注入原理這是一種“存儲(chǔ)型”的注入。應(yīng)用程序在第一次輸入時(shí)可能對(duì)數(shù)據(jù)進(jìn)行了安全的轉(zhuǎn)義或過(guò)濾并將其存入數(shù)據(jù)庫(kù)。但當(dāng)程序后續(xù)從數(shù)據(jù)庫(kù)中取出這些數(shù)據(jù)并不加處理地再次用于SQL查詢時(shí)注入就發(fā)生了。攻擊流程注冊(cè)一個(gè)用戶名包含惡意Payload的用戶例如admin‘ --。注冊(cè)時(shí)程序可能對(duì)單引號(hào)進(jìn)行了轉(zhuǎn)義變成admin\‘ --存入數(shù)據(jù)庫(kù)。后續(xù)有一個(gè)“修改密碼”的功能它會(huì)執(zhí)行這樣的SQLUPDATE users SET password‘新密碼‘ WHERE username‘$username‘。當(dāng)從數(shù)據(jù)庫(kù)取出用戶名admin‘ --并拼接到SQL中時(shí)語(yǔ)句變?yōu)閁PDATE users SET password‘新密碼‘ WHERE username‘a(chǎn)dmin‘ -- ‘。注釋符--使得后面的單引號(hào)被注釋這條語(yǔ)句實(shí)際上修改了admin用戶的密碼而不是你注冊(cè)的那個(gè)惡意用戶。CTF考點(diǎn)這類題目通常需要你仔細(xì)梳理整個(gè)應(yīng)用邏輯找到“輸入-存儲(chǔ)-再調(diào)用”的完整鏈條非常考驗(yàn)邏輯思維能力。8. 從解題到精通構(gòu)建你的知識(shí)體系與實(shí)戰(zhàn)資源SQL注入的學(xué)習(xí)是一個(gè)螺旋上升的過(guò)程。掌握了基礎(chǔ)技巧后如何精進(jìn)系統(tǒng)化學(xué)習(xí)找一本經(jīng)典的Web安全書籍如《白帽子講Web安全》閱讀其中關(guān)于SQL注入的章節(jié)建立完整的知識(shí)體系了解原理背后的數(shù)據(jù)庫(kù)原理和HTTP協(xié)議。刷題平臺(tái)CTFshow分區(qū)明確從入門到進(jìn)階。攻防世界題目質(zhì)量高有歷年各大CTF賽事的真題。HackTheBox雖然偏滲透測(cè)試但其中的一些Web挑戰(zhàn)題對(duì)SQL注入的考察非常深入。SQLi-Labs如前所述專項(xiàng)突破神器。關(guān)注變種與前沿隨著ORM框架、預(yù)編譯語(yǔ)句的普及經(jīng)典注入在減少但新的利用方式在出現(xiàn)。例如NoSQL注入針對(duì)MongoDB等數(shù)據(jù)庫(kù)語(yǔ)法與SQL完全不同。SQL注入與框架特性結(jié)合例如在Spring MVC中如果錯(cuò)誤地使用like查詢拼接依然可能導(dǎo)致注入。繞過(guò)預(yù)編譯極其罕見(jiàn)且困難通常與ORM框架的復(fù)雜使用方式或特定數(shù)據(jù)庫(kù)特性有關(guān)。理解防御真正的高手必須懂得如何防御。學(xué)習(xí)使用參數(shù)化查詢預(yù)編譯語(yǔ)句、對(duì)輸入進(jìn)行嚴(yán)格的白名單校驗(yàn)、使用最小權(quán)限原則配置數(shù)據(jù)庫(kù)賬戶。看看DVWA的“Impossible”級(jí)別代碼就是最好的防御范例。最后我想說(shuō)CTF中的SQL注入是一個(gè)完美的起點(diǎn)但它只是一個(gè)起點(diǎn)。它訓(xùn)練了你對(duì)輸入輸出的敏感度、對(duì)系統(tǒng)邏輯的分析能力以及耐心。當(dāng)你能夠不依賴工具手工完成一道復(fù)雜的盲注題目時(shí)你已經(jīng)具備了安全研究的基本素養(yǎng)。接下來(lái)你可以帶著這種思維去探索更廣闊的漏洞世界比如文件包含、反序列化、模板注入等等。這條路沒(méi)有盡頭但每一步都充滿了解謎的樂(lè)趣。