HGAME 2024 WEEK1 WP

文章目录

    • WEB
      • ezHTTP
      • Bypass it
      • Select Courses
      • 2048*16
      • jhat
    • RE
      • ezASM
      • ezPYC
      • ezUPX
      • ezIDA
    • PWN
      • EzSignIn
    • CRYPTO
      • 奇怪的图片
      • ezRSA
      • ezMath
      • ezPRNG
    • MISC
      • SignIn
      • 来自星尘的问候
      • simple_attack
      • 希儿希儿希尔
      • 签到

放假比较闲,打打比赛
HGAME 2024 WEEK1 WP_第1张图片

WEB

ezHTTP

来自vidar.club、UA要求阿巴阿巴阿巴、来自本地(提示不是XFF,其他的都试一下发现是X-Real-IP)、最后解jwt得到flag

HGAME 2024 WEEK1 WP_第2张图片

Bypass it

有个注册按钮但是无法跳转过去,查看一下注释发现里面有个JavaScript写的alert('很抱歉,当前不允许注册');top.location.href='login.html'

那么禁用一下浏览器的js注册一个账号,再开启js即可,火狐浏览器的方法为
url框输入about:config搜索javascript.enabled,把true改成false即可

Select Courses

最迷惑的一集

HGAME 2024 WEEK1 WP_第3张图片

然后想着里面有个full,源码里面还看到了is_full这些

在这里插入图片描述

接着就一直这样发包:

HGAME 2024 WEEK1 WP_第4张图片

full还是1对吧,但是如果左边我故意让右边400几次,再发正常的包,多次重复这个步骤,莫名其妙full=0了

(例如下面这张图期间发了1次id=4+4,id=441,发了3次id=4)

HGAME 2024 WEEK1 WP_第5张图片

复现不出来,纯看运气,拿当时出交flag时截的截图了

HGAME 2024 WEEK1 WP_第6张图片

2048*16

卡死惹

有个index-_wkhdPNY.js,存的整个游戏的逻辑,大概率flag的输出在这里面

随便找个格式化一下https://willnode.github.io/deobfuscator/

在这里插入图片描述

盲猜flag被base64加密过,不过搜hga的base64字符串没搜到,继续往下翻

HGAME 2024 WEEK1 WP_第7张图片

猜测这个可能跟flag有关,先保留

HGAME 2024 WEEK1 WP_第8张图片

找到获胜的逻辑,会执行s0(n(439), "V+g5LpoEej/fy0nPNivz9SswHIhGaDOmU8CuXb72dB1xYMrZFRAl=QcTq6JkWK4t3")

随便打开个网页,在控制台把整个js输入进去

HGAME 2024 WEEK1 WP_第9张图片

然后alert一下s0(n(439), "V+g5LpoEej/fy0nPNivz9SswHIhGaDOmU8CuXb72dB1xYMrZFRAl=QcTq6JkWK4t3")

HGAME 2024 WEEK1 WP_第10张图片

jhat

之前问gpt问了老半天,直到hint3已出现就恍然大悟怎么问了

HGAME 2024 WEEK1 WP_第11张图片

select new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream("/flag"))).readLine()

HGAME 2024 WEEK1 WP_第12张图片

接着问了一下GPT,读取根目录:select java.util.Arrays.toString(new java.io.File("/").list())

HGAME 2024 WEEK1 WP_第13张图片

RE

ezASM

HGAME 2024 WEEK1 WP_第14张图片

与0x22异或即可

HGAME 2024 WEEK1 WP_第15张图片

ezPYC

刚开始用着几年前一直用的pyinstxtractor发现就是逆不出pyc头,才发现这玩意早更新了

然后找个在线的pyc逆一下即可

flag = [
    87,
    75,
    71,
    69,
    83,
    121,
    83,
    125,
    117,
    106,
    108,
    106,
    94,
    80,
    48,
    114,
    100,
    112,
    112,
    55,
    94,
    51,
    112,
    91,
    48,
    108,
    119,
    97,
    115,
    49,
    112,
    112,
    48,
    108,
    100,
    37,
    124,
    2]
c = [
    1,
    2,
    3,
    4]
#后略

一眼xor

HGAME 2024 WEEK1 WP_第16张图片

ezUPX

upx -d ezUPX

然后IDA打开即可

