有些命令好像有点不一样?
不要一直等,可能那样永远也等不到flag
nc 上后,经过简单测试,1 和 4 并没有什么重要信息
3 会陷入一个等待,题目有说明不要一直等 ,而 5 是退出,因此猜测突破口在 2
键入 2 后,可以看到 flag 就在根目录下
尝试命令注入,使用分号闭合前一条命令,后面插入新的命令
/;cat /ctfshow_flag
但是程序似乎陷入了一个无限的死循环,一直刷屏 ,可能是对输入字节进行了限制
我们缩短 payload:
;cat /ctf*
或者
/;cat /ct*
这里星号 * 是通配符,表示匹配所有以 ctf 开头的文件
执行成功
拿到 flag:ctfshow{331938ce-6990-4f79-91be-18fe53b701e4}
接下来我们分析二进制文件
checksec pwn
是 64 位程序,保护全开
拖进 ida64 反编译
可以看到 case 3 最终是会执行 system("cat /ctfshow_flag"); 命令的
但是在它之前有一个 sleep(0x1BF52u);
0x1BF52u 是什么概念,它表示等待大约 114514 秒,约合31小时48分钟
显然我们题目环境不可能存在这么久
我们再来看 case 2
伪代码详细分析:
puts 就相当于 print 打印输出,这个没啥好说的
read(0, buf, 0xAuLL);
read() 函数是一个 UNIX 系统调用,通常用于从文件描述符中读取数据。
用法:
ssize_t read(int fd, void *buf, size_t count);
参数解释:
fd:文件描述符,表示要读取的文件或者输入源。在 UNIX 系统中,0 表示标准输入(STDIN),1 表示标准输出(STDOUT),2 表示标准错误(STDERR)。
文件描述符0:用于接收用户输入或者从管道、重定向或者其他输入源读取数据。
文件描述符1:用于向终端或者其他输出目标输出数据。
buf:指向存储读取数据的缓冲区的指针。
count:要读取的最大字节数。
这行代码从标准输入(文件描述符为0)读取最多10个字符到缓冲区 buf 中。
0xAuLL是十六进制表示的 10,表示最多读取 10 个字符。
这与我们前面的猜测一致,输入字符长度受限,而我们可用的 payload:;cat /ctf* 或者 /;cat /ct* 就刚好是 10 个字符。
注:0xAuLL 中的 uLL 表示这是一个无符号长长整型(unsigned long long)的常量,sleep(0x1BF52u)中的u表示无符号整型(unsigned)。
strcat(dest, buf);
这行代码将用户输入的内容追加到 dest 字符串后面
双击跟进 dest
可以看到 dest 被声明为一个大小为 4 字节的字符数组,用来存储字符串
详细解释:
dest 是一个标签(label),它是程序中一个位置的名称或者符号。
db 是汇编语言中的伪指令(pseudo-instruction),用于声明字节(byte)类型的数据。
4 表示数组的大小为4字节。
dup(?) 表示重复(duplicate)未知值(?)4次,即将4个未知值(通常为0)依次填充到数组中。
接下来直接调用 system() 函数执行了用户输入的内容
这也就是为什么我们可以实现命令执行,从而获取 flag