一周刷题记录 | WebMisc
文章目錄
- BUU
- 0x00:[WesternCTF2018]shrine
- 0x01:[網(wǎng)鼎杯 2020 玄武組]SSRFMe
- HECTF
- 0x00 ezphp
- 0x01:ssrfme
- 0x03:簽到
- 2020 安洵杯
- 0x00:Bash
- 0x01:王牌特工
BUU
每天一道題,沖沖沖!
0x00:[WesternCTF2018]shrine
首頁便給了一段flask代碼,簡單分析一下
import flask import osapp = flask.Flask(__name__)app.config['FLAG'] = os.environ.pop('FLAG')@app.route('/') def index():return open(__file__).read()@app.route('/shrine/<path:shrine>') def shrine(shrine):def safe_jinja(s):s = s.replace('(', '').replace(')', '')blacklist = ['config', 'self']return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + sreturn flask.render_template_string(safe_jinja(shrine))if __name__ == '__main__':app.run(debug=True)發(fā)現(xiàn)這一段代碼
app.config['FLAG'] = os.environ.pop('FLAG') #pop() 函數(shù)用于移除列表中的一個(gè)元素(默認(rèn)最后一個(gè)元素),并且返回該元素的值。
意思便是該題將FLAG存儲到了配置變量中,但下面的代碼過濾了config以及()
這個(gè)題考察的是SSTI,那下面就要想辦法去使用config查看所有應(yīng)用程序的配置值(FLAG值應(yīng)該包含在其中),需要構(gòu)造一個(gè)和config作用相同的payload,可以使用flask兩個(gè)內(nèi)置函數(shù)進(jìn)行構(gòu)造
先尋找一下全部全局變量
{{url_for.__globals__}} {{get_flashed_messages.__globals__}}
發(fā)現(xiàn)有current_app全局變量,查看一下config
0x01:[網(wǎng)鼎杯 2020 玄武組]SSRFMe
<?php function check_inner_ip($url) {$match_result=preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',$url);if (!$match_result){die('url fomat error');}try{$url_parse=parse_url($url);}catch(Exception $e){die('url fomat error');return false;}$hostname=$url_parse['host'];$ip=gethostbyname($hostname);$int_ip=ip2long($ip);return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16; }function safe_request_url($url) {if (check_inner_ip($url)){echo $url.' is inner ip';}else{$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_HEADER, 0);$output = curl_exec($ch);$result_info = curl_getinfo($ch);if ($result_info['redirect_url']){safe_request_url($result_info['redirect_url']);}curl_close($ch);var_dump($output);}} if(isset($_GET['url'])){$url = $_GET['url'];if(!empty($url)){safe_request_url($url);} } else{highlight_file(__FILE__); } // Please visit hint.php locally. ?>這么長的代碼,拆開來看,先看一下check_inner_ip函數(shù)
輸入的需要匹配到http|https|gopher|dict,下面了解這幾個(gè)函數(shù),就清楚這段代碼所要表達(dá)的意思了
- parse_url:解析 URL,返回其組成部分
- gethostbyname:返回主機(jī)名對應(yīng)的 IPv4地址
- ip2long:將 IPV4 的字符串互聯(lián)網(wǎng)協(xié)議轉(zhuǎn)換成長整型數(shù)字
再來查看safe_request_url函數(shù)要表達(dá)的意思,先判斷是否是內(nèi)網(wǎng)IP,如果不是,再跳轉(zhuǎn)到下面。
- curl_init — 初始化一個(gè)cURL會話
- curl_setopt — 設(shè)置一個(gè)cURL傳輸選項(xiàng)
- curl_exec — 執(zhí)行一個(gè)cURL會話
- curl_getinfo — 獲取一個(gè)cURL連接資源句柄的信息
也是一種PHP的請求方式,那這存在什么漏洞那?
可以看篇文章
https://www.anquanke.com/post/id/86527
這個(gè)代碼出現(xiàn)漏洞原因便在于,同時(shí)用了cURL和parse_url
所有的問題,幾乎都是由URL解析器和請求函數(shù)的不一致造成的,即使有具體的規(guī)定,但是不同的編程語言仍然使用他們自己的實(shí)現(xiàn)
在cURL作為請求的實(shí)施者時(shí),它最終將evil.com:80作為了目標(biāo)
而其他的幾種URL解析器則得到了不一樣的結(jié)果,則產(chǎn)生了不一致。
當(dāng)他們被一起使用時(shí),可以被利用的有如下的幾種組合
所以可以就構(gòu)造payload,利用cURL請求外網(wǎng),利用parse_url請求內(nèi)網(wǎng)信息
0.0.0.0代表本機(jī)ipv4的所有地址,使用ip2long函數(shù)處理后也是0,因此可以繞過去check_inner_ip函數(shù)的檢測。
繞過去之后便發(fā)現(xiàn)這一段代碼
得到redis的密碼是root,這道題考察的是ssrf+redis getshell,但之前接觸這方面的題過于少了,所以到這里是一點(diǎn)思路都沒有
看了師傅們的WP,遇到ssrf+redis getshell這種的,考察一般都是以下幾種姿勢:
- 可寫webshell
- 寫ssh公鑰
- 寫crontab反彈shell(僅限centos)
- 主從復(fù)制RCE
這道題看師傅們的WP,用的方法都是主從復(fù)制RCE,什么是主從復(fù)制那?
主從復(fù)制,是指將一臺Redis服務(wù)器的數(shù)據(jù),復(fù)制到其他的Redis服務(wù)器。前者稱為主節(jié)點(diǎn)(master),后者稱為從節(jié)點(diǎn)(slave);數(shù)據(jù)的復(fù)制是單向的,只能由主節(jié)點(diǎn)到從節(jié)點(diǎn)。
在redis4.0版本以上,可以進(jìn)行主從復(fù)制,主從復(fù)制是為了備份文件,即主機(jī)復(fù)制寫,從機(jī)負(fù)責(zé)讀。思路就是開啟惡意服務(wù),讓靶機(jī)redis認(rèn)為此為redis服務(wù)器,利用主從復(fù)制,將惡意構(gòu)造的exp.so文件加載到redis之中,從而實(shí)現(xiàn)getshll或命令執(zhí)行
https://github.com/xmsec/redis-ssrf
https://github.com/n0b0dyCN/redis-rogue-server
要進(jìn)行主從復(fù)制RCE,就需要利用到這兩個(gè)工具,第一個(gè)用于生成payload,也可以啟動惡意服務(wù),第二個(gè)主要是exp.so。注意需要將第二個(gè)工具exp.so導(dǎo)入到第一個(gè)工具下,也就是和rogue-server.py同目錄,這里先開啟一下rogue-server.py 用于偽裝為主redis,它開啟的端口為6666
修改ssrf-redis.py
運(yùn)行一下
生成了payload,但無法利用
看了師傅們的WP,就手動去構(gòu)造吧,然后再進(jìn)行二次url編碼(因?yàn)橛玫搅薱url)
通過這道題學(xué)到了很多東西,ssrf+redis的考法還有很多種,會在另一篇博客中專門總結(jié)一下。
參考博客
https://www.jianshu.com/p/a940731cddaf
HECTF
0x00 ezphp
第一個(gè)if條件,md5強(qiáng)類型,沒有強(qiáng)制限制類型,所有用數(shù)組就可以
strtr() 函數(shù)轉(zhuǎn)換字符串中特定的字符。
自己本地測試一下就知道了
第一個(gè)if($md5_1 != $md5_2)不能使用hash弱類型比較,經(jīng)過strtr() 函數(shù)替換之后,再使用hash弱類型繞過,既然這個(gè)函數(shù)可以將md5中出現(xiàn)的cxhp給替換成0123,第一個(gè)參數(shù)找一個(gè)數(shù)字(必須為全數(shù)字),md5加密后只要是ce開頭的即可
payload:
http://121.196.32.184:8081/?param1[]=123¶m2[]=111&str1=2120624&str2=QNKCDZO
這里在寫腳本找ce開頭的數(shù)字時(shí)挺有趣的
md5加密之后只可能含有以下a、b、c、d、e、f這個(gè)幾個(gè)字符
在寫腳本的時(shí)候,一開始只認(rèn)為只要開頭是0e即可,但是測試發(fā)現(xiàn)行不通,明明也是0e開頭,為什么不相等那?如:
并沒有出現(xiàn)我們想要的flag,一開始以為是位數(shù)的問題,結(jié)果不是,觀察了通用的Hash 比較缺陷,有一個(gè)共同的特征
后面都是數(shù)字,不包含字母,才能使用科學(xué)計(jì)數(shù)法進(jìn)行弱類型比較
0x01:ssrfme
正則表達(dá)式限制我們不能使用SSRF file_get_content函數(shù)的黑魔法了,那只能按照http或https協(xié)議來,然后下面有一個(gè)異常處理代碼,如果發(fā)生異常則返回flase,恰好最后一段代碼有一個(gè)!,所以我們只要讓代碼異常拋出即可利用函數(shù)讀取flag。
但這個(gè)異常不知道要如何利用,往下面看發(fā)現(xiàn)可以從這段代碼中得到flase
只要滿足傳入的地址經(jīng)過ip2long函數(shù)處理后和前面不相等即可
簡單了解這幾個(gè)函數(shù)的作用:
- parse_url:解析 URL,返回其組成部分
- gethostbyname:返回主機(jī)名對應(yīng)的 IPv4地址
- ip2long:將 IPV4 的字符串互聯(lián)網(wǎng)協(xié)議轉(zhuǎn)換成長整型數(shù)字
0.0.0.0代表本機(jī)ipv4的所有地址,使用ip2long函數(shù)處理后也是0,便可以使用這個(gè)進(jìn)行讀取flag
payload:
?url=http://0.0.0.0/flag.php0x03:簽到
源代碼給出手機(jī)號,下面就是爆破驗(yàn)證碼
得到驗(yàn)證碼之后重置密碼,登陸即可獲取flag
2020 安洵杯
0x00:Bash
代碼也很簡單,命令執(zhí)行,但是構(gòu)造payload只能使用這幾個(gè)${#}\\(<)\去構(gòu)造,還是做題少,之前見的無字母數(shù)字構(gòu)造webshell的都不行,只能看官方的WP。
先了解幾個(gè)Shell符號
$# 的意思是參數(shù)的個(gè)數(shù),這道題沒有其余的參數(shù)所以會是 0
stdin是標(biāo)準(zhǔn)輸入,一般指鍵盤輸入到緩沖區(qū)里的東西
<<< 的用途是將任意字符串交由前面的指令執(zhí)行
(())表示整數(shù)擴(kuò)展,只是執(zhí)行,并不會返回值,$$ 代表的是目前的 pid ,pid 會 > 0 所以可以得到 1,${##} 也可以得到1
<<雙小于號,用來將后繼的內(nèi)容重定向到左側(cè)命令的stdin中
將 bbb 以二進(jìn)制制轉(zhuǎn)換成數(shù)字,其中2#表示二進(jìn)制
命令替換: $(command)
算術(shù)擴(kuò)展: $((arithmetic))
stdin重定向: command < file
stdin文字重定向: command <<< text
可變的字符串長度: ${#variable}
bash的參數(shù)數(shù)量: $#
bash進(jìn)程ID: $$
Linux下高效編寫Shell——shell特殊字符匯總
因?yàn)閎ash 可以用 $'\ooo' 的形式來表達(dá)任意字節(jié)(ooo 是字節(jié)轉(zhuǎn)ascii 的八進(jìn)制),所以可以執(zhí)行任意命令
所以思路就是構(gòu)造二進(jìn)制,然后通過ASCII碼轉(zhuǎn)化得到所有字母,比如:
所以構(gòu)造payload
#通過2進(jìn)制得到所有的數(shù)字,八進(jìn)制可以執(zhí)行命令,所以得到七個(gè)數(shù)字即可 n = dict() n[0] = '$#' n[1] = '${##}' n[2] = '$((${##}<<${##}))' n[3] = '$(($((${##}<<${##}))#${##}${##}))' n[4] = '$(($((${##}<<${##}))<<${##}))' n[5] = '$(($((${##}<<${##}))#${##}$#${##}))' n[6] = '$(($((${##}<<${##}))#${##}${##}$#))' n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))'因?yàn)檫@道題0也在白名單中,所以可以將$#直接替換為0也可以,但還有一個(gè)問題,仔細(xì)看前面舉的$'\154'這個(gè)例子,如果bash直接解析的話是l,但是第一次解析的話只是數(shù)字
所以轉(zhuǎn)換成數(shù)字之后就需要用到 <<< 來重定向了,但是一層不夠,只用一層會出現(xiàn) bash: $'\154': command not found 這樣的報(bào)錯(cuò),bash一次解析只能解析到成數(shù)字,需要第二次解析。需要給原先的命令添加轉(zhuǎn)義字符
無命令回顯就用最常見的方法,反彈shell或者是盲注,記錄一下師傅的腳本
0x01:王牌特工
第一眼看到的是flagbox,然后就binwalk一下,得到一個(gè)key值,使用VeraCrypt掛載一下硬盤
但是是假的,回過頭看一下發(fā)現(xiàn)還有coolboy.swp沒有進(jìn)行分析,應(yīng)該是隱藏在這里
先用 fsstat findme 查看鏡像信息
然后用 ext3grep --inode 2 findme 查看文件目錄
接著用 ext3grep --restore-file .coolboy.swp findme 恢復(fù)指定的文件
但是是空的,使用vim -r RESTORED_FILES/.coolboy.swp 恢復(fù)它的內(nèi)容。
得到真正的key值,再重新掛載flagbox,即可得到flag
總結(jié)
以上是生活随笔為你收集整理的一周刷题记录 | WebMisc的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UNCTF2020 | Web Wp
- 下一篇: 第六届上海市大学生网络安全大赛 | Wp