cookies
看提示是Welcome to my cookie search page. See how much I like different kinds of cookies!
先抓包发现cookies的值为-1
底下的框的内容是snickerdoodle,输入试试
发现页面上显示I love snickerdoodle cookies!
然后抓包发现cookie的值为0,猜测是爆破数字(只是加了个重定向),然后爆破到18的时候出了flag
GET aHEAD
又是文件协议,特容易被忽略
可使用协议如下:
GET: 请求指定的页面信息,并返回实体主体。
HEAD: 只请求页面的首部。
POST: 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。
PUT: 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE: 请求服务器删除指定的页面。
OPTIONS: 允许客户端查看服务器的性能。
TRACE: 请求服务器在响应中的实体主体部分返回所得到的内容。
PATCH: 实体中包含一个表,表中说明与该URI所表示的原内容的区别。
MOVE: 请求服务器将指定的页面移至另一个网络地址。
COPY: 请求服务器将指定的页面拷贝至另一个网络地址
LINK: 请求服务器建立链接关系。
UNLINK: 断开链接关系。
WRAPPED: 允许客户端发送经过封装的请求。
Extension-mothed:在不改动协议的前提下,可增加另外的方法。
Insp3ct0r
直接查看源代码,发现获得1/3的flag,然后提示这是html,三个分别在html,css,js中,直接打开上面的css,js,获得完整的flag
Scavenger Hunt
方法和上一个差不多,只不过打开js发现是一句How can I keep Google from indexing my website?不是很理解应该怎么办,只能去扫目录,发现/robots.txt,/.DS_Store和/.htaccess/
出题人的意思应该是通过设置/robots.txt来阻止Google的索引,然后打开这个后提示I think this is an apache server… can you Access the next flag?
为了查看apache的配置而访问/.htaccess/,提示I love making websites on my Mac, I can Store a lot of information there.
然后通过mac的文件泄露联想到/.DS_Store,然后获取最后一部分flag
Some Assembly Required 1
感觉就是闲的
打开以后是一个文本框,检查源代码看见一个js,内容如下:
1 | const _0x402c=['value','2wfTpTR','instantiate','275341bEPcme','innerHTML','1195047NznhZg','1qfevql','input','1699808QuoWhA','Correct!','check_flag','Incorrect!','./JIFxzHyW8W','23SMpAuA','802698XOMSrr','charCodeAt','474547vVoGDO','getElementById','instance','copy_char','43591XxcWUl','504454llVtzW','arrayBuffer','2NIQmVj','result'];const _0x4e0e=function(_0x553839,_0x53c021){_0x553839=_0x553839-0x1d6;let _0x402c6f=_0x402c[_0x553839];return _0x402c6f;};(function(_0x76dd13,_0x3dfcae){const _0x371ac6=_0x4e0e;while(!![]){try{const _0x478583=-parseInt(_0x371ac6(0x1eb))+parseInt(_0x371ac6(0x1ed))+-parseInt(_0x371ac6(0x1db))*-parseInt(_0x371ac6(0x1d9))+-parseInt(_0x371ac6(0x1e2))*-parseInt(_0x371ac6(0x1e3))+-parseInt(_0x371ac6(0x1de))*parseInt(_0x371ac6(0x1e0))+parseInt(_0x371ac6(0x1d8))*parseInt(_0x371ac6(0x1ea))+-parseInt(_0x371ac6(0x1e5));if(_0x478583===_0x3dfcae)break;else _0x76dd13['push'](_0x76dd13['shift']());}catch(_0x41d31a){_0x76dd13['push'](_0x76dd13['shift']());}}}(_0x402c,0x994c3));let exports;(async()=>{const _0x48c3be=_0x4e0e;let _0x5f0229=await fetch(_0x48c3be(0x1e9)),_0x1d99e9=await WebAssembly[_0x48c3be(0x1df)](await _0x5f0229[_0x48c3be(0x1da)]()),_0x1f8628=_0x1d99e9[_0x48c3be(0x1d6)];exports=_0x1f8628['exports'];})();function onButtonPress(){const _0xa80748=_0x4e0e;let _0x3761f8=document['getElementById'](_0xa80748(0x1e4))[_0xa80748(0x1dd)];for(let _0x16c626=0x0;_0x16c626<_0x3761f8['length'];_0x16c626++){exports[_0xa80748(0x1d7)](_0x3761f8[_0xa80748(0x1ec)](_0x16c626),_0x16c626);}exports['copy_char'](0x0,_0x3761f8['length']),exports[_0xa80748(0x1e7)]()==0x1?document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e6):document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e8);} |
然后很容易发现,文本框调用了onButtonPress()函数,所以直接追这个函数就行
发现调用了大量的_0x4e0e函数(navigatePop)
阅读代码:
1 | const _0x4e0e = function(url, whensCollection) { |
发现,逻辑是读取一个数字,减去470后在前面的_0x402c取字符串
所以导出对应关系:
1 | _0x4e0e(470)=value |
其中parseInt函数的作用是把字符串解析成数字:https://www.runoob.com/jsref/jsref-parseint.html
懒得手算,所以转换成JavaScript打印出转换的值,加入:
1 | var arr = str.split(" "); |
完善onButtonPress()函数:
1 | (async() => { |
然后我们发现:没什么卵用。
无非就是输对了代码以后会显示correct,输错了会显示incorrect
然后回去看题目,提到了Assembly,也就是混淆这玩意的东西,所以可能是让我们找混淆这玩意的代码,直接F12,调到source,发现有个wasm,那就是代码的混淆规则,在最后找到了flag
实际上:因为那一大堆字符串里面只有一个./JIFxzHyW8W像路径,按路径去试的话,一下子就出来了
More Cookies
因为涉及密码学的知识,所以完全是知识盲区
似乎是利用了AES CBC这种加密方法
简单了解了一下,发现这似乎并不完全算是“加密”,而是“生成”
这种算法是,假如我有一串字符串A
将A经过Base64加密,生成B
随机生成两个数a和b(a<=128,b<=128)
将B的第a个字符(换成ascii码)异或b(换成字符),生成C
然后C再进行一次base64加密,得到D,就是我们最后获取的cookie
所以,由p XOR q = r 推出 p XOR r = q 得逆运算:
cookie用base64解密得C
C的第a个字符异或b得到B
B再被base64解密得到A,就是需要的cookie
所以爆破脚本:
#!/usr/bin/python2
import requests
import base64
s=requests.Session()
s.get(“http://mercury.picoctf.net:43275/")
cookie=s.cookies[“auth_name”]
print(cookie)
unb64=base64.b64decode(cookie)
print(unb64)
unb64b=base64.b64decode(unb64)
for i in range (0,128):
pos=i//8
guessdec=unb64b[0:pos]+chr(ord(unb64b[pos])^(1<<(i%8)))+unb64b[pos+1:]
guessenc1 = base64.b64encode(guessdec)
guess=base64.b64encode(base64.b64encode(guessdec))
r=requests.get(“http://mercury.picoctf.net:43275/",cookies={"auth_name": guess})
if “pico” in r.text:
print(r.text)
where are the robots
估计是考robots.txt,试了试发现内容是User-agent: * Disallow: /1bb4c.html,直接访问拿到flag
login
离谱
先是用什么账号和密码都能登上去,提示是登录Joe的账号,事实上只有Joe登不上去
尝试sql注入失败,估计不会爆破就没试
结果正确方法是:
先随便用一个账号和密码登录,发现cookie的内容为
username=123
password=456
456=False
所以把username的值改为Joe,把False改成True后刷新,就出flag了
dont-use-client-side
打开后是个输入框,尝试输几个都失败了,看源码,发现前端代码:
1 | function verify() { |
很明显,输入正确的字符串就是flag,所以这个时候最简单的方法就是:拿这一大堆字符串去爆破flag
picoCTF{ 和 5}都给了,要爆破的也就只有五个(开玩笑的)
直接看也不难,就是个拼接(数数)
pico
CTF{
no_c
lien
ts_p
lz_b
706c
5}
It is my Birthday
打开以后要上传两个文件,盲猜是要碰撞了,但不知道是什么碰撞
所以先传两个试试
发现需要传pdf,那就传
发现Files are not different! 那就传不一样的
回显MD5 hashes do not match!
猜的没错,md5碰撞
随便从网上找两个抄上去
然后就出答案了,而且非常贴心的给了源码!
1 | <?php |
Who are you?
打开以后是一句话:Only people who use the official PicoBrowser are allowed on this site!
看来是检测浏览器信息了,应该是查的header的User-Agent,改成PicoBrowser就好
发现I don’t trust users visiting from another site.
那估计是referer吧,改成它自己的网址
发现Sorry, this site only worked in 2018.
Date参数2018
回:I don’t trust users who can be tracked.
DNT:dnt
回:This website is only for people from Sweden.
需要瑞典的ip,xff,找个ip填上去
回:You’re in Sweden but you don’t speak Swedish?
改Accept-Language:sv
拿到flag
感想:我那次出的还是保守了
login
又一个login
试出来admin是账号,但是似乎没法注释,以这个网站的尿性,应该不是sql,查看源码,发现js:
1 | (async()=>{await new Promise((e=>window.addEventListener("load",e))),document.querySelector("form").addEventListener("submit",(e=>{e.preventDefault();const r={u:"input[name=username]",p:"input[name=password]"},t={};for(const e in r)t[e]=btoa(document.querySelector(r[e]).value).replace(/=/g,"");return"YWRtaW4"!==t.u?alert("Incorrect Username"):"cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ"!==t.p?alert("Incorrect Password"):void alert(`Correct Password! Your flag is ${atob(t.p)}.`)}))})(); |
用sublime排一下版:
1 | (async () => { |
因为一开始爆出了admin,用base64加密后是YWRtaW4=,和对比的正好差一个=
发现貌似会base64加密后把=给去掉
本以为后面那个要试着加=,但是好像直接解码就出结果了