02.Scanner

我们在开始做渗透的时候,需要先去目标进行侦察。这次我们用Rust来实现一个自己的扫描器。

现在主要使用的扫描器有两种,被动扫描和主动扫描

被动侦察

被动侦察是在不直接与目标交互的情况下收集有关目标的信息的过程。例如,在不同的社交网络和搜索引擎上搜索目标。
使用公开可用的资源称为 OSINT,用于开源情报。

使用被动侦察收集什么样的数据?通常,有关公司员工的信息片段,例如姓名、电子邮件地址、电话号码,以及源代码存储库、泄露的令牌。多亏了像 Shodan 这样的搜索引擎,我们还可以寻找对世界开放的服务和机器。

主动侦察

主动侦察是通过与目标交互直接收集有关目标的信息的过程。
主动侦察噪音较大,可以被防火墙和蜜罐检测到,因此您必须小心避免被检测到,例如,通过在很长一段时间内传播扫描。

蜜罐是一个虚假的外部端点,给定公司的人永远不会使用它,因此攻击这个端点的唯一人是攻击者。它可以是邮件服务器、HTTP 服务器,甚至是嵌入了远程内容的文档。一旦蜜罐被扫描或命中,它就会向公司的安全团队报告。

金丝雀是相同的,但在内部网络中。其目的是在攻击者突破外部边界后检测他们。

对目标的侦察本身可以分为两个步骤: 资产发现 和 漏洞识别

资产发现

传统上资产仅由技术元素定义:IP 地址、服务器、域名、网络……今天的范围更广,包括社交网络帐户、公共源代码存储库、物联网对象……如今,一切都是在互联网上或连接到互联网,从攻击性的角度来看,这很有趣。列出和映射目标的所有资产的目的是为我们即将到来的攻击找到切入点和漏洞。

子域名枚举

公共资产发现投资回报最大的方法当然是子域枚举。
查找子域的最简单来源是证书透明度日志。当证书颁发机构 (CA) 颁发 Web 证书(例如用于 HTTPS 流量)时,证书将存放在公开的透明日志中。
此类日志的合法用途是检测可能将证书交付给错误实体的流氓证书颁发机构(想象一下 *.google.com 的证书交付给恶意黑客团队,这意味着
他们将能够在不被发现的情况下进入中间人)。
另一方面,这种透明度使我们能够自动化我们的大部分工作,因为如今,大多数互联网服务(以及攻击面)都可以通过 HTTPS 获得。
例如,要搜索为其及其子域颁发的所有证书,请转到 https://crt.sh 并搜索

此方法的局限性在于非 HTTP(S) 服务(例如电子邮件或 VPN 服务器)和通配符子域(例如 *.kerkour.com)可能会混淆所使用的真实子域。

子域名枚举的建议

  1. 有人维护了一些wordlist,包括了常用了子域名,可以帮助发现子域名。
  2. 暴力尝试,很多人是用程序随机生成字符串去尝试,这种效果会非常不好。
  3. 使用Amass来做子域名枚举

我们的第一个Rust扫描器

扫描器分为很多种,有端口扫描,漏洞扫描,子域名扫描,SQL注入扫描,主要就是为了把繁琐的侦察任务自动化,防止一些人为疏忽发生。

但是你也得明白,扫描器不是什么万能的。你需要面对误报,暴露自己的意图被系统ban掉等等。

枚举子域名

我们实现的方法就是通过crt.sh的接口访问来得到子域,访问的API 是 https://crt.sh/?q=%25.%5Bdomain.com%5D&output=json

我们先来看看crt.sh返回的结果:

可以看到是直接得到了域名,那就只需要我们拼凑一个请求就可以了,后面就是直接解析结果。

01.SHA-1 hash cracker

hash cracker的意义

主要是为了熟悉Rust的语法,市面上有很多的hash cracker,比如hashcat等程序,他们优化得很好,建议使用他们。

破解的流程

从上面的SHA-1函数的输入和输出可以看到,我们需要用一个wordlist生成hash。然后和已有的hash进行比较。

那么我们这个工具的命令行如下:

sha1_cracker: <wordlist.txt> <sha1_hash>

我们开始用一个初始程序,这个程序得到传进来的参数并检查参数是否符合要求

use std:: {
    env,
    error::Error,
};

const SHA1_HEX_STRING_LENGTH: usize = 40;


fn main() -> Result<(), Box<dyn Error>> {
   let args: Vec<String> = env::args().collect();

   if args.len() !=3 {
       //println!("input error");
       println!("Usage:\n      sha1_cracker: <wordlist.txt> <sha1_hash>");

       return Ok(());
   }

   let hash_to_crack = args[2].trim();

   if hash_to_crack.len() != SHA1_HEX_STRING_LENGTH {
       return  Err("sha1 hash is not valid".into());
   }

   Ok(())

}

后面就开始读字典来生成hash值并做对比

use sha1::Digest;

use std:: {
    env,
    error::Error,
    fs::File,
    io::{BufRead, BufReader},
};

const SHA1_HEX_STRING_LENGTH: usize = 40;


fn main() -> Result<(), Box<dyn Error>> {
   let args: Vec<String> = env::args().collect();

   if args.len() !=3 {
       //println!("input error");
       println!("Usage:\n      sha1_cracker: <wordlist.txt> <sha1_hash>");

       return Ok(());
   }

   let hash_to_crack = args[2].trim();

   if hash_to_crack.len() != SHA1_HEX_STRING_LENGTH {
       return  Err("sha1 hash is not valid".into());
   }

   let worldlist_file = File::open(&args[1])?;
   let reader = BufReader::new(&worldlist_file);

   for line in reader.lines() {
       let password = line?.trim().to_string();
       let gen_password = hex::encode(sha1::Sha1::digest(password.as_bytes()));
       println!("{}", gen_password);
       
       if hash_to_crack == gen_password {
           println!("password found: {}", &password);
           return Ok(());
       }
   }

   println!("passowrd not found in wordlist!");

   Ok(())

}



Github 链接:https://github.com/xxg1413/Hacking-with-Rust/tree/main/sha1_cracker