watctf_f25_PWN_WP
intro2pwn
check:
1 |
|
source:
1 |
|
没有栈可执行保护,并且知道栈地址,而且还有足够的写入和栈溢出,我们可以直接写入 shellcode 然后栈溢出劫持程序流来完成 getshell 。
exp:
1 |
|
hex-editor-xtended-v2
check:
1 |
|
source:
1 |
|
该程序本身并不存在什么漏洞,程序明显提示 /secret.txt 就是 flag。但是 realpath 函数和 strncmp 函数的双组合过滤让我们无法通过 .. 或 / 组合路径绕过检查。( realpath 函数是一个标志库函数用于将 linux 路径化成最简形式)
最有意思的地方才是这里。在 linux 中存在着一个文件 /proc/self/mem 只要任何一个程序使用 fopen 去打开这个路径都是会自动判断打开自己程序的内存文件。
没错,今天我才理解了什么叫 linux 下皆为文件。
并且这种打开方式可以让我们任意读取和修改内存而不受限于 linux 的内存读写执行权限控制。也就是说我们可以读写内存里面的每一个字节包括原本被判断为本不应该读写的内容。
1 |
|
通过逆向我们可以很容易发现 strncmp(path, “/secret.txt”, strlen(“/secret.txt”)) == 0 这个一语句的第二参数是硬编码在内存中:
1 |
|
经过其处于只读段但是我们通过 fopen 打开内存文件读写这种姿势完全不受限制,这意味着我们可以修改该硬编码的第一个字节为 ‘\x00’ 这样就绕过了不能读写 /secret.txt 文件的限制。
tips: 写入两次 ‘\x00’ 是因为第一次写入后文件不会马上保存导致 ‘\x00’ 待在缓冲区中,而连续写入两次就能解决这个问题。
exp:
1 |
|
person-tracker
check:
1 |
|
source:
1 |
|
ida:
1 |
|
根据源代码和逆向可知 flag 将会被加载到地址 0x49B21E 处。
很明显,代码中的注释表明我有 null by one 漏洞。
程序依靠 Person 结构体中的 struct Person *next 来索引下一个 Person 结构体,而新创建的结构体总是在头上。
通过调试我们发现:
1 |
|
我们可以发现地址 0x2e169d90 为 struct Person *next 指向的是 0x2e169d40,我们可以用 null by one 修改 0x2e169d90 地址处的 0x2e169d40 为 0x2e169d00 。
此时 0x2e169d00 + 0x20 处正好是 0x2e169d10 所在的 Person 结构体可编辑的位置,我们可以修改这里的地址为 0x49B21E - 0x8 的位置,从而通过 2 号 Person 结构体查看其 name 来将 flag 打印出来。
tips: 远程与本地所使用的 libc 略有不同,所以堆块的数量要做微调才能打通。
exp:
1 |
|