sctf2021 pwn出题思路
这个题目的编译环境是ollvm编译出的musl libc, 然后使用这个musl去静态编译出文件来。从而得到的文件中的gadget就很少见了。
看到沙盒应该就有对应的思路了,先使用retfq跳到32位使用open, 然后回到64位使用read, 最后通过alarm得到flag,
这应该是shellcode题目常见的思路,
这里相关的gadget都通过内联汇编或者赋值语句放在程序内了,用ropper查找应该会比ROPgadget效果好一些些。
// pop rcx; retn;
int ret = 0xc359;
// jmp $
int b = 0xfeeb;
// retfq
int a = 0xcb48;
// int 80; retn;
int b = 0xc380cd;
asm volatile(
"movb (%rsi, %rax), %bl\n\t"
"mov %rbx, %rdi\n\t"
"push %r14\n\t"
"ret\n\t"
);
其实个人对于gadget的理解是这样的:
一小段代码,它的结构大概是如此: [功能][副作用][再次控制]
,
这个功能是我们想要让他运行的代码。
副作用即 我们运行这个gadget必定会向下运行,必须要让他满足的一些指令,或者会干扰我们利用的一些操作也要去处理掉。
再次控制可以是ret, 或者call/jmp某个寄存器,都是ok的,
于是设计题目的时候多次使用了一些很不常规的gadget, 可惜出题有些仓促也没怎么测试题目,导致一些位置没处理好,这几个重要的位置也有挺多非预期,也就直接公布这个题解大伙看看吧。
原本思路是通过leave栈迁移,
其实这个第一条完全可用,而且比第一条还短。
那么这里有一个长度限制,使用pop rdi, jmp rax;
会比pop rdi; pop rap; ret
少一个字节,
并且在main函数返回的时候已经设置好了这个rax的值
看到wp很多师傅通过pop rsp进行栈迁移了,这个在出题的时候确实没有考虑到,这个方案可以更简单一些。
在gadget中其实是没有可用的pop rdx
相关的,
这个最后的
ret 0xfdbf;
会让栈降低 0xfdbf个大小,不可控
但是有个这样的gadget路线