2019 De1CTF

admin 2024年8月25日00:49:15评论7 views字数 7424阅读24分44秒阅读模式

SSRF ME

hint:flag is in ./flag.txt

访问靶机,拿到题目源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
#! /usr/bin/env python#encoding=utf-8from flask import Flaskfrom flask import requestimport socketimport hashlibimport urllibimport sysimport osimport jsonreload(sys)sys.setdefaultencoding('latin1')app = Flask(__name__)secert_key = os.urandom(16)class Task:    def __init__(self, action, param, sign, ip):        self.action = action        self.param = param        self.sign = sign        self.sandbox = md5(ip)        if(not os.path.exists(self.sandbox)):          #SandBox For Remote_Addr            os.mkdir(self.sandbox)    def Exec(self):        result = {}        result['code'] = 500        if (self.checkSign()):            if "scan" in self.action:                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')                resp = scan(self.param)                if (resp == "Connection Timeout"):                    result['data'] = resp                else:                    print resp                    tmpfile.write(resp)                    tmpfile.close()                result['code'] = 200            if "read" in self.action:                f = open("./%s/result.txt" % self.sandbox, 'r')                result['code'] = 200                result['data'] = f.read()            if result['code'] == 500:                result['data'] = "Action Error"        else:            result['code'] = 500            result['msg'] = "Sign Error"        return result    def checkSign(self):        if (getSign(self.action, self.param) == self.sign):            return True        else:            return False#generate Sign For Action Scan.@app.route("/geneSign", methods=['GET', 'POST'])def geneSign():    param = urllib.unquote(request.args.get("param", ""))    action = "scan"    return getSign(action, param)@app.route('/De1ta',methods=['GET','POST'])def challenge():    action = urllib.unquote(request.cookies.get("action"))    param = urllib.unquote(request.args.get("param", ""))    sign = urllib.unquote(request.cookies.get("sign"))    ip = request.remote_addr    if(waf(param)):        return "No Hacker!!!!"    task = Task(action, param, sign, ip)    return json.dumps(task.Exec())@app.route('/')def index():    return open("code.txt","r").read()def scan(param):    socket.setdefaulttimeout(1)    try:        return urllib.urlopen(param).read()[:50]    except:        return "Connection Timeout"def getSign(action, param):    return hashlib.md5(secert_key + param + action).hexdigest()def md5(content):    return hashlib.md5(content).hexdigest()def waf(param):    check=param.strip().lower()    if check.startswith("gopher") or check.startswith("file"):        return True    else:        return Falseif __name__ == '__main__':    app.debug = False    app.run(host='0.0.0.0',port=80)

回显flag的地方应该是Exec函数,然后要先过一个判断self.checkSign()

定位到checkSign函数又是一个判断 if(getSign(self.action, self.param) == self.sign)

在定位到getSign函数 return hashlib.md5(secert_key + param + action).hexdigest()

这里会把key,param,action串起来然后md5加密,self.sign是cookie里的,这个可以造,再说,然后是

123456789101112131415161718192021
if (self.checkSign()):            if "scan" in self.action:                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')                resp = scan(self.param)                if (resp == "Connection Timeout"):                    result['data'] = resp                else:                    print resp                    tmpfile.write(resp)                    tmpfile.close()                result['code'] = 200            if "read" in self.action:                f = open("./%s/result.txt" % self.sandbox, 'r')                result['code'] = 200                result['data'] = f.read()            if result['code'] == 500:                result['data'] = "Action Error"        else:            result['code'] = 500            result['msg'] = "Sign Error"        return result

要求scan在action里面,这样子他会创建一个文件,在scan一个{$param}文件,定位到scan函数,

return urllib.urlopen(param).read()[:50],他会打开一个{$param}文件并且只取前50位,所以就打开flag.txt咯,

patam=flag.txt,然后他会把flag.txt的内容写进那个result文件。接着如果read在action里面,他就会打开result文件,并把内容赋值给result,然后输出(就是给你看啦)。

那么目的明确了,往前推就是,action=readscan,然后param=flag.txt,那么为了过检查,sign=MD5(flag.txtreadscan),怎么获得这个呢,有getsign这个函数。怎么回显sign呢?有geneSign()这个函数,geneSign这个函数里的action赋值为scan了,所以我们只需要让param=flag.txtrread,就可以获得MD5(flag.txtreadscan)了。okay,万事俱备。那怎么执行到Exec()函数呢,在/De1ta里的challenge()函数,param可以get。action和sign都是cookie里的。

所以总的步骤:

  1. 访问/geneSign?param=flag.txtread 得到$sign
  2. 访问/De1ta?param=flag.txt 抓包,写入sign=$sign和action=readscan

get flag。

XORZ

加密源码