HGAME 2024 WEEK1 WP_第17张图片

HGAME 2024 WEEK1 WP_第18张图片

xor 0x32

HGAME 2024 WEEK1 WP_第19张图片

VIDAR{Wow!Y0u_kn0w_4_l1ttl3_0f_UPX!}

ezIDA

IDA直接打开就能看到

PWN

EzSignIn

nc即可

CRYPTO

奇怪的图片

不是很懂密码为什么会放这个题,感觉还是考的misc,要说密码的话总感觉有点像OTP的样子

简单分析函数

import time

from PIL import Image, ImageDraw, ImageFont
import threading
import random
import secrets


flag = "hgame{fake_flag}"

#生成随机RGB图片
def generate_random_image(width, height):
    image = Image.new("RGB", (width, height), "white")
    pixels = image.load()
    for x in range(width):
        for y in range(height):
            red = random.randint(0, 255)
            green = random.randint(0, 255)
            blue = random.randint(0, 255)
            pixels[x, y] = (red, green, blue)
    return image

#图像上画flag
def draw_text(image, width, height, token):
    font_size = random.randint(16, 40)
    font = ImageFont.truetype("arial.ttf", font_size)
    text_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
    x = random.randint(0, width - font_size * len(token))
    y = random.randint(0, height - font_size)
    draw = ImageDraw.Draw(image)
    draw.text((x, y), token, font=font, fill=text_color)
    return image

#异或两张图RGB
def xor_images(image1, image2):
    if image1.size != image2.size:
        raise ValueError("Images must have the same dimensions.")
    xor_image = Image.new("RGB", image1.size)
    pixels1 = image1.load()
    pixels2 = image2.load()
    xor_pixels = xor_image.load()
    for x in range(image1.size[0]):
        for y in range(image1.size[1]):
            r1, g1, b1 = pixels1[x, y]
            r2, g2, b2 = pixels2[x, y]
            xor_pixels[x, y] = (r1 ^ r2, g1 ^ g2, b1 ^ b2)
    return xor_image

#生成与随机token当文件名
def generate_unique_strings(n, length):
    unique_strings = set()
    while len(unique_strings) < n:
        random_string = secrets.token_hex(length // 2)
        unique_strings.add(random_string)
    return list(unique_strings)

random_strings = generate_unique_strings(len(flag), 8)


current_image = generate_random_image(120, 80)
key_image = generate_random_image(120, 80)

def random_time(image, name):
    time.sleep(random.random())
    image.save(".\\png_out\\{}.png".format(name))

for i in range(len(flag)):
    current_image = draw_text(current_image, 120, 80, flag[i])
    threading.Thread(target=random_time, args=(xor_images(current_image, key_image), random_strings[i])).start()

简单看了一下,生成了一个随机RGB的image和一个key_image,然后在image上面生成一个flag的其中一个字符就异或一下一直到生成完。能够发现current_image是用的同一张,意思是生成了字符之后还会在上面生成,就会产生覆盖(不过不要紧)

简单来说,就是

key^a1 = a2
key^b1 = b2

a2^b2 = a1^b1
背景都是相同的,那么a1^b1就是异或不同的字符

基于这一点,我想到如果我选中的图是第一张图或者最后一张图,那么用这张图片去异或其他图片,得到的信息是绝对递增的,不会出现信息个数相同的情况(即假设全为flag{123}选中的为f,再往后异或会出现f^fl = l,f^fla = la……;反之}^3} = 3,}^23} = 23)

因此尝试爆破

from PIL import Image, ImageDraw, ImageFont


def xor_images(image1, image2):
    if image1.size != image2.size:
        raise ValueError("Images must have the same dimensions.")
    xor_image = Image.new("RGB", image1.size)
    pixels1 = image1.load()
    pixels2 = image2.load()
    xor_pixels = xor_image.load()
    for x in range(image1.size[0]):
        for y in range(image1.size[1]):
            r1, g1, b1 = pixels1[x, y]
            r2, g2, b2 = pixels2[x, y]
            xor_pixels[x, y] = (r1 ^ r2, g1 ^ g2, b1 ^ b2)
    return xor_image

