Skip to content

Commit

Permalink
Merge pull request #30 from Flangvik/dev
Browse files Browse the repository at this point in the history
Commit for V3.5.1
  • Loading branch information
Flangvik authored Apr 12, 2023
2 parents e6b9b2e + 4d51079 commit 539a69e
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 30 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ See the [TeamFiltration](https://github.com/Flangvik/TeamFiltration/wiki/TeamFil
This tool has been used internally since January 2021 and was publicly released in my talk "Taking a Dumb In The Cloud" during DefCON30.

## Download
[You can download the latest precompiled release for Linux, Windows and MacOSX X64 ](https://github.com/Flangvik/TeamFiltration/releases/latest)
[You can download the latest precompiled release for Linux, Windows and MacOS ](https://github.com/Flangvik/TeamFiltration/releases/latest)

**The releases are precompiled into a single application-dependent binary. The size go up, but you do not need DotNetCore or any other dependencies to run them.**
**The releases are precompiled into a single application-dependent binary. The size go up, but you do not need NET or any other dependencies to run them.**

## Usage

Expand Down Expand Up @@ -40,7 +40,7 @@ This tool has been used internally since January 2021 and was publicly released
└╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╝
╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝╝
[] TeamFiltration V3.5.1 PUBLIC, created by @Flangvik at @TrustedSec
[] TeamFiltration V3.5.1 PUBLIC, created by @Flangvik at @TrustedSec
[+] Args parsed
Usage:
Expand Down Expand Up @@ -125,6 +125,6 @@ Usage:
- [GitHub - KoenZomers/OneDriveAPI: API in .NET to communicate with OneDrive Personal and OneDrive for Business](https://github.com/KoenZomers/OneDriveAPI)
- [Research into Undocumented Behavior of Azure AD Refresh Tokens ](https://github.com/secureworks/family-of-client-ids-research)
- [WS API Gateway management tool for creating on the fly HTTP pass-through proxies for unique IP rotation](https://github.com/ustayready/fireprox)
- Credits to [Ryan] (https://twitter.com/detectdotdev) for validating and discussing my observations / questions!
- Credits to [Ryan](https://twitter.com/detectdotdev) for validating and discussing my observations / questions!
- The entire [TrustedSec](https://TrustedSec.com) team for helping me polish this tool!

48 changes: 37 additions & 11 deletions TeamFiltration/TeamFiltration/Handlers/TeamsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public TeamsHandler(BearerTokenResp getBearToken, GlobalArgumentsHandler teamFil

_teamsClient = new HttpClient(httpClientHandler);
_teamsClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {getBearToken.access_token}");

_teamsClient.DefaultRequestHeaders.Add("User-Agent", teamFiltrationConfig.TeamFiltrationConfig.UserAgent);
_teamsClient.DefaultRequestHeaders.Add("x-ms-client-caller", "x-ms-client-caller");
_teamsClient.DefaultRequestHeaders.Add("x-ms-client-version", "27/1.0.0.2021011237");
Expand Down Expand Up @@ -130,7 +130,7 @@ public async Task<ChatLogResp> GetChatLogs(Conversation chatResp)

public async Task<UserConversationsResp> GetThreads(string meetingId)
{

var getConversationUrl = $"https://{TeamsRegion}.ng.msg.teams.microsoft.com/v1/threads/{meetingId}?view=msnp24Equivalent";
var getConversationsReq = await _teamsClient.PollyGetAsync(getConversationUrl);
var getConversationResp = await getConversationsReq.Content.ReadAsStringAsync();
Expand All @@ -141,7 +141,7 @@ public async Task<UserConversationsResp> GetThreads(string meetingId)

public async Task<UserConversationsResp> GetConversations()
{

var getConversationUrl = $"https://{TeamsRegion}.ng.msg.teams.microsoft.com/v1/users/ME/conversations";
var getConversationsReq = await _teamsClient.PollyGetAsync(getConversationUrl);
var getConversationResp = await getConversationsReq.Content.ReadAsStringAsync();
Expand All @@ -158,9 +158,9 @@ public async Task<WorkingWithResp> GetWorkingWithList(string tenantId)
return workingWithDataResp;
}

public async Task<(bool isValid, string objectId, TeamsExtSearchRep responseObject)> EnumUser(string username, string enumUserUrl)
public async Task<(bool isValid, string objectId, TeamsExtSearchRep responseObject, Outofofficenote Outofofficenote)> EnumUser(string username, string enumUserUrl)
{

Outofofficenote Outofofficenote = new Outofofficenote() { };
int failedCount = 0;

failedResp:
Expand All @@ -169,7 +169,6 @@ public async Task<WorkingWithResp> GetWorkingWithList(string tenantId)
var enumUserReq = await _teamsClient.PollyGetAsync(enumUserUrl + $"{TeamsRegion}/beta/users/{username}/externalsearchv3");



if (enumUserReq.IsSuccessStatusCode)
{

Expand Down Expand Up @@ -200,27 +199,54 @@ public async Task<WorkingWithResp> GetWorkingWithList(string tenantId)
&& responeObject.FirstOrDefault().userPrincipalName.ToLower().Equals(username.ToLower())
)
{
return (true, responeObject.FirstOrDefault().objectId, responeObject.FirstOrDefault());

//Check the user presence
HttpResponseMessage getUserPresence = await _teamsClient.PollyPostAsync(
$"https://presence.teams.microsoft.com/v1/presence/getpresence/",

new StringContent(
"[{ \"mri\":\"" + responeObject.FirstOrDefault().mri + "\"}]"
, Encoding.UTF8
, "application/json"
)
);

var getPresenceObject = JsonConvert.DeserializeObject<List<GetPresenceResp>>(await getUserPresence.Content.ReadAsStringAsync());

try
{
if (getPresenceObject.FirstOrDefault()?.presence?.calendarData?.isOutOfOffice != null)
{
Outofofficenote = getPresenceObject.FirstOrDefault()?.presence?.calendarData.outOfOfficeNote;
}
}
catch (Exception ex)
{


}

return (true, responeObject.FirstOrDefault().objectId, responeObject.FirstOrDefault(), Outofofficenote);
}
}
}
return (false, "", null);
return (false, "", null, null);

}
else if (enumUserReq.StatusCode.Equals(HttpStatusCode.Forbidden))
{
//If we get the forbidden error response, we can assume it's valid!
return (true, Guid.NewGuid().ToString(), null);
return (true, Guid.NewGuid().ToString(), null, null);
}
else if (enumUserReq.StatusCode.Equals(HttpStatusCode.InternalServerError))
{
failedCount++;
if (failedCount > 2)
return (false, "", null);
return (false, "", null, null);
else
goto failedResp;
}
return (false, "", null);
return (false, "", null, null);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using TeamFiltration.Models.Teams;

namespace TeamFiltration.Models.TeamFiltration
{
Expand All @@ -17,5 +18,6 @@ public ValidAccount()
public string Username { get; set; }
public string objectId { get; set; }
public string DisplayName { get; set; }
public string OutOfOfficeMessage { get; set; }
}
}
40 changes: 40 additions & 0 deletions TeamFiltration/TeamFiltration/Models/Teams/GetPresenceResp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TeamFiltration.Models.Teams
{
public class GetPresenceResp
{
public string mri { get; set; }
public Presence presence { get; set; }
public bool etagMatch { get; set; }
public string etag { get; set; }
public int status { get; set; }
}

public class Presence
{
public string sourceNetwork { get; set; }
public Calendardata calendarData { get; set; }
public object[] capabilities { get; set; }
public string availability { get; set; }
public string activity { get; set; }
public string deviceType { get; set; }
}

public class Calendardata
{
public Outofofficenote outOfOfficeNote { get; set; }
public bool isOutOfOffice { get; set; }
}

public class Outofofficenote
{
public string message { get; set; }
public DateTime publishTime { get; set; }
public DateTime expiry { get; set; }
}
}
2 changes: 1 addition & 1 deletion TeamFiltration/TeamFiltration/Modules/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static void DatabaseStart(string[] args)

//Format based on o
if (selection.Contains("csv"))
formattedDataOut = ToCsv(",", dataOut);
formattedDataOut = ToCsv(";", dataOut);

if (selection.Contains("json"))
formattedDataOut = JsonConvert.SerializeObject(dataOut, Formatting.Indented);
Expand Down
37 changes: 25 additions & 12 deletions TeamFiltration/TeamFiltration/Modules/Enumerate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ public static async Task<bool> ValidUserWrapperTeams(TeamsHandler teamsHandler,
//check list and add
if (!_teamsObjectIds.Contains(validUser.objectId))
{
_databaseHandle.WriteLog(new Log("ENUM", $"{username} valid!", ""));
if (validUser.Outofofficenote != null)
_databaseHandle.WriteLog(new Log("ENUM", $"{username} valid (OutOfOffice message found)!", ""));
else
_databaseHandle.WriteLog(new Log("ENUM", $"{username} valid!", ""));

try
{
Expand All @@ -80,7 +83,8 @@ public static async Task<bool> ValidUserWrapperTeams(TeamsHandler teamsHandler,
Username = username,
Id = Helpers.Generic.StringToGUID(username).ToString(),
objectId = validUser.objectId,
DisplayName = (validUser.responseObject != null) ? validUser.responseObject?.displayName : ""
DisplayName = (validUser.responseObject != null) ? validUser.responseObject?.displayName : "",
OutOfOfficeMessage = (validUser.Outofofficenote != null) ? validUser.Outofofficenote.message : "",
}


Expand Down Expand Up @@ -115,13 +119,7 @@ public static async Task<bool> ValidUserWrapperTeams(TeamsHandler teamsHandler,
//LiteDB needs to fix their crap
}
}
/*
* There is a "bug" in litedb that makes it unable to handle more then 300/s transactions a second
else if (!validUser.isValid)
{
//User is not valid, let's note that down
_databaseHandle.WriteInvalidAcc(new ValidAccount() { Username = username, Id = Helpers.Generic.StringToGUID(username).ToString(), objectId = validUser.objectId });
}*/

return false;
}
catch (Exception ex)
Expand Down Expand Up @@ -302,6 +300,7 @@ public static async Task EnumerateAsync(string[] args)
};


startSelection:
using (var httpClient = new HttpClient(httpClientHandler))
{
var gitHubDict = new Dictionary<int, string>() { };
Expand All @@ -315,6 +314,7 @@ public static async Task EnumerateAsync(string[] args)
gitHubDict.Add(7, "https://raw.githubusercontent.com/Flangvik/statistically-likely-usernames/master/smith.txt");
gitHubDict.Add(8, "https://raw.githubusercontent.com/Flangvik/statistically-likely-usernames/master/smithj.txt");
gitHubDict.Add(9, "https://raw.githubusercontent.com/Flangvik/statistically-likely-usernames/master/john_smith.txt");
gitHubDict.Add(10, "https://raw.githubusercontent.com/Flangvik/statistically-likely-usernames/master/j.smith.txt");


foreach (var usernameDict in gitHubDict)
Expand All @@ -323,13 +323,26 @@ public static async Task EnumerateAsync(string[] args)
}
Console.WriteLine();
Console.Write("[?] Select an email format #> ");
var selection = Convert.ToInt32(Console.ReadLine());
int selection = 0;
try
{
selection = Convert.ToInt32(Console.ReadLine());
}
catch (Exception ex)
{

Console.WriteLine("[!] Failed to parse input / selection, try again!");
Console.WriteLine("");
goto startSelection;
}

var userListReq = await httpClient.PollyGetAsync(gitHubDict.GetValueOrDefault(selection));
if (userListReq.IsSuccessStatusCode)
{
var userListContent = await userListReq.Content.ReadAsStringAsync();
userListData = (userListContent).Split("\n").Where(x => !string.IsNullOrEmpty(x)).Select(x => x + $"@{domain}").ToArray();
}else
}
else
{
Console.WriteLine("[!] Failed to download statistically-likely-usernames from Github!");
Environment.Exit(0);
Expand All @@ -352,7 +365,7 @@ public static async Task EnumerateAsync(string[] args)
userListData = userListData.Except(currentValidAccounts).ToArray();
userListData = userListData.Except(currentInvalidAccounts).ToArray();

if(userListData.Count() == 0)
if (userListData.Count() == 0)
{
_databaseHandle.WriteLog(new Log("ENUM", $"No valid accounts left after filters applied, exiting..", ""));
Environment.Exit(0);
Expand Down
4 changes: 2 additions & 2 deletions TeamFiltration/TeamFiltration/TeamFiltration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

<ItemGroup>
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
<PackageReference Include="AWSSDK.APIGateway" Version="3.7.100.95" />
<PackageReference Include="AWSSDK.APIGateway" Version="3.7.100.109" />
<PackageReference Include="ConsoleTables" Version="2.4.2" />
<PackageReference Include="Extreme.Net.Core" Version="2.0.4" />
<PackageReference Include="LiteDB" Version="5.0.16" />
Expand All @@ -43,7 +43,7 @@
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="PushoverNET" Version="1.0.28" />
<PackageReference Include="System.Data.SQLite" Version="1.0.117" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.28.1" />
<PackageReference Include="TimeZoneConverter" Version="6.1.0" />
</ItemGroup>

Expand Down

0 comments on commit 539a69e

Please sign in to comment.