22 个版本 (14 个稳定版)
2.0.4 | 2024年7月24日 |
---|---|
2.0.1 | 2024年7月22日 |
1.1.0 | 2024年7月20日 |
1.0.7 | 2024年6月21日 |
0.1.0 | 2023年6月10日 |
#126 in 网络编程
每月767次下载
2MB
17K SLoC
pistol-rs
库必须以 root(Linux、*BSD)或管理员(Windows)的身份运行,建议使用 rust 的稳定版。
从 crates.io 导入
[dependencies]
pistol = "^2"
在 Windows 上,从这里下载 winpcap
这里 或 npcap
这里,然后将 x64 文件夹中的 Packet.lib
放置在您的代码根目录下(注意:根据 libpnet 的文档,libpnet 没有测试 npcap)。
跨平台支持
平台 | 注意 |
---|---|
Linux | 支持 |
Unix (*BSD, MacOS) | 支持 |
Windows | 支持(winpcap 或 npcap) |
libpnet 在 Windows 上的错误
错误问题: https://github.com/libpnet/libpnet/issues/707,libpnet 无法在 Windows 上获取 IPv6 地址。
因此,直到 libpnet 修复此错误,Windows 上尚不支持 IPv6。
rust 夜间版本上的 libpnet 错误
错误问题: https://github.com/libpnet/libpnet/issues/686
主机发现(Ping 扫描)
`pistol` 主机发现的实现根据 nmap 文档。
方法 | 详细文档 | 注意 |
---|---|---|
[x] TCP SYN Ping | nmap 参考 | IPv4 & IPv6 |
[x] TCP ACK Ping | nmap 参考 | IPv4 & IPv6 |
[x] UDP Ping | nmap 参考 | IPv4 & IPv6 |
[x] ICMP Ping | nmap 参考 | IPv4 & IPv6 (ICMP, ICMPv6) |
[x] ARP 扫描 | nmap 参考 | IPv4 |
[ ] IP 协议 Ping | nmap 参考 | 复杂且不太有用 |
端口扫描技术和算法
`pistol` 端口扫描的实现根据 nmap pdf 和 文档。
方法 | 详细文档 | 注意 |
---|---|---|
[x] TCP SYN 扫描 | nmap 参考 | IPv4 & IPv6 |
[x] TCP Connect() 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP FIN 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP Null 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP Xmas 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP ACK 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP 窗口扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP Maimon 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] UDP 扫描 | nmap 参考 | IPv4 & IPv6 |
[√] TCP 空闲扫描 | nmap 参考 | IPv4 |
[ ] IP 协议扫描 | nmap 参考 | 复杂且不太有用 |
[ ] TCP FTP 反向扫描 | nmap 参考 | 已修复被利用的漏洞 |
洪水攻击
方法 | 注意 |
---|---|
[√] TCP SYN 洪水 | IPv4 & IPv6 支持 |
[√] TCP ACK 洪水 | IPv4 & IPv6 支持 |
[√] UDP 洪水 | IPv4 & IPv6 支持 |
[√] ICMP 洪水 | IPv4 & IPv6 支持 (ICMP, ICMPv6) |
远程操作系统检测
方法 | 详细文档 | 注意 |
---|---|---|
[√] IPv4 操作系统检测 | nmap 参考 | 现在支持以 nmap 格式打印指纹 |
[√] IPv6 操作系统检测 | nmap 参考 | 现在支持以 nmap 格式打印指纹 |
IPv6 上的操作系统检测?
在 ipv6 上,指纹对于人类来说难以阅读且没有意义,有关详细信息,请参阅此处,nmap 使用逻辑回归在 ipv6 上匹配目标操作系统,但匹配算法相当过时,设计逻辑复杂。
第一点是关于在ipv6检测中的指纹中的ST
、RT
和EXTRA
度量标准,这三个度量标准在代码中完全没有使用,同时没有详细说明如何计算ST
和RT
,我不知道为什么 nmap 会保留它们在最终的指纹中。
第二点是NI
探测。在 nmap 的相关文档中,它描述了NI
探测的具体结构,但我没有在代码中看到任何关于它的内容,并且它似乎在逻辑回归预测时完全忽略了这种探测。
此外,对于当前主流操作系统,ipv6 指纹支持不如 ipv4 丰富,因此请先尝试 ipv4。
服务和应用程序版本检测
方法 | 详细文档 |
---|---|
[√] IPv4 服务扫描 | nmap 参考 |
[√] IPv6 服务扫描 | nmap 参考 |
调试
use pistol::Logger;
fn main() -> Result<()> {
Logger::init_debug_logging()?;
// Logger::init_warn_logging()?;
// your code below
...
}
示例
0. 创建目标
现在您可以在创建扫描目标时包含 IPv4 和 IPv6 地址,并且 pistol
将自动调用相应的算法来处理。
但是请注意,某些算法只能与某些协议一起使用,例如,空闲扫描只能与 IPv4 一起使用,如果与 IPv6 一起使用,则不会执行任何操作,并显示警告消息。
use pistol::Target;
use pistol::Host;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
fn main() -> Result<()> {
let dst_ipv4 = Ipv4Addr::new(192, 168, 72, 134);
let host1 = Host::new(dst_ipv4.into(), Some(vec![22, 99]));
let dst_ipv6 = Ipv6Addr::new(0xfe80, 0, 0, 0, 0x020c, 0x29ff, 0xfeb6, 0x8d99);
let host2 = Host::new(dst_ipv6.into(), Some(vec![443, 8080]));
let target = Target::new(vec![host1, host2]);
// your code below
...
}
注意
如果您不想使用 Target
,您也可以使用我们提供的 _raw
函数,例如,tcp_syn_scan
的相应原始函数是 tcp_syn_scan_raw
。
1. SYN 端口扫描示例
use pistol::scan::tcp_syn_scan;
use pistol::Target;
use pistol::Host;
use std::net::Ipv4Addr;
use std::time::Duration;
use anyhow::Result;
fn main() -> Result<()> {
// When using scanning, please use a real local address to get the return packet.
// And for flood attacks, please consider using a fake address.
// If the value here is None, the programme will automatically look up the available addresses from the existing interfaces on the device.
let src_ipv4 = None;
// If the value of `source port` is `None`, the program will generate the source port randomly.
let src_port = None;
// The destination address is required.
let dst_ipv4 = Ipv4Addr::new(192, 168, 72, 134);
let threads_num = 8;
let timeout = Some(Duration::new(1, 0));
// Test with an open port `22` and a closed port `99`.
let host = Host::new(dst_ipv4.into(), Some(vec![22, 99]));
// Users should build the `target` themselves.
let target = Target::new(vec![host]);
// Number of tests
let tests = 4;
let ret = tcp_syn_scan(
target,
src_ipv4,
src_port,
threads_num,
timeout,
tests
).unwrap();
println!("{}", ret);
Ok(())
}
或者
use pistol::scan::tcp_syn_scan_raw;
use std::net::Ipv4Addr;
use std::time::Duration;
use anyhow::Result;
fn main() -> Result<()> {
let dst_ipv4 = Ipv4Addr::new(192, 168, 72, 134);
let dst_port = 80;
let src_ipv4 = None;
let src_port = None;
let timeout = Some(Duration::new(1, 0));
let (ret, _rtt) =
tcp_syn_ping_raw(dst_ipv4.into(), dst_port, src_ipv4, src_port, timeout)?;
println!("{:?}", ret);
Ok(())
}
输出
+----------------+------+-----------------------------+
| Scan Results |
+----------------+------+-----------------------------+
| 192.168.72.134 | 22 | open|open|open|open |
+----------------+------+-----------------------------+
| 192.168.72.134 | 99 | closed|closed|closed|closed |
+----------------+------+-----------------------------+
| avg rtt: 51.5ms |
| open ports: 1 |
+----------------+------+-----------------------------+
2. 远程操作系统检测示例
测试目标服务器是 ubuntu 22.04 服务器。
use pistol::os::os_detect;
use pistol::Target;
use pistol::Host;
use std::net::Ipv4Addr;
use std::time::Duration;
use anyhow::Result;
fn main() -> Result<()> {
// If the value of `src_ipv4` is `None`, the program will find it auto.
let src_ipv4 = None;
// If the value of `src_port` is `None`, the program will generate it randomly.
let src_port = None;
let dst_ipv4 = Ipv4Addr::new(192, 168, 72, 134);
// `dst_open_tcp_port` must be a certain open tcp port.
let dst_open_tcp_port = 22;
// `dst_closed_tcp_port` must be a certain closed tcp port.
let dst_closed_tcp_port = 8765;
// `dst_closed_udp_port` must be a certain closed udp port.
let dst_closed_udp_port = 9876;
let host = Host::new(
dst_ipv4.into(),
Some(vec![
dst_open_tcp_port, // The order of these three ports cannot be disrupted.
dst_closed_tcp_port,
dst_closed_udp_port,
]),
);
let target = Target::new(vec![host]);
let timeout = Some(Duration::new(3, 0));
let top_k = 3;
let threads_num = 8;
// The `fingerprint` is the obtained fingerprint of the target OS.
// Return the `top_k` best results (the number of os detect result may not equal to `top_k`), sorted by score.
let ret = os_detect(
target,
src_ipv4,
src_port,
top_k,
threads_num,
timeout,
)?;
println!("{}", ret);
Ok(())
}
输出
+----------------+------+--------+--------------------------------------------------------------------------------------------------------------+
| OS Detect Results |
+----------------+------+--------+--------------------------------------------------------------------------------------------------------------+
| 192.168.72.134 | #1 | 82/101 | # Linux 4.15.0-88-generic #88~16.04.1-Ubuntu SMP Wed Feb 12 04:19:15 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux |
| | | | # Linux 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64 GNU/Linux |
| | | | # Linux 5.0.0-32-generic #34~18.04.2-Ubuntu SMP Thu Oct 10 10:36:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux |
| | | | # Linux 5.2.10-yocto-standard #1 SMP PREEMPT Fri Oct 4 11:58:01 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux |
| | | | # Linux 5.3.0-kali3-amd64 |
| | | | # Linux 5.3.16-200.fc30.x86_64 #1 SMP Fri Dec 13 17:48:38 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux |
| | | | # Linux 5.4.6-amd64.gbcm #3 SMP Thu Dec 26 13:55:41 -03 2019 x86_64 GNU/Linux |
| | | | # Linux 5.6.15-arch1-1 #1 SMP PREEMPT Wed, 27 May 2020 23:42:26 +0000 x86_64 GNU/Linux |
| | | | # Linux 5.2.11-arch1-1-ARCH |
| | | | # Linux 5.4.0-1012-raspi #12-Ubuntu SMP Wed May 27 04:08:35 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux |
+----------------+------+--------+--------------------------------------------------------------------------------------------------------------+
| 192.168.72.134 | #2 | 81/101 | # Linux 5.0.0-23-generic #24-Ubuntu SMP Mon Jul 29 15:36:44 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux |
| | | | # Linux 5.3.0-24-generic x86_64 Ubuntu 19.10 |
| | | | # Linux 5.3.9-sunxi (root@builder) (gcc version 7.4.1 20181213 [linaro-7.4-2019.02 |
+----------------+------+--------+--------------------------------------------------------------------------------------------------------------+
| 192.168.72.134 | #3 | 80/101 | # Linux 5.4.0-1008-raspi #8-Ubuntu SMP Wed Apr 8 11:13:06 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux |
+----------------+------+--------+--------------------------------------------------------------------------------------------------------------+
3. IPv6 上的远程操作系统检测示例
测试目标服务器是 ubuntu 22.04 服务器。
use pistol::os::os_detect;
use pistol::Target;
use pistol::Host;
use std::net::Ipv4Addr;
use std::time::Duration;
use anyhow::Result;
fn main() -> Result<()> {
let src_ipv6 = None;
let dst_ipv6: Ipv6Addr = "fe80::20c:29ff:feb6:8d99".parse().unwrap();
let dst_open_tcp_port = 22;
let dst_closed_tcp_port = 8765;
let dst_closed_udp_port = 9876;
let host = Host::new(
dst_ipv6.into(),
Some(vec![
dst_open_tcp_port,
dst_closed_tcp_port,
dst_closed_udp_port,
]),
);
let target = Target::new(vec![host]);
let src_port = None;
let timeout = Some(Duration::new(3, 0));
let top_k = 3;
let threads_num = 8;
let ret = os_detect(target, src_ipv6, src_port, top_k, threads_num, timeout)?;
println!("{}", ret);
Ok(())
}
输出
+---------------- ---------+------+------+--------------------------+
| OS Detect Results |
+--------------------------+------+------+--------------------------+
| fe80::20c:29ff:feb6:8d99 | #1 | 0.9 | Linux 4.19 |
+--------------------------+------+------+--------------------------+
| fe80::20c:29ff:feb6:8d99 | #2 | 0.7 | Linux 3.13 - 4.6 |
+--------------------------+------+------+--------------------------+
| fe80::20c:29ff:feb6:8d99 | #3 | 0.0 | Android 7.1 (Linux 3.18) |
+--------------------------+------+------+--------------------------+
根据 nmap文档,如果探测结果的意义不小于 15
,则 novelty
值(表中的第三列)必须小于 15
,因此当此值大于 15
时,返回空列表。同样,当两个最高 OS 类别的分数相差不到 10%
时,分类被认为是模糊的,并且不是成功的匹配。
3. 远程服务检测示例
- 192.168.1.51 - Ubuntu 22.04 (ssh: 22, httpd: 80)
use pistol::vs::vs_scan;
use pistol::vs::ExcludePorts;
use pistol::Target;
use pistol::Host;
use std::net::Ipv4Addr;
use std::time::Duration;
use anyhow::Result;
fn main() -> Result<()> {
let dst_addr = Ipv4Addr::new(192, 168, 1, 51);
let host = Host::new(dst_addr.into(), Some(vec![22, 80]));
let target = Target::new(vec![host]);
let threads_num = 8;
let timeout = Some(Duration::new(1, 0));
// only_null_probe = true, only_tcp_recommended = any, only_udp_recomended = any: only try the NULL probe (for TCP)
// only_tcp_recommended = true: only try the tcp probe recommended port
// only_udp_recommended = true: only try the udp probe recommended port
let (only_null_probe, only_tcp_recommended, only_udp_recomended) = (false, true, true);
let exclude_ports = Some(ExcludePorts::new(vec![51, 52]));
let intensity = 7; // nmap default
let ret = vs_scan(
target,
only_null_probe,
only_tcp_recommended,
only_udp_recommended,
exclude_ports,
intensity,
threads_num,
timeout,
)?;
println!("{}", ret);
Ok(())
}
输出
+--------------+--------+--------+
| Service Scan Results |
+--------------+--------+--------+
| 192.168.1.51 | 22 | ssh |
+--------------+--------+--------+
| 192.168.1.51 | 80 | http |
+--------------+--------+--------+
依赖关系
~7–17MB
~196K SLoC