import os
DL = os.listdir('./')
NDL = [file for file in DL if ".png" in file]
print(NDL)
print(len(NDL))
for j in range(len(NDL)):
    image1 = Image.open(NDL[j])
    dr = NDL[j].split(".png")[0]
    os.mkdir(f'../{dr}')
    for i in range(len(NDL)):
        image2 = Image.open(NDL[i])
        image3 = xor_images(image1,image2)
        image3.save(f'../{dr}/{i}.png')
        image3.close()
        image2.close()

这里获得了很多文件夹,当我看到18ef202a的时候发觉不简单,有一张单独出现的{

HGAME 2024 WEEK1 WP_第20张图片

注意到出现{的个数正好为5个,说明这张原图上面写的字符是hgame{,那么后面按照顺序递增就是flag的正向顺序

最后排序得到hgame{1adf_17eb_803c}

ezRSA

观察到leak1和leak2是

leak1=pow(p,q,n)
leak2=pow(q,p,n)

不是很懂密码,所以只能百度这个了,找到一个用了leak1=pow(p,q,n)的题https://www.cnblogs.com/U-L-G-A-N-O-Y/articles/17866487.html

HGAME 2024 WEEK1 WP_第21张图片

HGAME 2024 WEEK1 WP_第22张图片

可知leak1和leak2其实就是p和q,写常规解RSA即可

import gmpy2
import binascii

e = 65537
p = 149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669
q = 116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461
c=10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971
n = p*q

L = (p-1)*(q-1)
d = gmpy2.invert(e,L)
m = gmpy2.powmod(c,d,n)

print(binascii.unhexlify(hex(m)[2:]))
#hgame{F3rmat_l1tt1e_the0rem_is_th3_bas1s}

ezMath

不懂crypto,搜一下特征assert x**2 - D * y**2 == 1

https://www.wxjk.net/other/23395136.html

HGAME 2024 WEEK1 WP_第23张图片

#sage
numTry = 1500
def solve_pell(N, numTry):
    cf = continued_fraction(sqrt(N))
    for i in range(numTry):
        denom = cf.denominator(i)
        numer = cf.numerator(i)
        if numer^2 - N * denom^2 == 1:
            return numer, denom
    return None, None

x,y = solve_pell(114514,numTry)
print(y)

HGAME 2024 WEEK1 WP_第24张图片

得到

9037815138660369922198555785216162916412331641365948545459353586895717702576049626533527779108680

解一下就行

from Crypto.Cipher import AES
from libnum import n2s as long_to_bytes
def pad(x):
    return x+b'\x00'*(16-len(x)%16)
y = 9037815138660369922198555785216162916412331641365948545459353586895717702576049626533527779108680

key_bytes = long_to_bytes(y)
key_padded = pad(key_bytes)[:16]

enc = b"\xce\xf1\x94\x84\xe9m\x88\x04\xcb\x9ad\x9e\x08b\xbf\x8b\xd3\r\xe2\x81\x17g\x9c\xd7\x10\x19\x1a\xa6\xc3\x9d\xde\xe7\xe0h\xed/\x00\x95tz)1\\\t8:\xb1,U\xfe\xdec\xf2h\xab`\xe5'\x93\xf8\xde\xb2\x9a\x9a"

cipher = AES.new(key_padded, AES.MODE_ECB)
decrypted_flag = cipher.decrypt(enc)

print(decrypted_flag)
#b'hgame{G0od!_Yo3_k1ow_C0ntinued_Fra3ti0ns!!!!!!!}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

ezPRNG

不是很懂密码学,我只知道lfsr和伪随机数那个库,但是改一改就不是很会了,这个题我选择的是

c语言多线程爆破(爆破完约6小时,针对此题耗时约2小时)

#include 
#include 
#include 
#include 

#define NUM_THREADS 8  // CPU线程
#define SEARCH_SPACE 4294967295U

uint32_t PRNG(uint32_t R, uint32_t mask) {
    uint32_t nextR = (R << 1) & 0xffffffff;
    uint32_t i = (R & mask) & 0xffffffff;
    uint32_t nextbit = 0;
    while (i != 0) {
        nextbit ^= (i % 2);
        i = i / 2;
    }
    nextR ^= nextbit;
    return nextR;
}

void *search_thread(void *arg) {
    int thread_id = *((int *)arg);
    uint32_t mask = 0b10001001000010000100010010001001;
    char* outputs[4] = {
        "1111110110111011110000101011010001000111111001111110100101000011110111",
        "0010000000001010111100001100011101111101111000100100111010101110010110",
        "1110110110010001011100111110111110111001111101010011001111100100001000",
        "0001101010101010100001001001100010000101010100001010001000100011101100"
    };
    char buffer[71];

    uint32_t start = thread_id * (SEARCH_SPACE / NUM_THREADS);
    uint32_t end = (thread_id == NUM_THREADS - 1) ? SEARCH_SPACE : (thread_id + 1) * (SEARCH_SPACE / NUM_THREADS);

    for (int i = 0; i < 4; i++) {
        for (uint32_t R = start; R <= end; R++) {
            uint32_t currentR = R;
            for (int j = 0; j < 70; j++) {
                currentR = PRNG(currentR, mask);
                buffer[j] = (currentR & 1) + '0';
            }
            buffer[70] = '\0';

            if (strncmp(buffer, outputs[i], 70) == 0) {
                printf("Found matching R: %08x in thread %d\n", R, thread_id);
                break;
            }
			    if (R % 100000000 == 0) {
                printf("Progress: %u\n", R);}
        }
    }

    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i;
        pthread_create(&threads[i], NULL, search_thread, (void *)&thread_ids[i]);
    }

    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    printf("Search completed.\n");
    return 0;
}

HGAME 2024 WEEK1 WP_第25张图片

HGAME 2024 WEEK1 WP_第26张图片

HGAME 2024 WEEK1 WP_第27张图片

总之最后得到flag:hgame{fbbbee82-3f43-4f91-9337-907880e4191a}

MISC

SignIn

笑鼠了,刚开赛太着急看换个方式签到,以为说的是满足'hgame\{[A-Z_]+\}'就行,过了半分多钟才发现不对旁边有个附件。

发到手机上从充电口网上看就行了

hgame{WOW_GREAT_YOU_SEE_IT_WONDERFUL}

来自星尘的问候

当时stegbreak没爆出来就没去单独试steghide了,后来单独试了发现是steghide,不知道stegbreak咋回事,下次还是stegseek吧。

密码123456,然后图片进行谷歌搜图

HGAME 2024 WEEK1 WP_第28张图片

搜字母表https://www.bilibili.com/read/cv14514692/

手动转换一下得到hgame{wel??me!}

没找到问号,试了一下welcome不对,感觉是数字但是一下子没找到,去搜leet发现字母c没有对应的数字表示,就试了下hgame{welc0me!},正确

simple_attack

明文攻击,不过第一次用winrar压缩发现不能被攻击,我猜出题人又是用的bandzip,用bandzip果不其然能被攻击,而且为什么不用store;还有为什么不用winrar,感觉好像bandzip跟其他压缩软件挺格格不入的

HGAME 2024 WEEK1 WP_第29张图片

解压出来的photo直接浏览器输入即可自动转base64的图片

HGAME 2024 WEEK1 WP_第30张图片

希儿希儿希尔

一眼希尔密码,文件尾找到密文,看图片就是恢复高宽了,百度找一个爆破CRC的即可

这个代码直接换原新的图片

import binascii
import struct
import sys
file = input("图片地址:")
fr = open(file,'rb').read()
data: bytearray = bytearray(fr[0x0c:0x1d])
crc32key = eval('0x'+str(binascii.b2a_hex(fr[0x1d:0x21]))[2:-1])
n = 4095
for w in range(n):
    width = bytearray(struct.pack('>i', w))
    for h in range(n):
        height = bytearray(struct.pack('>i', h))
        for x in range(4):
            data[x+4] = width[x]
            data[x+8] = height[x]
        crc32result = binascii.crc32(data) & 0xffffffff
        if crc32result == crc32key:
            print(width,height)
            newpic = bytearray(fr)
            for x in range(4):
                newpic[x+16] = width[x]
                newpic[x+20] = height[x]
            fw = open(file+'.png','wb')
            fw.write(newpic)
            fw.close
            file.close()

得到的图片存在LSB,里面是key

在这里插入图片描述

HGAME 2024 WEEK1 WP_第31张图片

hgame{DISAPPEARINTHESEAOFBUTTERFLY}

签到

HGAME 2024 WEEK1 WP_第32张图片

你可能感兴趣的:(ctf,信息安全)