PHP前端开发

C程序和子进程

百变鹏仔 1个月前 (01-18) #Python
文章标签 进程
问题内容

我编写了这个简单的 c 程序来解释具有相同特征的更困难的问题。

#include <stdio.h>int main(int argc, char *argv[]){    int n;    while (1){        scanf("%d", &amp;n);        printf("%d", n);    }    return 0;}</stdio.h>

它按预期工作。

我还编写了一个子进程脚本来与该程序交互:

from subprocess import popen, pipe, stdoutprocess = popen("./a.out", stdin=pipe, stdout=pipe, stderr=stdout)# sending a byteprocess.stdin.write(b'3')process.stdin.flush()# reading the echo of the numberprint(process.stdout.readline())process.stdin.close()

问题是,如果我运行 python 脚本,执行会在 readline() 上冻结。事实上,如果我中断脚本,我会得到:

/tmp » python script.py^ctraceback (most recent call last):  file "/tmp/script.py", line 10, in <module>    print(process.stdout.readline())          ^^^^^^^^^^^^^^^^^^^^^^^^^keyboardinterrupt</module>

如果我更改我的 python 脚本:

from subprocess import popen, pipe, stdoutprocess = popen("./a.out", stdin=pipe, stdout=pipe, stderr=stdout)with process.stdin as pipe:    pipe.write(b"3")    pipe.flush()# reading the echo of the numberprint(process.stdout.readline())# sending another num:pipe.write(b"4")pipe.flush()process.stdin.close()

我得到了这个输出:

» python script.pyb'3'Traceback (most recent call last):  File "/tmp/script.py", line 13, in <module>    pipe.write(b"4")ValueError: write to closed file</module>

这意味着第一个输入已正确发送,并且读取已完成。

我真的找不到解释这种行为的东西;有人可以帮助我理解吗?提前致谢

[编辑]:由于有很多要点需要澄清,所以我添加了此编辑。我正在使用 rop 技术进行缓冲区溢出漏洞利用的培训,并且我正在编写一个 python 脚本来实现这一目标。为了利用这个漏洞,由于aslr,我需要发现libc地址并使程序重新启动而不终止。由于脚本将在目标机器上执行,我不知道哪些库可用,那么我将使用 subprocess,因为它是内置于 python 中的。不详细说明,攻击在第一个 scanf 上发送一系列字节,目的是泄漏 libc 基地址并重新启动程序;然后发送第二个有效负载以获得一个 shell,我将通过它以交互模式进行通信。

这就是为什么:

  1. 我只能使用内置库
  2. 我必须发送字节并且无法附加结尾 :我的有效负载将无法对齐或可能导致失败
  3. 我需要保持 stdin 打开
  4. 我无法更改 c 代码

正确答案


更改这些:

这对我有用:

#include <stdio.h>int main(int argc, char *argv[]){    int n;    while (1){        scanf("%d", &amp;n);        printf("%d", n);        fflush(stdout);  /* i've added this line only. */    }    return 0;}</stdio.h>
import subprocessp = subprocess.popen(    ('./a.out',), stdin=subprocess.pipe, stdout=subprocess.pipe)try:  print('a'); p.stdin.write(b'42 '); p.stdin.flush()  print('b'); print(repr(p.stdout.readline()));  print('c'); p.stdin.write(b'43'); p.stdin.flush()  print('d'); print(repr(p.stdout.readline()));finally:  print('e'); print(p.kill())

原始 c 程序在终端窗口中交互运行时能够正常工作的原因是,在 c 中,当将换行符 () 写入终端时,输出会自动刷新。因此 printf("%d", n); 最后会隐式执行 fflush(stdout); 。

当使用 subprocess 从 python 运行时,原始 c 程序无法工作的原因是它将输出写入管道(而不是终端),并且没有自动刷新到管道。发生的情况是,python 程序正在等待字节,而 c 程序不会将这些字节写入管道,但它正在等待更多字节(在下一个 scanf 中),因此两个程序都在无限期地等待对方。 (但是,在输出几 kib(通常为 8192 字节)后,将会出现部分自动刷新。但是单个十进制数太短,无法触发该操作。)

如果无法更改 c 程序,那么您应该使用终端设备而不是管道来在 c 和 python 程序之间进行通信。 pty python 模块可以创建终端设备,这对我来说适用于你的原始 c 程序:

import os, pty, subprocessmaster_fd, slave_fd = pty.openpty()p = subprocess.popen(    ('./a.out',), stdin=slave_fd, stdout=slave_fd,    preexec_fn=lambda: os.close(master_fd))try:  os.close(slave_fd)  master = os.fdopen(master_fd, 'rb+', buffering=0)  print('a'); master.write(b'42'); master.flush()  print('b'); print(repr(master.readline()));  print('c'); master.write(b'43'); master.flush()  print('d'); print(repr(master.readline()));finally:  print('e'); print(p.kill())

如果你不想从python发送换行符,这里有一个没有换行符的解决方案,它对我有用:

import os, pty, subprocess, termiosmaster_fd, slave_fd = pty.openpty()ts = termios.tcgetattr(master_fd)ts[3] &amp;= ~(termios.ICANON | termios.ECHO)termios.tcsetattr(master_fd, termios.TCSANOW, ts)p = subprocess.Popen(    ('./a.out',), stdin=slave_fd, stdout=slave_fd,    preexec_fn=lambda: os.close(master_fd))try:  os.close(slave_fd)  master = os.fdopen(master_fd, 'rb+', buffering=0)  print('A'); master.write(b'42 '); master.flush()  print('B'); print(repr(master.readline()));  print('C'); master.write(b'43	'); master.flush()  print('D'); print(repr(master.readline()));finally:  print('E'); print(p.kill())