mirror of
https://github.com/Stone-Red-Code/FraudCapturer.git
synced 2026-09-04 00:56:05 +02:00
- Switch to console based application
- Add automatic IP blocking - Add automatic domain blocking
This commit is contained in:
+5
-11
@@ -3,24 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.0.32014.148
|
VisualStudioVersion = 17.0.32014.148
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FraudCapturer", "FraudCapturer\FraudCapturer.csproj", "{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FraudCapturer", "FraudCapturer\FraudCapturer.csproj", "{28BC39A1-7295-4270-8A30-BA5DCDD8EF54}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|x64 = Release|x64
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{28BC39A1-7295-4270-8A30-BA5DCDD8EF54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{28BC39A1-7295-4270-8A30-BA5DCDD8EF54}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Debug|x64.ActiveCfg = Debug|x64
|
{28BC39A1-7295-4270-8A30-BA5DCDD8EF54}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Debug|x64.Build.0 = Debug|x64
|
{28BC39A1-7295-4270-8A30-BA5DCDD8EF54}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{B7D42E3E-C88C-4043-BA19-3B5BCA3E2EB8}.Release|x64.Build.0 = Release|x64
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<Application x:Class="FraudCapturer.App"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:local="clr-namespace:FraudCapturer"
|
|
||||||
StartupUri="MainWindow.xaml">
|
|
||||||
<Application.Resources>
|
|
||||||
</Application.Resources>
|
|
||||||
</Application>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace FraudCapturer;
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for App.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class App : Application
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using System.Windows;
|
|
||||||
|
|
||||||
[assembly: ThemeInfo(
|
|
||||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
|
||||||
//(used if a resource is not found in the page,
|
|
||||||
// or application resource dictionaries)
|
|
||||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
|
||||||
//(used if a resource is not found in the page,
|
|
||||||
// app, or any theme specific resource dictionaries)
|
|
||||||
)]
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
using PacketDotNet;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
internal class DomainHelper
|
||||||
|
{
|
||||||
|
public static string[] GetDomainsFromDnsReqest(TransportPacket transportPacket)
|
||||||
|
{
|
||||||
|
List<string> domains = new();
|
||||||
|
MatchCollection matchCollection = Regex.Matches(transportPacket.GetPayloadAsString().ToLower(), @"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]");
|
||||||
|
foreach (Match match in matchCollection)
|
||||||
|
{
|
||||||
|
domains.Add(match.Value);
|
||||||
|
}
|
||||||
|
return domains.Distinct().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DomainInfo? GetDomainReputation(string domain)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IPAddress[] addresslist = Dns.GetHostAddresses(domain);
|
||||||
|
DomainInfo domainInfo = new DomainInfo
|
||||||
|
{
|
||||||
|
IpAddress = addresslist[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpClient httpClient = new HttpClient();
|
||||||
|
httpClient.DefaultRequestHeaders.Add("User-Agent", $"{Program.AppName} - (coming soon)");
|
||||||
|
|
||||||
|
AntiFishReqestBody reqestBody = new AntiFishReqestBody()
|
||||||
|
{
|
||||||
|
Message = domain
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpContent httpContent = new StringContent(JsonSerializer.Serialize(reqestBody), Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
HttpResponseMessage responseMessage = httpClient.PostAsync("https://anti-fish.bitflow.dev/check", httpContent).GetAwaiter().GetResult(); ;
|
||||||
|
|
||||||
|
string resultString = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult(); ;
|
||||||
|
AntiFishResultBody? resultBody = JsonSerializer.Deserialize<AntiFishResultBody>(resultString);
|
||||||
|
|
||||||
|
AntiFishResult? result = resultBody?.Matches?.FirstOrDefault(m => m.Domain == domain);
|
||||||
|
|
||||||
|
if (result is null)
|
||||||
|
{
|
||||||
|
return domainInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
domainInfo.IsMatch = true;
|
||||||
|
domainInfo.TrustRating = result.TrustRating;
|
||||||
|
domainInfo.Source = result.Source;
|
||||||
|
domainInfo.Type = result.Type;
|
||||||
|
|
||||||
|
return domainInfo;
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"error: {ex.Message} ({domain})");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AntiFishReqestBody
|
||||||
|
{
|
||||||
|
[JsonPropertyName("message")]
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AntiFishResult
|
||||||
|
{
|
||||||
|
[JsonPropertyName("followed")]
|
||||||
|
public bool Followed { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("domain")]
|
||||||
|
public string? Domain { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("source")]
|
||||||
|
public string? Source { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string? Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("trust_rating")]
|
||||||
|
public double TrustRating { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AntiFishResultBody
|
||||||
|
{
|
||||||
|
[JsonPropertyName("match")]
|
||||||
|
public bool Match { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("matches")]
|
||||||
|
public List<AntiFishResult>? Matches { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
internal class DomainInfo
|
||||||
|
{
|
||||||
|
public string? Type { get; set; }
|
||||||
|
public string? Source { get; set; }
|
||||||
|
public double TrustRating { get; set; }
|
||||||
|
public bool IsMatch { get; set; }
|
||||||
|
public IPAddress? IpAddress { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
internal class FirewallHelper
|
||||||
|
{
|
||||||
|
public static void BlockIp(IPAddress? ipAddress)
|
||||||
|
{
|
||||||
|
if (ipAddress is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(ipAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRuleIfDoesnotExist(ipAddress);
|
||||||
|
|
||||||
|
File.AppendAllText(Program.IpStorePath, $"{Environment.NewLine}{ipAddress}");
|
||||||
|
|
||||||
|
string[] iPs = File.ReadAllLines(Program.IpStorePath);
|
||||||
|
|
||||||
|
System.Diagnostics.Process process = new System.Diagnostics.Process();
|
||||||
|
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo
|
||||||
|
{
|
||||||
|
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
|
||||||
|
FileName = "cmd.exe",
|
||||||
|
Arguments = $"/C netsh advfirewall firewall set rule name=\"{Program.AppName} IP Block\" new remoteIp={string.Join(',', iPs)}"
|
||||||
|
};
|
||||||
|
process.StartInfo = startInfo;
|
||||||
|
_ = process.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnblockIp(IPAddress? ipAddress)
|
||||||
|
{
|
||||||
|
if (ipAddress is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(ipAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> iPs = File.ReadAllLines(Program.IpStorePath).ToList();
|
||||||
|
iPs.Remove(ipAddress.ToString());
|
||||||
|
|
||||||
|
File.WriteAllLines(Program.IpStorePath, iPs);
|
||||||
|
|
||||||
|
System.Diagnostics.Process process = new System.Diagnostics.Process();
|
||||||
|
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo
|
||||||
|
{
|
||||||
|
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
|
||||||
|
FileName = "cmd.exe",
|
||||||
|
Arguments = $"/C netsh advfirewall firewall set rule name=\"{Program.AppName} IP Block\" new remoteIp={string.Join(',', iPs.ToArray())}"
|
||||||
|
};
|
||||||
|
process.StartInfo = startInfo;
|
||||||
|
_ = process.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddRuleIfDoesnotExist(IPAddress ipAddress)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Process process = new System.Diagnostics.Process();
|
||||||
|
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo
|
||||||
|
{
|
||||||
|
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
|
||||||
|
FileName = "cmd.exe",
|
||||||
|
Arguments = $"/C netsh advfirewall firewall show rule name=\"{Program.AppName} IP Block\" >nul || netsh advfirewall firewall add rule name=\"{Program.AppName} IP Block\" dir=in interface=any action=block remoteIp={ipAddress} && netsh advfirewall firewall add rule name=\"{Program.AppName} IP Block\" dir=out interface=any action=block remoteIp={ipAddress}"
|
||||||
|
};
|
||||||
|
process.StartInfo = startInfo;
|
||||||
|
_ = process.Start();
|
||||||
|
process.WaitForExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>WinExe</OutputType>
|
|
||||||
<TargetPlatformVersion>8.0</TargetPlatformVersion>
|
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="IronOcr" Version="2021.12.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,18 +1,14 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />
|
<PackageReference Include="SharpPcap" Version="6.1.0" />
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="IronOcr" Version="2021.12.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
internal class IpHelper
|
||||||
|
{
|
||||||
|
public static IpInfo? GetIpReputation(IPAddress ipAddress)
|
||||||
|
{
|
||||||
|
HttpClient httpClient = new HttpClient();
|
||||||
|
|
||||||
|
string rawResponseData = httpClient.GetStringAsync($"http://proxycheck.io/v2/{ipAddress}?key=65019k-719i38-2k0r91-36q7o7&risk=2&vpn=1&asn=1&tag={Program.AppName}").GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
JsonDocument responseData = JsonDocument.Parse(rawResponseData);
|
||||||
|
|
||||||
|
if (!responseData.RootElement.TryGetProperty("status", out JsonElement statusValue))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statusValue.GetString() != "ok")
|
||||||
|
{
|
||||||
|
Console.Write(statusValue.GetString());
|
||||||
|
if (responseData.RootElement.TryGetProperty("message", out JsonElement messageValue))
|
||||||
|
{
|
||||||
|
Console.WriteLine($": {messageValue.GetString()}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!responseData.RootElement.TryGetProperty(ipAddress.ToString(), out JsonElement jsonElement))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string type = string.Empty;
|
||||||
|
string provider = string.Empty;
|
||||||
|
bool isProxy = false;
|
||||||
|
int risk = 0;
|
||||||
|
|
||||||
|
if (jsonElement.TryGetProperty("type", out JsonElement typeValue))
|
||||||
|
{
|
||||||
|
type = typeValue.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonElement.TryGetProperty("provider", out JsonElement providerValue))
|
||||||
|
{
|
||||||
|
provider = providerValue.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonElement.TryGetProperty("proxy", out JsonElement proxyValue))
|
||||||
|
{
|
||||||
|
isProxy = proxyValue.GetString() == "yes";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonElement.TryGetProperty("risk", out JsonElement riskValue))
|
||||||
|
{
|
||||||
|
risk = riskValue.GetInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(provider))
|
||||||
|
{
|
||||||
|
provider = "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
IpInfo ipInfo = new IpInfo()
|
||||||
|
{
|
||||||
|
Type = type,
|
||||||
|
IsProxy = isProxy,
|
||||||
|
Provider = provider,
|
||||||
|
Risk = risk
|
||||||
|
};
|
||||||
|
|
||||||
|
return ipInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInternalIpAddress(string ipAdress)
|
||||||
|
{
|
||||||
|
if (ipAdress == "::1")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] ip = IPAddress.Parse(ipAdress).GetAddressBytes();
|
||||||
|
switch (ip[0])
|
||||||
|
{
|
||||||
|
case 10:
|
||||||
|
case 127:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 172:
|
||||||
|
return ip[1] >= 16 && ip[1] < 32;
|
||||||
|
|
||||||
|
case 192:
|
||||||
|
return ip[1] == 168;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsLocalIpAddress(string host)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// get host IP addresses
|
||||||
|
IPAddress[] hostIPs = Dns.GetHostAddresses(host);
|
||||||
|
// get local IP addresses
|
||||||
|
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
|
||||||
|
|
||||||
|
// test if any host IP equals to any local IP or to localhost
|
||||||
|
foreach (IPAddress hostIP in hostIPs)
|
||||||
|
{
|
||||||
|
if (IPAddress.IsLoopback(hostIP))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (IPAddress localIP in localIPs)
|
||||||
|
{
|
||||||
|
if (hostIP.Equals(localIP))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
internal class IpInfo
|
||||||
|
{
|
||||||
|
public bool IsProxy { get; set; }
|
||||||
|
public string? Type { get; set; }
|
||||||
|
public string? Provider { get; set; }
|
||||||
|
public int Risk { get; set; }
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<Window x:Class="FraudCapturer.MainWindow"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:FraudCapturer"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="MainWindow" Height="450" Width="800">
|
|
||||||
|
|
||||||
<Window.DataContext>
|
|
||||||
<local:MainWindowViewModel />
|
|
||||||
</Window.DataContext>
|
|
||||||
<Grid>
|
|
||||||
<Image Source="{Binding }"></Image>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace FraudCapturer;
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for MainWindow.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class MainWindow : Window
|
|
||||||
{
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
using IronOcr;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace FraudCapturer;
|
|
||||||
|
|
||||||
internal class MainWindowViewModel
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, Result> domainCache = new();
|
|
||||||
|
|
||||||
public MainWindowViewModel()
|
|
||||||
{
|
|
||||||
Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Run()
|
|
||||||
{
|
|
||||||
return Task.Run(async () =>
|
|
||||||
{
|
|
||||||
Dictionary<string, Result> results = await ProcessScreenshot();
|
|
||||||
|
|
||||||
if (results.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string alarmText = string.Empty;
|
|
||||||
|
|
||||||
foreach (Result result in results.Values)
|
|
||||||
{
|
|
||||||
alarmText += Environment.NewLine;
|
|
||||||
alarmText += $"{Environment.NewLine}Domain: {result.Domain}";
|
|
||||||
alarmText += $"{Environment.NewLine}Type: {result.Type}";
|
|
||||||
alarmText += $"{Environment.NewLine}TrustRating: {result.TrustRating}";
|
|
||||||
alarmText += $"{Environment.NewLine}Followed: {result.Followed}";
|
|
||||||
alarmText += $"{Environment.NewLine}Source: {result.Source}";
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageBox.Show(alarmText.Trim(), "Alarm!", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
|
|
||||||
}
|
|
||||||
}).ContinueWith(t => Run());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int count = 0;
|
|
||||||
|
|
||||||
private async Task<Dictionary<string, Result>> ProcessScreenshot()
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
Debug.WriteLine(count);
|
|
||||||
|
|
||||||
Rectangle rect = new Rectangle(Cursor.Position.X - 300, Cursor.Position.Y - 300, 600, 600);
|
|
||||||
Bitmap bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
|
|
||||||
Graphics g = Graphics.FromImage(bitmap);
|
|
||||||
g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bitmap.Size, CopyPixelOperation.SourceCopy);
|
|
||||||
|
|
||||||
string resultText;
|
|
||||||
|
|
||||||
IronTesseract? ocr = new IronTesseract();
|
|
||||||
|
|
||||||
using OcrInput? input = new OcrInput(bitmap);
|
|
||||||
|
|
||||||
// Fast Dictionary
|
|
||||||
ocr.Language = OcrLanguage.EnglishFast;
|
|
||||||
|
|
||||||
// Latest Engine
|
|
||||||
ocr.Configuration.TesseractVersion = TesseractVersion.Tesseract5;
|
|
||||||
|
|
||||||
//AI OCR only without font analysis
|
|
||||||
ocr.Configuration.EngineMode = TesseractEngineMode.LstmOnly;
|
|
||||||
|
|
||||||
//Turn off unneeded options
|
|
||||||
ocr.Configuration.ReadBarCodes = false;
|
|
||||||
ocr.Configuration.RenderSearchablePdfsAndHocr = false;
|
|
||||||
|
|
||||||
// Assume text is laid out neatly in an orthagonal document
|
|
||||||
ocr.Configuration.PageSegmentationMode = TesseractPageSegmentationMode.SparseText;
|
|
||||||
|
|
||||||
OcrResult? result = ocr.Read(input);
|
|
||||||
resultText = result.Text;
|
|
||||||
Debug.WriteLine(resultText);
|
|
||||||
return await ProcessMatches(resultText);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<Dictionary<string, Result>> ProcessMatches(string text)
|
|
||||||
{
|
|
||||||
string newDomains = string.Empty;
|
|
||||||
Dictionary<string, Result> results = new();
|
|
||||||
MatchCollection matchCollection = Regex.Matches(text.ToLower(), @"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]");
|
|
||||||
|
|
||||||
foreach (Match match in matchCollection)
|
|
||||||
{
|
|
||||||
if (domainCache.ContainsKey(match.Value))
|
|
||||||
{
|
|
||||||
results.Add(match.Value, domainCache[match.Value]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
newDomains += $"{match.Value} ";
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrWhiteSpace(newDomains))
|
|
||||||
{
|
|
||||||
HttpClient httpClient = new HttpClient();
|
|
||||||
httpClient.DefaultRequestHeaders.Add("User-Agent", "FraudCapturer - (coming soon)");
|
|
||||||
|
|
||||||
ReqestBody reqestBody = new ReqestBody()
|
|
||||||
{
|
|
||||||
Message = newDomains
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpContent httpContent = new StringContent(JsonSerializer.Serialize(reqestBody), Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
HttpResponseMessage responseMessage = await httpClient.PostAsync("https://anti-fish.bitflow.dev/check", httpContent);
|
|
||||||
|
|
||||||
string resultString = await responseMessage.Content.ReadAsStringAsync();
|
|
||||||
ResultBody? resultBody = JsonSerializer.Deserialize<ResultBody>(resultString);
|
|
||||||
|
|
||||||
if (resultBody is null || resultBody.Matches is null || resultBody.Match == false)
|
|
||||||
{
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Result result in resultBody.Matches)
|
|
||||||
{
|
|
||||||
if (result?.Domain is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
domainCache.Add(result.Domain, result);
|
|
||||||
results.Add(result.Domain, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using PacketDotNet;
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
internal static class PackageHelper
|
||||||
|
{
|
||||||
|
public static string GetPayloadAsString(this TransportPacket transportPacket)
|
||||||
|
{
|
||||||
|
byte[] data = transportPacket.PayloadData;
|
||||||
|
string bytes = "";
|
||||||
|
string ascii = "";
|
||||||
|
|
||||||
|
for (int i = 1; i <= data.Length; i++)
|
||||||
|
{
|
||||||
|
// add the current byte to the bytes hex string
|
||||||
|
bytes += data[i - 1].ToString("x").PadLeft(2, '0') + " ";
|
||||||
|
|
||||||
|
// add the current byte to the asciiBytes array for later processing
|
||||||
|
if (data[i - 1] < 0x21 || data[i - 1] > 0x7e)
|
||||||
|
{
|
||||||
|
ascii += ".";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ascii += Encoding.ASCII.GetString(new[] { data[i - 1] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ascii.Trim('.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
|
||||||
|
using PacketDotNet;
|
||||||
|
|
||||||
|
using SharpPcap;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace FraudCapturer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Example showing packet manipulation
|
||||||
|
/// </summary>
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public const string AppName = "FraudCapturer";
|
||||||
|
public const string IpStorePath = "ipAdresses.txt";
|
||||||
|
|
||||||
|
private static DateTime lastCacheClear;
|
||||||
|
private static string lastDomain = string.Empty;
|
||||||
|
|
||||||
|
private static readonly List<string> capturedIpsCache = new();
|
||||||
|
private static readonly Dictionary<string, DomainInfo> capturedDomainsCache = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||||
|
// Print SharpPcap version
|
||||||
|
Console.WriteLine(AppName);
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
// Retrieve the device list
|
||||||
|
CaptureDeviceList devices = CaptureDeviceList.Instance;
|
||||||
|
|
||||||
|
// If no devices were found print an error
|
||||||
|
if (devices.Count < 1)
|
||||||
|
{
|
||||||
|
Console.WriteLine("No devices were found on this machine");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("The following devices are available on this machine:");
|
||||||
|
Console.WriteLine("----------------------------------------------------");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// Print out the available devices
|
||||||
|
foreach (ILiveDevice dev in devices)
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0}) {1}", i, dev.Description);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
int choice = -1;
|
||||||
|
while (choice < 0 || choice >= devices.Count)
|
||||||
|
{
|
||||||
|
Console.Write("-- Please choose a device to capture: ");
|
||||||
|
bool valid = int.TryParse(Console.ReadLine(), out choice);
|
||||||
|
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
choice = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ICaptureDevice? device = null;
|
||||||
|
|
||||||
|
device = devices[choice];
|
||||||
|
|
||||||
|
//Register our handler function to the 'packet arrival' event
|
||||||
|
device.OnPacketArrival +=
|
||||||
|
new PacketArrivalEventHandler(Device_OnPacketArrival);
|
||||||
|
|
||||||
|
// Open the device for capturing
|
||||||
|
device.Open();
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("-- Listening on {0}, hit 'Ctrl-C' to exit...", device.Description);
|
||||||
|
|
||||||
|
// Start capture 'INFINTE' number of packets
|
||||||
|
device.Capture();
|
||||||
|
|
||||||
|
// Close the pcap device
|
||||||
|
// (Note: this line will never be called since
|
||||||
|
// we're capturing infinite number of packets
|
||||||
|
device.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Device_OnPacketArrival(object sender, PacketCapture e)
|
||||||
|
{
|
||||||
|
RawCapture rawPacket = e.GetPacket();
|
||||||
|
Packet packet = Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);
|
||||||
|
if (packet is EthernetPacket)
|
||||||
|
{
|
||||||
|
IPPacket ip = packet.Extract<IPPacket>();
|
||||||
|
if (ip != null)
|
||||||
|
{
|
||||||
|
IPAddress remoteIpAddress;
|
||||||
|
string direction;
|
||||||
|
|
||||||
|
if (IpHelper.IsLocalIpAddress(ip.SourceAddress.ToString()))
|
||||||
|
{
|
||||||
|
remoteIpAddress = ip.DestinationAddress;
|
||||||
|
direction = "Out";
|
||||||
|
}
|
||||||
|
else if (IpHelper.IsLocalIpAddress(ip.DestinationAddress.ToString()))
|
||||||
|
{
|
||||||
|
remoteIpAddress = ip.SourceAddress;
|
||||||
|
direction = "In";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DateTime.Now - lastCacheClear >= new TimeSpan(0, 10, 0))
|
||||||
|
{
|
||||||
|
lastCacheClear = DateTime.Now;
|
||||||
|
capturedIpsCache.Clear();
|
||||||
|
capturedDomainsCache.Clear();
|
||||||
|
File.WriteAllText(IpStorePath, string.Empty);
|
||||||
|
Console.WriteLine("Cleared cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckDns(packet, remoteIpAddress, direction);
|
||||||
|
|
||||||
|
if (capturedIpsCache.Contains(remoteIpAddress.ToString()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan timeRemainingUntilCacheReset = new TimeSpan(0, 10, 0) - (DateTime.Now - lastCacheClear);
|
||||||
|
Console.WriteLine($"Next cache reset in {timeRemainingUntilCacheReset.Minutes} minute(s) and {timeRemainingUntilCacheReset.Seconds} second(s)");
|
||||||
|
|
||||||
|
capturedIpsCache.Add(remoteIpAddress.ToString());
|
||||||
|
|
||||||
|
CheckIpAddress(remoteIpAddress, direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckIpAddress(IPAddress remoteIpAddress, string direction)
|
||||||
|
{
|
||||||
|
IpInfo? ipInfo = IpHelper.GetIpReputation(remoteIpAddress);
|
||||||
|
|
||||||
|
if (IpHelper.IsInternalIpAddress(remoteIpAddress.ToString()))
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||||
|
Console.WriteLine($"[{direction}] [Internal] {remoteIpAddress}");
|
||||||
|
}
|
||||||
|
else if (ipInfo is not null)
|
||||||
|
{
|
||||||
|
bool block = false;
|
||||||
|
if (ipInfo.Risk >= 67)
|
||||||
|
{
|
||||||
|
FirewallHelper.BlockIp(remoteIpAddress);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
else if (ipInfo.Risk >= 34 && ipInfo.IsProxy)
|
||||||
|
{
|
||||||
|
FirewallHelper.BlockIp(remoteIpAddress);
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
else if (ipInfo.IsProxy && ipInfo.Type != "VPN")
|
||||||
|
{
|
||||||
|
FirewallHelper.BlockIp(remoteIpAddress);
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"[{direction}] [Provider: {ipInfo.Provider}] [Risk: {ipInfo.Risk}] [Proxy: {ipInfo.IsProxy}] [Type: {ipInfo.Type}] [Block: {block}] {remoteIpAddress}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||||
|
Console.WriteLine($"[{direction}] [Invalid] {remoteIpAddress}");
|
||||||
|
}
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckDns(Packet packet, IPAddress remoteIpAddress, string direction)
|
||||||
|
{
|
||||||
|
TransportPacket transportPacket = packet.Extract<TcpPacket>();
|
||||||
|
transportPacket ??= packet.Extract<UdpPacket>();
|
||||||
|
|
||||||
|
if (transportPacket != null && transportPacket.DestinationPort == 53)
|
||||||
|
{
|
||||||
|
string[] domains = DomainHelper.GetDomainsFromDnsReqest(transportPacket);
|
||||||
|
foreach (string domain in domains)
|
||||||
|
{
|
||||||
|
DomainInfo? domainInfo;
|
||||||
|
bool block = false;
|
||||||
|
|
||||||
|
if (capturedDomainsCache.ContainsKey(domain))
|
||||||
|
{
|
||||||
|
domainInfo = capturedDomainsCache[domain];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
domainInfo = DomainHelper.GetDomainReputation(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainInfo is null)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||||
|
if (lastDomain != domain)
|
||||||
|
{
|
||||||
|
lastDomain = domain;
|
||||||
|
Console.WriteLine($"[{direction}] [Dns] [Invalid] [Domain: {domain}] {remoteIpAddress}");
|
||||||
|
}
|
||||||
|
Console.ResetColor();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainInfo.IsMatch == false)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
if (lastDomain != domain)
|
||||||
|
{
|
||||||
|
lastDomain = domain;
|
||||||
|
Console.WriteLine($"[{direction}] [Dns] [Domain: {domain}] [Type: Undetected] [Block: {block}] {remoteIpAddress}");
|
||||||
|
}
|
||||||
|
Console.ResetColor();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainInfo.TrustRating >= 0.9)
|
||||||
|
{
|
||||||
|
FirewallHelper.BlockIp(domainInfo.IpAddress);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
else if (domainInfo.TrustRating >= 0.5)
|
||||||
|
{
|
||||||
|
FirewallHelper.BlockIp(domainInfo.IpAddress);
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastDomain != domain)
|
||||||
|
{
|
||||||
|
lastDomain = domain;
|
||||||
|
Console.WriteLine($"[{direction}] [Dns] [Domain: {domain}] [Type: {domainInfo.Type}] [Source: {domainInfo.Source}] [Source Trust: {domainInfo.TrustRating * 100d}] [Block: {block}] {remoteIpAddress}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace FraudCapturer;
|
|
||||||
|
|
||||||
internal class ReqestBody
|
|
||||||
{
|
|
||||||
[JsonPropertyName("message")]
|
|
||||||
public string? Message { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace FraudCapturer;
|
|
||||||
|
|
||||||
internal class Result
|
|
||||||
{
|
|
||||||
[JsonPropertyName("followed")]
|
|
||||||
public bool Followed { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("domain")]
|
|
||||||
public string? Domain { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("source")]
|
|
||||||
public string? Source { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("type")]
|
|
||||||
public string? Type { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("trust_rating")]
|
|
||||||
public double TrustRating { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace FraudCapturer;
|
|
||||||
|
|
||||||
internal class ResultBody
|
|
||||||
{
|
|
||||||
[JsonPropertyName("match")]
|
|
||||||
public bool Match { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("matches")]
|
|
||||||
public List<Result>? Matches { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
namespace FraudCapturer;
|
|
||||||
|
|
||||||
internal class ScreenshotHandler
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user