深入分析CTFshow-PWN入门-pwn19的解法与原理

我参考了 My6n 师傅的 https://blog.csdn.net/Myon5/article/details/137891670 这篇文章
感觉其中有一部分是错的,深入分析后写下这篇文章与大家探讨!
欢迎各位师傅批评指正!

image

image

64 位小端序,直接运行后告诉我们给了我们 shell,尝试 ls 命令报错
拖进 ida 分析,F5 反编译

image

这里的代码分析涉及到了多进程问题

fork()函数会创建一个新的子进程,而原来程序运行的进程被称为父进程
fork()函数在父进程中会返回该进程的 id 值(非 0),也就是 if 条件成立;在子进程中的返回值为 0,也就是执行 else
其中父进程会调用 wait() 函数来等待子进程的运行,所以程序会先执行 else 部分,再执行 if 条件成立部分

在子进程中fclose(_bss_start);关闭了子进程的输出流,导致cat文件时看不到输出,所以在 payload 中我们要对输出重定向

突破点:文件描述符状态:
● 0(stdin    标准输入): 可用(未关闭)
● 1(stdout   标准输出): 关闭
● 2(stderr   标准错误): 可用(未关闭)

构造cat ctf* 1>&0
连接题目容器,输入 payload 执行

image

成功获得 flag

分析一下具体原因:

1>&0 是重定向输入输出的语法,其中 1 表示标准输出文件描述符stdout(1),0 表示标准输入文件描述符stdin(0)
 >&  意味着将输出重定向到指定的文件描述符,所以 1>&0 表示将标准输出重定向到标准输入
1>&0 命令是在子进程中执行的,这条命令重定向子进程的标准输出到标准输入
     
因此子进程的输出会被发送到标准输入,而我们的标准输入就是我们与题目容器连接的终端
所以会在子进程中执行 cat /ctf* 命令,并且打印在我们的终端上

同理,我们也可以1>&2,因为错误信息也会被打印出来

image

同样得到 flag

image

简化一下写法也可以

再来探讨一下 My6n 师傅的payload:exec cat ctf* 1>&0的实际效果:

关于文件描述符的继承:

exec系统调用会保留当前进程的所有文件描述符
子进程关闭stdout(fd1)的状态不会改变
cat程序仍然向已经关闭的fd1输出

所以exec并不会去调用父进程,即使跳出子进程执行也继承了子进程的文件描述符,也就是说输出流还是关闭的

image

如果exec真的调用了父进程,那么父进程的输出流是正常的,理应就不需要重定向,但是未能拿到flag
说明并没有调用父进程,实际发挥作用的还是1>&0

image

从实践中也能看出来,exec不会起到任何作用

posted @ 2025-08-03 10:40  Claire_cat  阅读(35)  评论(0)    收藏  举报