蜀道山ctf2024[WP]

MISC:

1.欢迎来到2024蜀道山CTF

直接关注号获得flag,就不多说了

2.Elemental Wars

  1. 题目要求赢得机器人,尝试数次后,发现机器人数字完全随机,写脚本输入1-5的随机数,不断尝试即可
import socket
import time
import random

HOST = 'gamebox.yunyansec.com'  
PORT = 35759  

def choose_element():
    # 随机选择1到5之间的数字,并加上换行符
    return f"{random.randint(1, 5)}\n"

def get_enemy_health(response):
    # 提取敌人血量
    for line in response.splitlines():
        if "敌人的血量:" in line:
            health = int(line.split("敌人的血量:")[1])
            return health
    return None

def main():
    # 创建一个socket用来连接到服务器
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        print("已连接到服务器")

        while True:
            # 接收服务器的返回信息
            response = s.recv(1024).decode('utf-8')
            print(f"服务器: {response}")

            # 判断是否是选择元素的提示
            if "请选择你的元素" in response:
                # 发送随机选择的元素
                choice = choose_element()
                print(f"发送随机选择:{choice.strip()}")
                s.sendall(choice.encode('utf-8'))

                # 如果敌人血量小于1,停止战斗
                if enemy_health < 1:
                    print("敌人血量小于等于1,战斗结束!")
                    break
            # 等待下一轮
            time.sleep(1)

if __name__ == "__main__":
    main()

3.神奇的硬币纺纱机

  1. 一直输入 0 或 1 使结果达到 100 即可

4.javaPcap

压缩包中有两个文件,一个流量包文件,一个jar文件
首先打开流量包,过滤出来http的流量

只有get请求方式,而且看起来像是用后门执行了一些命令
追踪第一个流

将cmd 进行base64解码后是 whoami

用jd-gui进行反编译后,这些加密方式都能看出来编码,填充方式和加密模式
后面有密钥和加密方式,应该是返回的东西是用这个方式加密的

所以后面就是什么加密方式和密钥
用base64解码后,五次命令执行如下

whoami
ls
ls
base64 flag/flag.zip
cat flag/hint.txt

用相关加密方式解密后的返回内容分别是(在blowfish解密时,记得把密钥取前十六位)

root

total 5492
drwx------ 18 root root    4096 Nov  6 15:26 ..
drwxr-xr-x  3 root root    4096 Nov  4 17:22 .
drwxr-xr-x  2 root root    4096 Nov  4 17:22 flag
-rw-r--r--  1 root root 5610013 Nov  4 16:28 SimpleHttpServer.jar

flag.zip
hint.txt

UEsDBBQACQAIABSGZFkAAAAAAAAAACsAAAAIACkAZmxhZy50eHRVVAkABWiKKGeQGitndXgLAAEE
AAAAAAQAAAAAeGwJAAcUAwAAAADtgXBFs0Lb8F43+KxCxq77A+Zya0CyhPRERubzgNwf5fF5GVjt
ntPQZe8hy0s4qLAhBXW42FAs5Xhw4lBLBwiHHE6JOQAAACsAAABQSwECFAMUAAkACAAUhmRZhxxO
iTkAAAArAAAACAAcAAAAAAAAAAAA7YEAAAAAZmxhZy50eHRVVAkABWiKKGeQGitndXgLAAEEAAAA
AAQAAAAAUEsFBgAAAAABAAEAUgAAAJgAAAAAAA==

密码为执行命令(按照时间排序)的首字母的组合重复三次,比如执行了(id,whoami),那么密码就为iwiwiw

密码 : wllbcwllbcwllbc

使用base64转文件工具,将第四个命令执行的 flag.zip恢复

用密码解开压缩包后

reverse:

1.map

ida32位打开,无壳

大致逻辑就是sub_4010D0函数初始化v4和v5生成地图,sub_401C40检验path正确与否
sub_4010D0生成地图函数

大致看一下就是一个15*15的地图,然后最初初始化都为0,下面的内容就是将每行的某几列变成1,相当于就是墙,而0是通路,根据代码写脚本获得地图