123456789101112
from itertools import *from data import flag,plainkey=flag.strip("de1ctf{").strip("}")assert(len(key<38))salt="WeAreDe1taTeam"ki=cycle(key)si=cycle(salt)cipher = ''.join([hex(ord(p) ^ ord(next(ki)) ^ ord(next(si)))[2:].zfill(2) for p in plain])print cipher# output:# 49380d773440222d1b421b3060380c3f403c3844791b202651306721135b6229294a3c3222357e766b2f15561b35305e3c3b670e49382c295c6c170553577d3a2b791470406318315d753f03637f2b614a4f2e1c4f21027e227a4122757b446037786a7b0e37635024246d60136f7802543e4d36265c3e035a725c6322700d626b345d1d6464283a016f35714d434124281b607d315f66212d671428026a4f4f79657e34153f3467097e4e135f187a21767f02125b375563517a3742597b6c394e78742c4a725069606576777c314429264f6e330d7530453f22537f5e3034560d22146831456b1b72725f30676d0d5c71617d48753e26667e2f7a334c731c22630a242c7140457a42324629064441036c7e646208630e745531436b7c51743a36674c4f352a5575407b767a5c747176016c0676386e403a2b42356a727a04662b4446375f36265f3f124b724c6e346544706277641025063420016629225b43432428036f29341a2338627c47650b264c477c653a67043e6766152a485c7f33617264780656537e5468143f305f4537722352303c3d4379043d69797e6f3922527b24536e310d653d4c33696c635474637d0326516f745e610d773340306621105a7361654e3e392970687c2e335f3015677d4b3a724a4659767c2f5b7c16055a126820306c14315d6b59224a27311f747f336f4d5974321a22507b22705a226c6d446a37375761423a2b5c29247163046d7e47032244377508300751727126326f117f7a38670c2b23203d4f27046a5c5e1532601126292f577776606f0c6d0126474b2a73737a41316362146e581d7c1228717664091c

解题思路:

加密脚本是salt^key^plain=output

所以逆过来,salt^output=key^plain

已知len(key)<38,

所以先爆破长度,

只要备选的key不是空集即可,

得到可能的长度只有30

然后就可以列出key的每一位的可能值

先随便选一组key异或,然后得到原文是莎翁14行诗

根据原文调整key即可。

脚本如下:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
from itertools import *import reps='1234567890qwertyuiopasdfghjklxcvbnmQWERTYUIOPSDFGHJKLZXCVBNM\'` ;,.'ks='1234567890qwertyuiopasdfghjklxcvbnmQWERTYUIOPSDFGHJKLZXCVBNM'res='1e5d4c055104471c6f234f5501555b5a014e5d001c2a54470555064c443e235b4c0e590356542a130a4242335a47551a590a136f1d5d4d440b0956773613180b5f184015210e4f541c075a47064e5f001e2a4f711844430c473e2413011a100556153d1e4f45061441151901470a196f035b0c4443185b322e130806431d5a072a46385901555c5b550a541c1a2600564d5f054c453e32444c0a434d43182a0b1c540a55415a550a5e1b0f613a5c1f10021e56773a5a0206100852063c4a18581a1d15411d17111b052113460850104c472239564c0755015a13271e0a55553b5a47551a54010e2a06130b5506005a393013180c100f52072a4a1b5e1b165d50064e411d0521111f235f114c47362447094f10035c066f19025402191915110b4206182a544702100109133e394505175509671b6f0b01484e06505b061b50034a2911521e44431b5a233f13180b5508131523050154403740415503484f0c2602564d470a18407b775d031110004a54290319544e06505b060b424f092e1a770443101952333213030d554d551b2006064206555d50141c454f0c3d1b5e4d43061e453e39544c17580856581802001102105443101d111a043c03521455074c473f3213000a5b085d113c194f5e08555415180f5f433e270d131d420c1957773f560d11440d40543c060e470b55545b114e470e193c155f4d47110947343f13180c100f565a000403484e184c15050250081f2a54470545104c5536251325435302461a3b4a02484e12545c1b4265070b3b5440055543185b36231301025b084054220f4f42071b1554020f430b196f19564d4002055d79'#res=salt^outputtrlen= int(len(res)/2)list1=[]for i in range(0,len(res),2):    list1.append(res[i:i+2])list2=[]                 #列出key全集for j in range(0,trlen):    list3=[]    for i in ks:        if (chr(ord(i)^int(list1[j],16))in ps):            list3.append(i)    list2.append(list3)             for length in range(1,38):          #根据key[0]不为空集来爆length    x=set(list2[0])     for j in range(0,trlen,length):        x &= set(list2[j])    if len(x)!=0:        print(length)y = []for z in range(30):          #爆key候选集    x=set(list2[z])     for j in range(z,trlen,30):        x &= set(list2[j])    if len(x)!=0:        y.append(x)print(str(y).replace("},","},\n"))key='W3lc0m3tOjo1nu55un1ojOt3m0cl3W'ki=cycle(key)           #看结果str1=''for each in list1:    str1+=chr(ord(next(ki))^int(each,16))print(str1)

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 [email protected] - source:Van1sh的小屋

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月25日00:49:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2019 De1CTFhttp://cn-sec.com/archives/3093362.html

发表评论

匿名网友 填写信息