如果python可执行文件是通过“env”指定的,那么ptrace将破坏堆栈
我试图截取如果python可执行文件是通过“env”指定的,那么ptrace将破坏堆栈,python,linux,environment-variables,ptrace,stack-smash,Python,Linux,Environment Variables,Ptrace,Stack Smash,我试图截取getrandomsyscall并修改其结果。我试着制作一个最小的可复制示例,如下所示:[原始代码库是用Rust编写的,大约有400行,进行了正确的错误检查,并且遇到了相同的问题] #include <stdio.h> #include <stdlib.h> #include <sys/ptrace.h> #include <sys/reg.h> #include <sys/syscall.h> #include <s
getrandom
syscall并修改其结果。我试着制作一个最小的可复制示例,如下所示:[原始代码库是用Rust编写的,大约有400行,进行了正确的错误检查,并且遇到了相同的问题]
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
void wait_sigtrap() {
int status;
wait(&status);
if (WIFEXITED(status)) exit(0);
}
int main() {
pid_t child = fork();
if (child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
const char* file = "./pi.py";
if (execl(file, file, "1000", NULL) < 0) {
perror("execl");
return 1;
};
} else {
pid_t pid = child;
wait_sigtrap(); // there will be an initial stop after traceme, ignore
// it
ptrace(PTRACE_SYSCALL, pid, 0, 0); // wait for another
for (;;) {
// detect enter, get syscall no
wait_sigtrap();
long no = ptrace(PTRACE_PEEKUSER, pid, 8 * ORIG_RAX, 0);
if (no != SYS_getrandom) {
ptrace(PTRACE_SYSCALL, pid, 0, 0); // wait for another
wait_sigtrap(); // wait for exit
} else {
// getrandom
long bufptr = ptrace(PTRACE_PEEKUSER, pid, 8 * RDI, 0);
long buflen = ptrace(PTRACE_PEEKUSER, pid, 8 * RSI, 0);
printf("getrandom request: 0x%016lx 0x%016lx\n", bufptr,
buflen);
fflush(stdout);
ptrace(PTRACE_SYSCALL, pid, 0, 0); // wait for another
wait_sigtrap(); // wait for exit
long ret = ptrace(PTRACE_PEEKUSER, pid, 8 * ORIG_RAX, 0);
if (ret < 0) {
printf("Syscall %ld exited with an error, not touching it",
no);
fflush(stdout);
} else {
long ind = 0;
while (ind < buflen) {
ptrace(PTRACE_POKEDATA, pid, bufptr + ind, 0);
ind += sizeof(long);
}
}
}
ptrace(PTRACE_SYSCALL, pid, 0, 0); // wait for another
}
}
return 0;
}
这将触发堆栈破坏保护:
getrandom request: 0x00007fee772e29a0 0x0000000000000018
getrandom request: 0x00007ffc1788eb90 0x00000000000009c0
getrandom request: 0x00007ffc1788e420 0x00000000000009c0
*** stack smashing detected ***: python terminated
======= Backtrace: =========
/usr/lib/libc.so.6(+0x7254c)[0x7fee7735554c]
/usr/lib/libc.so.6(__fortify_fail+0x37)[0x7fee773e1307]
/usr/lib/libc.so.6(__fortify_fail+0x0)[0x7fee773e12d0]
/usr/lib/python3.6/lib-dynload/_random.cpython-36m-x86_64-linux-gnu.so(+0x1285)[0x7fee75169285]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fe:00 22965216 /usr/bin/python3.6
00601000-00602000 r--p 00001000 fe:00 22965216 /usr/bin/python3.6
00602000-00603000 rw-p 00002000 fe:00 22965216 /usr/bin/python3.6
0082e000-00924000 rw-p 00000000 00:00 0 [heap]
7fee74f2e000-7fee74f44000 r-xp 00000000 fe:00 22941269 /usr/lib/libgcc_s.so.1
7fee74f44000-7fee75143000 ---p 00016000 fe:00 22941269 /usr/lib/libgcc_s.so.1
7fee75143000-7fee75144000 r--p 00015000 fe:00 22941269 /usr/lib/libgcc_s.so.1
7fee75144000-7fee75145000 rw-p 00016000 fe:00 22941269 /usr/lib/libgcc_s.so.1
7fee75168000-7fee7516c000 r-xp 00000000 fe:00 23600949 /usr/lib/python3.6/lib-dynload/_random.cpython-36m-x86_64-linux-gnu.so
7fee7516c000-7fee7536b000 ---p 00004000 fe:00 23600949 /usr/lib/python3.6/lib-dynload/_random.cpython-36m-x86_64-linux-gnu.so
7fee7536b000-7fee7536c000 r--p 00003000 fe:00 23600949 /usr/lib/python3.6/lib-dynload/_random.cpython-36m-x86_64-linux-gnu.so
7fee7536c000-7fee7536d000 rw-p 00004000 fe:00 23600949 /usr/lib/python3.6/lib-dynload/_random.cpython-36m-x86_64-linux-gnu.so
7fee7536d000-7fee7536f000 r-xp 00000000 fe:00 23600965 /usr/lib/python3.6/lib-dynload/_bisect.cpython-36m-x86_64-linux-gnu.so
7fee7536f000-7fee7556e000 ---p 00002000 fe:00 23600965 /usr/lib/python3.6/lib-dynload/_bisect.cpython-36m-x86_64-linux-gnu.so
7fee7556e000-7fee7556f000 r--p 00001000 fe:00 23600965 /usr/lib/python3.6/lib-dynload/_bisect.cpython-36m-x86_64-linux-gnu.so
7fee7556f000-7fee75570000 rw-p 00002000 fe:00 23600965 /usr/lib/python3.6/lib-dynload/_bisect.cpython-36m-x86_64-linux-gnu.so
7fee75570000-7fee75586000 r-xp 00000000 fe:00 23600924 /usr/lib/python3.6/lib-dynload/_sha3.cpython-36m-x86_64-linux-gnu.so
7fee75586000-7fee75785000 ---p 00016000 fe:00 23600924 /usr/lib/python3.6/lib-dynload/_sha3.cpython-36m-x86_64-linux-gnu.so
7fee75785000-7fee75786000 r--p 00015000 fe:00 23600924 /usr/lib/python3.6/lib-dynload/_sha3.cpython-36m-x86_64-linux-gnu.so
7fee75786000-7fee75788000 rw-p 00016000 fe:00 23600924 /usr/lib/python3.6/lib-dynload/_sha3.cpython-36m-x86_64-linux-gnu.so
7fee75788000-7fee75796000 r-xp 00000000 fe:00 23600925 /usr/lib/python3.6/lib-dynload/_blake2.cpython-36m-x86_64-linux-gnu.so
7fee75796000-7fee75995000 ---p 0000e000 fe:00 23600925 /usr/lib/python3.6/lib-dynload/_blake2.cpython-36m-x86_64-linux-gnu.so
7fee75995000-7fee75996000 r--p 0000d000 fe:00 23600925 /usr/lib/python3.6/lib-dynload/_blake2.cpython-36m-x86_64-linux-gnu.so
7fee75996000-7fee75997000 rw-p 0000e000 fe:00 23600925 /usr/lib/python3.6/lib-dynload/_blake2.cpython-36m-x86_64-linux-gnu.so
7fee75997000-7fee75be8000 r-xp 00000000 fe:00 22946259 /usr/lib/libcrypto.so.1.1
7fee75be8000-7fee75de7000 ---p 00251000 fe:00 22946259 /usr/lib/libcrypto.so.1.1
7fee75de7000-7fee75e05000 r--p 00250000 fe:00 22946259 /usr/lib/libcrypto.so.1.1
7fee75e05000-7fee75e0f000 rw-p 0026e000 fe:00 22946259 /usr/lib/libcrypto.so.1.1
7fee75e0f000-7fee75e12000 rw-p 00000000 00:00 0
7fee75e12000-7fee75e18000 r-xp 00000000 fe:00 23600946 /usr/lib/python3.6/lib-dynload/_hashlib.cpython-36m-x86_64-linux-gnu.so
7fee75e18000-7fee76017000 ---p 00006000 fe:00 23600946 /usr/lib/python3.6/lib-dynload/_hashlib.cpython-36m-x86_64-linux-gnu.so
7fee76017000-7fee76018000 r--p 00005000 fe:00 23600946 /usr/lib/python3.6/lib-dynload/_hashlib.cpython-36m-x86_64-linux-gnu.so
7fee76018000-7fee76019000 rw-p 00006000 fe:00 23600946 /usr/lib/python3.6/lib-dynload/_hashlib.cpython-36m-x86_64-linux-gnu.so
7fee76019000-7fee76023000 r-xp 00000000 fe:00 23600935 /usr/lib/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so
7fee76023000-7fee76222000 ---p 0000a000 fe:00 23600935 /usr/lib/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so
7fee76222000-7fee76223000 r--p 00009000 fe:00 23600935 /usr/lib/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so
7fee76223000-7fee76225000 rw-p 0000a000 fe:00 23600935 /usr/lib/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so
7fee76225000-7fee76265000 rw-p 00000000 00:00 0
7fee76265000-7fee76268000 r-xp 00000000 fe:00 23600948 /usr/lib/python3.6/lib-dynload/_heapq.cpython-36m-x86_64-linux-gnu.so
7fee76268000-7fee76467000 ---p 00003000 fe:00 23600948 /usr/lib/python3.6/lib-dynload/_heapq.cpython-36m-x86_64-linux-gnu.so
7fee76467000-7fee76468000 r--p 00002000 fe:00 23600948 /usr/lib/python3.6/lib-dynload/_heapq.cpython-36m-x86_64-linux-gnu.so
7fee76468000-7fee7646a000 rw-p 00003000 fe:00 23600948 /usr/lib/python3.6/lib-dynload/_heapq.cpython-36m-x86_64-linux-gnu.so
7fee7646a000-7fee7666a000 rw-p 00000000 00:00 0
7fee7666a000-7fee7677a000 r-xp 00000000 fe:00 22939716 /usr/lib/libm-2.25.so
7fee7677a000-7fee7697a000 ---p 00110000 fe:00 22939716 /usr/lib/libm-2.25.so
7fee7697a000-7fee7697b000 r--p 00110000 fe:00 22939716 /usr/lib/libm-2.25.so
7fee7697b000-7fee7697c000 rw-p 00111000 fe:00 22939716 /usr/lib/libm-2.25.so
7fee7697c000-7fee7697e000 r-xp 00000000 fe:00 22939712 /usr/lib/libutil-2.25.so
7fee7697e000-7fee76b7d000 ---p 00002000 fe:00 22939712 /usr/lib/libutil-2.25.so
7fee76b7d000-7fee76b7e000 r--p 00001000 fe:00 22939712 /usr/lib/libutil-2.25.so
7fee76b7e000-7fee76b7f000 rw-p 00002000 fe:00 22939712 /usr/lib/libutil-2.25.so
7fee76b7f000-7fee76b82000 r-xp 00000000 fe:00 22939717 /usr/lib/libdl-2.25.so
7fee76b82000-7fee76d81000 ---p 00003000 fe:00 22939717 /usr/lib/libdl-2.25.so
7fee76d81000-7fee76d82000 r--p 00002000 fe:00 22939717 /usr/lib/libdl-2.25.so
7fee76d82000-7fee76d83000 rw-p 00003000 fe:00 22939717 /usr/lib/libdl-2.25.so
7fee76d83000-7fee7704a000 r-xp 00000000 fe:00 22965217 /usr/lib/libpython3.6m.so.1.0
7fee7704a000-7fee77249000 ---p 002c7000 fe:00 22965217 /usr/lib/libpython3.6m.so.1.0
7fee77249000-7fee7724c000 r--p 002c6000 fe:00 22965217 /usr/lib/libpython3.6m.so.1.0
7fee7724c000-7fee772b2000 rw-p 002c9000 fe:00 22965217 /usr/lib/libpython3.6m.so.1.0
7fee772b2000-7fee772e3000 rw-p 00000000 00:00 0
7fee772e3000-7fee7747f000 r-xp 00000000 fe:00 22939771 /usr/lib/libc-2.25.so
7fee7747f000-7fee7767e000 ---p 0019c000 fe:00 22939771 /usr/lib/libc-2.25.so
7fee7767e000-7fee77682000 r--p 0019b000 fe:00 22939771 /usr/lib/libc-2.25.so
7fee77682000-7fee77684000 rw-p 0019f000 fe:00 22939771 /usr/lib/libc-2.25.so
7fee77684000-7fee77688000 rw-p 00000000 00:00 0
7fee77688000-7fee776a1000 r-xp 00000000 fe:00 22939790 /usr/lib/libpthread-2.25.so
7fee776a1000-7fee778a0000 ---p 00019000 fe:00 22939790 /usr/lib/libpthread-2.25.so
7fee778a0000-7fee778a1000 r--p 00018000 fe:00 22939790 /usr/lib/libpthread-2.25.so
7fee778a1000-7fee778a2000 rw-p 00019000 fe:00 22939790 /usr/lib/libpthread-2.25.so
7fee778a2000-7fee778a6000 rw-p 00000000 00:00 0
7fee778a6000-7fee778c9000 r-xp 00000000 fe:00 22939772 /usr/lib/ld-2.25.so
7fee778ca000-7fee778ef000 rw-p 00000000 00:00 0
7fee778ef000-7fee77aa2000 r--p 00000000 fe:00 22961001 /usr/lib/locale/locale-archive
7fee77aa2000-7fee77aa6000 rw-p 00000000 00:00 0
7fee77ac8000-7fee77ac9000 rw-p 00000000 00:00 0
7fee77ac9000-7fee77aca000 r--p 00023000 fe:00 22939772 /usr/lib/ld-2.25.so
7fee77aca000-7fee77acb000 rw-p 00024000 fe:00 22939772 /usr/lib/ld-2.25.so
7fee77acb000-7fee77acc000 rw-p 00000000 00:00 0
7ffc17872000-7ffc17893000 rw-p 00000000 00:00 0 [stack]
7ffc17917000-7ffc17919000 r--p 00000000 00:00 0 [vvar]
7ffc17919000-7ffc1791b000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
这个地址区域确实超出了堆栈。此外,当我试图简单地用自定义覆盖器替换getrandom
glibc系统调用时,错误不会出现在任何地方
更有趣的是,只有当我将可执行文件指定为/usr/bin/env python
时,才会出现这种情况。如果我直接指定/usr/bin/python
,一切都会按预期工作
此外,如果python可执行文件是通过env指定的,则存储在RDI和RSI寄存器中的参数将失效(被某些内容覆盖)。如果直接指定了python
,则情况并非如此
如果我使用strace
跟踪直接调用的/pi.py
的执行,即使使用patchedgetrandom
(使用LD\u PRELOAD
),也不会发生任何错误,输出缓冲区也会被成功覆盖。缓冲区完全包含在堆栈中
我正在运行ArchLinux、Linux4.9.36-1-lts、Glibc2.25和Python3.6.1
/编辑:它变得更有趣了。如果我使用LD_PRELOAD
技巧将libc getrandom例程修补为以下一个:
int getrandom(void *buf, size_t buflen, unsigned int flags)
{
(void) flags;
syscall(318, buf, buflen, flags);
printf("Using our getrandom\n");
uint8_t* b = buf;
for (int i = 0; i < buflen; ++i) {
b[i] = 0;
}
return buflen;
}
int getrandom(void*buf、size\t buflen、无符号int标志)
{
(b)旗帜;
系统调用(318,buf,buflen,flags);
printf(“使用我们的getrandom\n”);
uint8_t*b=buf;
对于(int i=0;i
然后,未修改的ptrace
程序成功并按预期工作
/编辑2:它变得更有趣了。在系统调用之后添加任何日志记录都可以神奇地修复该问题。例如,此修补程序:
[这是在commit 0d0a32fb91cdfea1626e6c6b77a9bc44e15a2b8a上测试的]我还没有机会运行您的代码,但我猜您的tracee会自己生成一个ptrace事件,并将您的enter syscall/exit syscall监视延迟一次,因此,你在系统调用结束时观察RSI,它不是我们预期的8这样的小数值,而是大得多。添加env行将添加另一个exec调用,该调用同步执行enter syscall/exit syscall监控。缓冲区长度正确,Python确实请求2496字节的随机数据,请参阅:好的,对不起,一定是其他内容。
ptrace(ptrace_POKEDATA,pid,bufptr+ind,0)
-ifbufptr+ind+sizeof(long)
exceptbufptr+buflen
您遇到了麻烦在这种情况下,它总是与sizeof(long)
对齐。经过一段时间的开发,这个问题神秘地消失了,可能是因为缺少PTRACE\u O\u SYSGOOD
。看见
int getrandom(void *buf, size_t buflen, unsigned int flags)
{
(void) flags;
syscall(318, buf, buflen, flags);
printf("Using our getrandom\n");
uint8_t* b = buf;
for (int i = 0; i < buflen; ++i) {
b[i] = 0;
}
return buflen;
}