def build_maze():
    # 定义迷宫大小
    N = 15
    maze = [[0] * N for _ in range(N)]

    # 第一行的第1-14列为墙
    for k in range(1, 15):
        maze[0][k] = 1

    # 第二行的第9-14列为墙
    for m in range(9, 15):
        maze[1][m] = 1

    # 第三行的第0-1列、第3-7列、第9-14列为墙
    for n in range(0, 2):
        maze[2][n] = 1
    for ii in range(3, 8):
        maze[2][ii] = 1
    for jj in range(9, 15):
        maze[2][jj] = 1

    # 第四行的第0-1列、第3-7列、第12-14列为墙
    for kk in range(0, 2):
        maze[3][kk] = 1
    for mm in range(3, 8):
        maze[3][mm] = 1
    for nn in range(12, 15):
        maze[3][nn] = 1

    # 第五行的第0-1列、第7列、第11-14列为墙
    for i1 in range(0, 2):
        maze[4][i1] = 1
    maze[4][7] = 1
    for i3 in range(11, 15):
        maze[4][i3] = 1

    # 第六行的第0-1列、第3-5列、第11-14列为墙
    for i4 in range(0, 2):
        maze[5][i4] = 1
    for i5 in range(3, 6):
        maze[5][i5] = 1
    for i6 in range(11, 15):
        maze[5][i6] = 1

    # 第七行的第0-1列、第3-5列、第7-9列、第11-14列为墙
    for i7 in range(0, 2):
        maze[6][i7] = 1
    for i8 in range(3, 6):
        maze[6][i8] = 1
    for i9 in range(7, 10):
        maze[6][i9] = 1
    for i10 in range(11, 15):
        maze[6][i10] = 1

    return maze

def print_maze(maze):
    symbols = {0: '·', 1: '*'}
    for row in maze:
        print("".join(symbols[cell] for cell in row))

if __name__ == "__main__":
    maze = build_maze()
    print_maze(maze)
def build_v6_maze():
    N = 15
    maze = [[0] * N for _ in range(N)]

    # 初始赋值
    maze[0][0] = 1
    maze[0][1] = 0
    maze[0][2] = 0
    maze[0][3] = 1

    # 第一组循环
    for i in range(4, 6):
        maze[0][i] = 1

    # 第二组循环
    for i in range(7, 10):
        maze[0][i] = 1

    # 第三组循环
    for i in range(11, 15):
        maze[0][i] = 1

    # 第四组循环
    for i in range(0, 2):
        maze[1][i] = 1

    # 第五组循环
    for i in range(7, 10):
        maze[1][i] = 1

    # 第六组循环
    for i in range(11, 15):
        maze[1][i] = 1

    # 第七组循环
    for i in range(0, 6):
        maze[2][i] = 1

    # 第八组循环
    for i in range(7, 10):
        maze[2][i] = 1

    # 第九组循环
    for i in range(11, 15):
        maze[2][i] = 1

    # 第十组循环
    for i in range(0, 6):
        maze[3][i] = 1

    # 第十一组循环
    for i in range(11, 15):
        maze[3][i] = 1

    # 第十二组循环
    for i in range(0, 9):
        maze[4][i] = 1

    # 第十三组循环
    for i in range(13, 15):
        maze[4][i] = 1

    # 第十四组循环
    for i in range(0, 9):
        maze[5][i] = 1

    # 特定位置赋值
    maze[5][9] = 0
    maze[5][10] = 1
    maze[5][11] = 1
    maze[5][12] = 0

    # 第十五组循环
    for i in range(13, 15):
        maze[5][i] = 1

    # 第十六组循环
    for i in range(0, 9):
        maze[6][i] = 1

    # 更多特定位置赋值
    maze[6][9] = 0
    maze[6][10] = 1
    maze[6][11] = 1
    maze[6][12] = 0

    # 第十七组循环
    for i in range(13, 15):
        maze[6][i] = 1

    # 第十八组循环
    for i in range(0, 12):
        maze[7][i] = 1

    return maze

def print_maze(maze):
    symbols = {0: '·', 1: '*'}
    for row in maze:
        print(''.join(symbols[cell] for cell in row))

if __name__ == "__main__":
    maze = build_v6_maze()
    print_maze(maze)

最后地图的样子

然后就是手动找路径,最后是

DRRRRRRRRDDDDRRDDDDDDRRDDDRR

DRRDDDRRRRDDDDDDRRRRDRRDDDRR

DRRDDDDDDDRRRRDDRRRDRRRDDDRR

路徑有點忘了,應該是這三個之中的一個

LZSDS{md5(DRRDDDDDDDRRRRDDRRRDRRRDDDRR)}
LZSDS{1979869e0c4ef6c542e54ae5c48f63ec}()

