CATCTF2022_pwn复现
CATCTF2022 PWN赛题复现
welcome_CAT_CTF
运行程序,发现是一个小游戏,可以上下左右来移动 @
这个字符,并且程序运行之初询问了服务器的 IP 和端口。
看伪代码的这里(如下)
如果能进入此处的 if ,那么就可以获取到服务器上的 flag
,条件有两个,第一个是满足s[100 * v0 - 100 + v1] == &unk_963B
这个后面的其实就是字符 @
。
而在按下 w
键,进行的操作如下
case 'w': |
按照逻辑可以猜测,按下 w
是向上移动,而向上移动的前提肯定是上面的那个内存要是空格,不然当前 @
上面有字符是无法向上移动的(可以结合程序运行发现这一点),所以可以猜测 s[100 * v0 - 100 + v1]
指向的就是当前字符 @
的上一个格子,因此获取 flag
的那个 if 前面的判断就是需要当前 @
上面的格子里也是一个 @
,实现这一点只需要简单的 adws
来移动即可。
而程序正常运行的话无论如何也无法让 glod
这个变量大于 100000000
,而获取 flag
的方式只要是进入这个 if 判断就可以获取,因此可以使用 gdb
中的 set
命令修改变量的值,从而绕过检查。
总结一下就是先用 gdb
修改 glod
这个全局变量大于 100000000
,接着让 @
移动到 @
下面,然后按下 j
(因为获取 flag
的那个 if 条件是在 case: ‘j’
下面的) 即可获取flag
bitcoin
这题当时就扫了一眼,一看是 C++
的题目直接跑路了,不过比赛完了之后入门了一下 C++
所以现在正找 C++
的题目练练手呢( winmt
师傅出的那个除外,实在感觉太难辣,如果有可能的话放到最后复现,如果没可能的话就跑路了 QAQ ),这道题其实一点也不难,就是一个常规的栈溢出,不过 C++
写的程序,确实跟之前做的常规栈溢出还有一点不太一样。
关于 C++
零基础入门,从零到零点一的话,可以看这篇文章
保护策略
漏洞所在:
因为没有开 canary
,因此这里 std::cin >> v4
包括往 v3
中输入数据都是存在栈溢出的。
所以常规打一个 ret2libc
即可,然后程序禁用了 execve
,最后去执行 orw
利用思路:
这里要说明一点,本题要再次输入的话,要利用 cin >>
来实现,这个东西是需要控制两个参数的,第一个是 std::cin
的地址,第二个是写入数据的目标地址。而执行的地方为
有一点像 scanf
函数,然后就是先泄露 libc
地址,同时控制 rbp
的值为接下来的栈迁移做一个准备,再做一个往 bss
段上输入的 rop
,最后给一个 leave ; ret
触发栈迁移。准备往 bss
段上写的 rop
是在已经有了 libc
地址的情况下做的,因此我们可以去调用 mprotect
函数将 bss
段改为可读可写可执行,后面紧跟着执行 orw
的 shellcode
。
其实泄露的 libc
地址就一个用处,就是从 libc
中取了一个 pop rdx ; ret
这个 gadget
需要注意的是, orw
之前必须要先把标准输入给 close
掉。也就是先执行 close(1)
再 open
read
write
不然远程打印不出来 flag
EXP:
from tools import * |
injection2.0
这种类型的题目是第一次见,跟着官方的 WP
复现一下。
文件分析
给的文件是上面这些, rootfs.img
文件是一个文件系统映像文件,它是将 _install
文件进行了打包。所以这里是用 qemu
来模拟的,在 _install
文件中 init
作为 qemu
的初始化脚本。
init
文件内容如下
!/bin/sh |
而关键是在下面三句
echo 0 | tee /proc/sys/kernel/yama/ptrace_scope |
第一句是关闭了 linux
内核中的 ptrace
限制。ptrace
是一种 linux
内核中的进程调试功能,他可以让一个进程跟踪另一个进程的执行情况,跟踪进程可以访问被跟踪进程的内存空间和寄存器的值。为了防止恶意程序利用 ptrace
进行攻击,Linux
内核开发者在内核引入了 yama
的安全机制,其中的一个子模块 ptrace_scope
就是用来限制 ptrace
使用的,默认情况下, yama
的 ptrace_scope
被设置为 1
,这意味着只有当父进程和子进程属于同一用户时,才能跟踪子进程,如果设置为 0
就是关闭这个限制,任何进程都可以跟踪其他进程。
第二句是运行 target
程序,并将程序的标准输出和标准错误都重定向到 pso.file
文件,并将该进程设置为后台进程。
第三句是脱离原先的终端,并获取 root
权限
然后 target
文件内容如下
先将 flag
文件读入到栈上,然后 close
将三个文件流全部关闭,再将 flag
文件删除掉,最后有一个永真循环,不断打印休眠打印字符串(目的是让进程一直处于运行状态,不会结束)
利用思路:
因为将 /proc/sys/kernel/yama/ptrace_scope
设置为了 0
,并且权限为 root
。因此可以使用 ptrace
接口来访问进程的内存。
首先执行命令 ps -ef
获取进程的 PID
,再用 /proc/pid/maps
获取栈地址,因为此时的进程依然在运行,所以 flag
依然存在到栈上,调用 ptrace
获取栈内数据比对 flag
,比对成功的话,就将接下来内存中的数据打印出来,从而获取 flag
。
而上面所说的比对并打印 flag
需要用C语言的脚本来实现,因为是第一次做这种题目,所以直接把官方的 WP
中的 exp
贴到这里了(主要感觉这种轮子没必要再去自己写一个,直接用或者根据需求再改改就挺好)
|
但是这个脚本我们是无法在远程的环境上编写并编译的,所以我们得在本地编译好,然后用 python
脚本将 exp
进行 base64
编码,然后上传到远程环境。
python
脚本如下:
这个依然是官方的 python
脚本。作用就是将 exp
上传到远端环境中。
from pwn import * |