渗透测试之通过代码审计打点
文章來(lái)源: 酒仙橋六號(hào)部隊(duì)
前言
代碼審計(jì)(Code Audit)顧名思義就是通過(guò)閱讀源代碼,從中找出程序源代碼中存在的
缺陷或安全隱患,提前發(fā)現(xiàn)并解決風(fēng)險(xiǎn),這在甲方的SDL建設(shè)中是很重要的一環(huán)。而在滲透測(cè)試中,可以通過(guò)代碼審計(jì)挖掘程序漏洞,快速利用漏洞進(jìn)行攻擊達(dá)成目標(biāo)。
?
審計(jì)思路
常見(jiàn)的審計(jì)思路有:
?
1.尋找敏感功能點(diǎn),通讀功能點(diǎn)代碼;
? 優(yōu)點(diǎn): 精準(zhǔn)定向挖掘,利用程度高;
? 缺點(diǎn):命名不規(guī)范的代碼容易被忽略,導(dǎo)致失去先機(jī)。
2.根據(jù)敏感關(guān)鍵字回溯參數(shù)傳遞過(guò)程;
? 優(yōu)點(diǎn):通過(guò)搜索敏感關(guān)鍵字可快速定位可能存在的漏洞,可定向挖掘,高效、高質(zhì)量;
? 缺點(diǎn):對(duì)程序整體架構(gòu)了解不夠深入,在漏洞定位時(shí)比較耗時(shí),邏輯漏洞覆蓋不到。
3.直接通讀全文代碼;
? 優(yōu)點(diǎn):對(duì)整體架構(gòu)熟悉,了解程序的數(shù)據(jù)流處理、配置文件、過(guò)濾函數(shù)等;
? 缺點(diǎn):耗時(shí)長(zhǎng),需要足夠的時(shí)間熟悉整體架構(gòu)。
審計(jì)方法
按照是否使用(半)自動(dòng)化工具分有工具掃描、人工審計(jì)和兩者相結(jié)合的幾種審計(jì)方式,筆者比較喜歡硬剛,畢竟正常挖業(yè)務(wù)層面漏洞沒(méi)有那么復(fù)雜,不太需要對(duì)底層的一些特性了解的很清楚。
按照數(shù)據(jù)流向可分為正向?qū)徲?jì)和逆向?qū)徲?jì),正向?qū)徲?jì)即從功能入口點(diǎn)進(jìn)行跟蹤,一直到數(shù)據(jù)流處理結(jié)束;逆向?qū)徲?jì)即現(xiàn)根據(jù)一些關(guān)鍵詞搜索,定位到可能存在風(fēng)險(xiǎn)的關(guān)鍵詞/函數(shù),再反推到功能入口,看整個(gè)處理過(guò)程是否存在漏洞。
成功案例
案例一:一個(gè)任意文件下載漏洞引起的代碼審計(jì)
在一次授權(quán)測(cè)試中,找到一處任意文件下載漏洞,正常思路先下載網(wǎng)站的配置文件,看看數(shù)據(jù)庫(kù)是否可以外聯(lián)。
不幸的是不可以外聯(lián)(其實(shí)現(xiàn)在能外聯(lián)的也很少了),幸運(yùn)的是在配置文件中收集到了一個(gè)域用戶,這是意外之喜。
接著下載Download.aspx文件看看內(nèi)容:
我們知道, .net是編譯型語(yǔ)言,在aspx中一般是沒(méi)有服務(wù)代碼的,這里看到使用了Inherits來(lái)繼承后端代碼。
Inherits是啥?
MSDN官方解釋:定義供頁(yè)繼承的代碼隱藏類。它可以是從Page類派生的任何類。此特性與CodeFile
特性一起使用,后者包含指向代碼隱藏類的源文件的路徑。
通俗一點(diǎn)就是代碼都在這個(gè)Inherits指向的dll中了,那么我們下載到dll文件,就可以對(duì)后端代碼進(jìn)行一波窺探了,于是構(gòu)造下載XXXXXX.Web.dll,文件下載到本地后,IL Spy打開(kāi)就是一頓肉眼觀察。
大致看了一下目錄,有Upload字樣,優(yōu)先級(jí)直線上升,先進(jìn)去看看:
public void uploadFile() {string formStringParamValue = SWFUrlOper.GetFormStringParamValue("path");string formStringParamValue2 = SWFUrlOper.GetFormStringParamValue("fn");bool flag = SWFUrlOper.GetFormStringParamValue("small").ToLower() == "true";......string[] array = new string[]{"jpg","gif","png","bmp"};string formStringParamValue3 = SWFUrlOper.GetFormStringParamValue("data");try {System.Web.HttpPostedFile httpPostedFile = base.Request.Files["Filedata"];string b = string.Empty;string text = string.Empty;if (httpPostedFile.ContentLength > 0) {text = httpPostedFile.FileName;if (text.IndexOf(".") != -1) {b = text.Substring(text.LastIndexOf(".") + 1, text.Length - text.LastIndexOf(".") - 1).ToLower();}SWFUploadFile sWFUploadFile = new SWFUploadFile();if (flag) {sWFUploadFile.set_SmallPic(true);sWFUploadFile.set_MaxWith((formIntParamValue == 0) ? sWFUploadFile.get_MaxWith() : formIntParamValue);sWFUploadFile.set_MaxHeight((formIntParamValue2 == 0) ? sWFUploadFile.get_MaxHeight() : formIntParamValue2);}sWFUploadFile.set_IsWaterMark(isWaterMark);int num = 0;string text2 = sWFUploadFile.SaveFile(httpPostedFile, formStringParamValue, formStringParamValue2, ref num);...}38行進(jìn)行了文件保存,之前沒(méi)有對(duì)文件的內(nèi)容、后綴等有任何過(guò)濾,開(kāi)開(kāi)心心挖到任意文件上傳。二話不說(shuō)本地構(gòu)造上傳個(gè)shell。
<form name="form" method="post" action="http://xxxx.com/cms/SWFUpload.aspx" enctype="multipart/form-data" ><input type="file" name="Filedata"><input type="submit" name="Submit" value="upload" > </form>?
假如這里代碼被混淆的話,可以使用de4dot進(jìn)行反混淆,de4dot支持10幾種混淆方式的反混淆:
Dotfuscator
.NET Reactor
Xenocode
CryptoObfuscator
SmartAssembly
......
比如使用Dotfuscator混淆過(guò)的DLL是這樣的:
使用de4dot反混淆:
CMD命令行執(zhí)行: de4dot.exe ADD.dll
看下效果:
代碼已經(jīng)基本恢復(fù)到可讀狀態(tài)了,其他高級(jí)用戶請(qǐng)參考github上的介紹。
案例二:某個(gè)開(kāi)源系統(tǒng)的代碼審計(jì)
授權(quán)滲透時(shí)發(fā)現(xiàn)只有一個(gè)登錄框,遇到這種情況一般只能拼字典進(jìn)行爆破了,還好客戶使用的是一套開(kāi)源系統(tǒng)二次開(kāi)發(fā),可以down到代碼進(jìn)行分析一波。
拿到代碼看了一下結(jié)構(gòu),是thinkphp的二開(kāi),遵循MVC模型代碼那是一個(gè)層次分明。
因?yàn)槟繕?biāo)只有登錄框,所以這里我關(guān)注的重點(diǎn)除了文件上傳、SQL注入,又多了一個(gè)繞過(guò)登陸的想法了,no代碼no嗶嗶~(yú)~
Upload太刺眼了,忍不住進(jìn)去分析一下。
class UploadController extends ComController {......private function saveimg($file) {$uptypes = array('image/jpeg','image/jpg','image/jpeg','image/png','image/pjpeg','image/gif','image/bmp','image/x-png');$max_file_size=2000000; //上傳文件大小限制,單位BYTE$destination_folder = 'Public/attached/'.date('Ym').'/'; //上傳文件路徑if ($max_file_size < $file["size"]) {echo "文件太大!";return null;}if (!in_array($file["type"], $uptypes)) {echo "文件類型不符!".$file["type"];return null;}if (!file_exists($destination_folder)) {mkdir($destination_folder);}$filename = $file["tmp_name"];$image_size = getimagessize($filename);$pinfo = pathinfo($file["name"]);$ftype = $pinfo['extension'];$destination = $destination_folder.time().".".$ftype;if (file_exists($destination) && $overwrite != true) {echo "同名文件已經(jīng)存在了";return null;}if (!move_uploaded_file($filename, $destination)) {return null;}return "/".$destination;}......只對(duì)文件MIME類型進(jìn)行了檢測(cè),做安全的都愛(ài)這樣的開(kāi)發(fā)工程師,比心~
不過(guò)這里繼承了ComController,里面有身份認(rèn)證,不能直接getshell了...嗚嗚嗚,還要突破登錄后臺(tái)才行。
跟進(jìn)ComController看下認(rèn)證檢查過(guò)程。
class ComController extends BaseController {public $USER;public function _initialize() {C(setting());$user = cookie('user');$this->USER = $user;$url = U("login/index");if (!$user) {header("Location: {$url}");exit(0);}$Auth = new Auth();$allow_controller_name=array('Upload'); //放行控制器名稱$allow_action_name = array(); //放行函數(shù)名稱if (!$Auth->check(CONTROLLER_NAME.'/'.ACTION_NAME, $this->USER['uid'])&&!in_array(CONTROLLER_NAME, $allow_controller_name) && !in_array(ACTION_NAME, $allow_action_name)) {$this->error('沒(méi)有權(quán)限訪問(wèn)本頁(yè)面!');}$user = member(intval($user['uid']));$this->assign('user', $user);嗯,我可能深深愛(ài)上了這個(gè)開(kāi)發(fā)工程師了,從cookie中獲取認(rèn)證信息,并賦值給$user對(duì)象,那么我們就可以操控用戶登錄啦,在配合后臺(tái)的任意文件上傳,美滋滋~
失敗案例
?
總結(jié)
相對(duì)于甲方不同,滲透測(cè)試中代碼審計(jì)更多的是挖掘可利用的漏洞或利用鏈進(jìn)行攻擊,盡可能的獲取更高的權(quán)限為目的。
個(gè)人覺(jué)得滲透測(cè)試時(shí)關(guān)注的漏洞優(yōu)先級(jí):
命令執(zhí)行 > 代碼執(zhí)行 > 文件上傳 > 文件包含 > SQL注入 > 文件下載 > 邏輯漏洞 > SSRF > XSS ....
代碼審計(jì)除了需要了解漏洞的原理、熟悉常見(jiàn)的編程語(yǔ)言、常見(jiàn)的危險(xiǎn)函數(shù)、常見(jiàn)的協(xié)議、滲透技巧外,還需要一些開(kāi)發(fā)調(diào)試工具(IDEA、PHPStrom、PyCharm ...),以上內(nèi)容有不正之處,還請(qǐng)大家斧正。
注:
de4dot項(xiàng)目地址:?
https://github.com/0xd4d/de4dot/
總結(jié)
以上是生活随笔為你收集整理的渗透测试之通过代码审计打点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: <深入剖析Tomcat>摘抄
- 下一篇: 对某bc站的一次渗透测试