2.HelloHarmony

挺有意思的一个题,是鸿蒙逆向,之前没遇到过,网上查找资料后发现hap文件也能修改为zip解压以及用jadx分析(魔改的可以分析.abc文件)
hap文件解压后\HelloHarmony\HelloHarmony\ets目录下用jadx打开.abc文件分析
查文章发现主要是看index文件p001entry.src.main.ets.pages.Index下面

看了一下大概猜测密码就是flag

Object newobjrange = import { Eeee } from "@normalized:N&&&entry/src/main/ets/Emmm/Eeee&"(5);
        Object testNapi = import { default as testNapi } from "@normalized:Y&&&libentry.so&";
        if ((200 == testNapi.check(newobjrange.encrypt(_lexenv_0_1_.password)) ? 1 : 0) != 0) {

这个意思就是导入了Eeee中的一个类用来检查,然后经过我的努力找到了它

大概意思就是大小用一个偏移量解密,小写的会比大写的偏移量多2,但是我没找到大写的偏移量,但这并不影响我后续枚举✌
然后分析so层找到检查
主函数:

WTF::WTF函数:


WTF::heiheihei主加密函数:

WTF::blablablablabla: 对数据进行异或操作,使用密钥keys中的特定元素。此函数是数据处理的核心部分,直接操作数据块进行加密或解密。
WTF::bla: 通过映射表map处理数据,这与inverse_bla函数相对应,进行基于映射的数据转换。
WTF::blablabla: 对数据进行循环位移操作,与inverse_blablabla函数的功能相同,但用于加密过程。

大致加密逻辑是输入的密码先在java层凯撒加密,然后在so层再一次加密
然后就是脚本(一开始我是用的大端存储,发现后半部分是乱码,然后换成小端存储就正常了)

# Initialize substitution array
sub_array = [(167 * i + 173) % 256 for i in range(256)]

# Build inverse substitution array
inv_sub_array = [0] * 256
for i, val in enumerate(sub_array):
    inv_sub_array[val] = i

# Build key schedule
key = b'HelloSDS'
key_len = len(key)
key_schedule = []
for i in range(8):
    val = ((key[i % key_len] << 24) | (key[(i + 1) % key_len] << 16) |
           (key[(i + 2) % key_len] << 8) | key[(i + 3) % key_len]) & 0xFFFFFFFF
    key_schedule.append(val)

# Encrypted data (eeee array)
encrypted = bytearray([
    0xF6, 0xB0, 0xA6, 0x36, 0x9A, 0xB3, 0x2B, 0xBF, 0x94, 0x54,
    0x15, 0x97, 0x93, 0x59, 0xBF, 0x50, 0x4D, 0xBF, 0x0A, 0x59,
    0x06, 0xD7, 0x97, 0x50, 0xD6, 0x59, 0x54, 0xD7, 0xCF, 0x06,
    0x5D, 0x20, 0x1D, 0x5A, 0x22, 0xEE, 0x99, 0x1F, 0xE1, 0x18
])

flag = bytearray(encrypted)

# Reverse the heiheihei steps
for i in reversed(range(8)):
    # Reverse rotation (rotate right by 1 byte)
    flag = flag[-1:] + flag[:-1]

    # Inverse substitution
    flag = bytearray(inv_sub_array[b] for b in flag)

    # Reverse XOR on the first 8 bytes
    k = key_schedule[i]
    for j in range(0, 8, 4):
        # Use 'little' endian to handle XOR operation
        val = int.from_bytes(flag[j:j + 4], 'little') ^ k  # Convert bytes to int (little-endian)
        flag[j:j + 4] = val.to_bytes(4, 'little')  # Convert back to bytes (little-endian)

# Print the result
try:
    # Attempt to decode as a string
    flag_str = flag.decode('utf-8')
    print("Decoded flag:", flag_str)
except UnicodeDecodeError:
    # Fallback to hexadecimal format
    print("Flag (hex):", flag.hex())
#Decoded flag: QEXIX{f0b_4y3_4_t4573y_0m_jyfw706y4wof} 

然后大写偏移量为5后发现变成了LZSDS,那说明小写就是7,最后得到flag
LZSDS{y0u_4r3_4_m4573r_0f_cryp706r4phy}

Crypto

1.xorsa

原脚本
from Crypto.Util.number import *
from gmpy2 import *
import uuid
flag='LZSDS{'+str(uuid.uuid4())+'}'

while True:
    p=getPrime(512)
    if p.bit_length()==512:
        break
mask=??????
q=p^mask
hint1=p^q
hint2=q
n=p*q
e=2026
m=bytes_to_long(flag.encode())
c=pow(m,e,n)
print("c =",c)
print("n =",n)
print("hint1 =",hint1)
print("hint2 =",hint2)

'''
c = 13760578729891127041098229431259961120216468948795732373975536417751222443069805775693845560005881981622202089883866395577154701229046245882282127054969114210307175116574178428823043817041956207503299220721042136515863979655578210499512044917781566303947681251248645504273995402630701480590505840473412765662
n = 14247038211821385209759067256846232227444163173099199085257790370590450749665206556163364754269182255358084948354345827898987234756662133974633117062902370811855466665351784027125333112663075085395676501121759786699720149098576433141817737564928779420725539793335830274229206316999461309927000523188222801659
hint1 = 8938538619961731399716016665470564084986243880394928918482374295814509353382364651201249532111268951793354572124324033902502588541297713297622432670722730
hint2 = 1493298155243474837320092849325750387759519643879388609208314494000605554020636706320849032906759121914762492378489852575583260177546578935320977613050647
'''

本来感觉特别简单,q告诉我了,q和hint1异或后就知道p了,p q e n c都知道了,直接就能解出来明文
但是解出来发现e phi不互质
ee 与 ϕ(n)ϕ(n) 不互质时,调整 ee 和 ϕ(n)ϕ(n),计算私钥指数 dd
解密密文,得到明文的 kk 次幂 m′m′。
计算 kk 次方根,恢复明文 mm。
解密脚本

from base64 import b64decode
from Crypto.Cipher import Blowfish
from Crypto.Util.Padding import unpad

def decrypt(encrypted_content, key, algorithm, key_size):
    try:
        # 处理密钥
        key_bytes = bytearray(key_size)
        input_key_bytes = key.encode('utf-8')
        key_bytes[0:len(input_key_bytes)] = input_key_bytes[0:key_size]

        # 创建 Cipher 对象
        cipher = Blowfish.new(key_bytes, Blowfish.MODE_ECB)

        # Base64 解码密文
        encrypted_bytes = b64decode(encrypted_content)

        # 解密并去除填充(PKCS5Padding)
        decrypted_bytes = cipher.decrypt(encrypted_bytes)
        decrypted_bytes = unpad(decrypted_bytes, Blowfish.block_size, style='pkcs5')

        return decrypted_bytes.decode('utf-8')
    except Exception as e:
        raise RuntimeError("解密错误: " + str(e))

if __name__ == "__main__":
    encrypted_content = "bCvVthlhq6kihQdSBv2WzUZfeSGvRMigmsAMsdEtYOKW577HPZqinI5hlkRNE33xwgwWyWseoI8oERTQEnfoRXc5dJAWtwF+CTkmcoeeu5ccy7Qjp/cJA2Slj/UJDC6UWgvagkU3OYuFIELSc1x6etggbESl2Ug0dwUk3hO/xpYGxgQPCXnzciXSTCmlCq5Wr2EPXNG3wE/+NCpeHDe2WTbyPylOunr7/NWFy+flv0plvq29HzGo7lx4clpnEBKhWV91U7S+Fm5PUy69Aer4mC64NUcNf7m9jKcKeMvQQv5OPU5L6OayrJuh8eBPRjenb1A+JKZGYQK3j7xyNJ30r1F20E+EyZNM/JWcPImyXdh/aebRvlqWH99FoIJZhRhh2lbA6ZXXNwKxx0tZI5IFyH6m5DaUGKe/NN0rZbLCNFZoW93VEPiYwoM94R9uEolHvKjIQlP8qDStic5oXH/UoA=="  # 替换为实际的加密内容
    key = "596d467a5a54593049475a73595763765a6d78685a793536615841"                 # 替换为实际的密钥
    algorithm = "Blowfish"          # 与加密时使用的算法一致
    key_size = 16                   # 与加密时的 keySize 一致

    decrypted_content = decrypt(encrypted_content, key, algorithm, key_size)
    print("解密后的内容: ", decrypted_content)
posted @ 2024-11-18 19:13  Zephyr07  阅读(242)  评论(0)    收藏  举报