quarta-feira, 31 de maio de 2023

Why (I Believe) WADA Was Not Hacked By The Russians

Disclaimer: This is my personal opinion. I am not an expert in attribution. But as it turns out, not many people in the world are good at attribution. I know this post lacks real evidence and is mostly based on speculation.



Let's start with the main facts we know about the WADA hack, in chronological order:


1. Some point in time (August - September 2016), the WADA database has been hacked and exfiltrated
2. August 15th, "WADA has alerted their stakeholders that email phishing scams are being reported in connection with WADA and therefore asks its recipients to be careful"  https://m.paralympic.org/news/wada-warns-stakeholders-phishing-scams
3. September 1st, the fancybear.net domain has been registered
   Domain Name: FANCYBEAR.NET    ...    Updated Date: 18-sep-2016    Creation Date: 01-sep-2016
 
4. The content of the WADA hack has been published on the website
5. The @FancyBears and @FancyBearsHT Twitter accounts have been created and started to tweet on 12th September, reaching out to journalists
6. 12th September, Western media started headlines "Russia hacked WADA"
7. The leaked documents have been altered, states WADA https://www.wada-ama.org/en/media/news/2016-10/cyber-security-update-wadas-incident-response


The Threatconnect analysis

The only technical analysis on why Russia was behind the hack, can be read here: https://www.threatconnect.com/blog/fancy-bear-anti-doping-agency-phishing/

After reading this, I was able to collect the following main points:

  1. It is Russia because Russian APT groups are capable of phishing
  2. It is Russia because the phishing site "wada-awa[.]org was registered and uses a name server from ITitch[.]com, a domain registrar that FANCY BEAR actors recently used"
  3. It is Russia because "Wada-arna[.]org and tas-cass[.]org were registered through and use name servers from Domains4bitcoins[.]com, a registrar that has also been associated with FANCY BEAR activity."
  4. It is Russia, because "The registration of these domains on August 3rd and 8th, 2016 are consistent with the timeline in which the WADA recommended banning all Russian athletes from the Olympic and Paralympic games."
  5. It is Russia, because "The use of 1&1 mail.com webmail addresses to register domains matches a TTP we previously identified for FANCY BEAR actors."

There is an interesting side-track in the article, the case of the @anpoland account. Let me deal with this at the end of this post.

My problem with the above points is that all five flag was publicly accessible to anyone as TTP's for Fancy Bear. And meanwhile, all five is weak evidence. Any script kittie in the world is capable of both hacking WADA and planting these false-flags.

A stronger than these weak pieces of evidence would be:

  • Malware sharing same code attributed to Fancy Bear (where the code is not publicly available or circulating on hackforums)
  • Private servers sharing the IP address with previous attacks attributed to Fancy Bear (where the server is not a hacked server or a proxy used by multiple parties)
  • E-mail addresses used to register the domain attributed to Fancy Bear
  • Many other things
For me, it is quite strange that after such great analysis on Guccifer 2.0, the Threatconnect guys came up with this low-value post. 


The fancybear website

It is quite unfortunate that the analysis was not updated after the documents have been leaked. But let's just have a look at the fancybear . net website, shall we?

Now the question is, if you are a Russian state-sponsored hacker group, and you are already accused of the hack itself, do you create a website with tons of bears on the website, and do you choose the same name (Fancy Bear) for your "Hack team" that is already used by Crowdstrike to refer to a Russian state-sponsored hacker group? Well, for me, it makes no sense. Now I can hear people screaming: "The Russians changed tactics to confuse us". Again, it makes no sense to change tactics on this, while keeping tactics on the "evidence" found by Threatconnect.

It makes sense that a Russian state-sponsored group creates a fake persona, names it Guccifer 2.0, pretends Guccifer 2.0 is from Romania, but in the end it turns out Guccifer 2.0 isn't a native Romanian speaker. That really makes sense.

What happens when someone creates this fancybear website for leaking the docs, and from the Twitter account reaches out to the media? Journalists check the website, they see it was done by Fancy Bear, they Bing Google this name, and clearly see it is a Russian state-sponsored hacker group. Some journalists also found the Threatconnect report, which seems very convincing for the first read. I mean, it is a work of experts, right? So you can write in the headlines that the hack was done by the Russians.

Just imagine an expert in the USA or Canada writing in report for WADA:
"the hack was done by non-Russian, but state-sponsored actors, who planted a lot of false-flags to accuse the Russians and to destroy confidence in past and future leaks". Well, I am sure this is not a popular opinion, and whoever tries this, risks his career. Experts are human, subject to all kinds of bias.

The Guardian

The only other source I was able to find is from The Guardian, where not just one side (it was Russia) was represented in the article. It is quite unfortunate that both experts are from Russia - so people from USA will call them being not objective on the matter. But the fact that they are Russian experts does not mean they are not true ...

https://www.theguardian.com/sport/2016/sep/15/fancy-bears-hackers--russia-wada-tues-leaks

Sergei Nikitin:
"We don't have this in the case of the DNC and Wada hacks, so it's not clear on what basis conclusions are being drawn that Russian hackers or special services were involved. It's done on the basis of the website design, which is absurd," he said, referring to the depiction of symbolically Russian animals, brown and white bears, on the "Fancy Bears' Hack Team" website.

I don't agree with the DNC part, but this is not the topic of conversation here.

Alexander Baranov:
"the hackers were most likely amateurs who published a "semi-finished product" rather than truly compromising information. "They could have done this more harshly and suddenly," he said. "If it was [state-sponsored] hackers, they would have dug deeper. Since it's enthusiasts, amateurs, they got what they got and went public with it.""

The @anpoland side-track

First please check the tas-cas.org hack https://www.youtube.com/watch?v=day5Aq0bHsA  , I will be here when you finished it. This is a website for "Court of Arbitration for Sport's", and referring to the Threatconnect post, "CAS is the highest international tribunal that was established to settle disputes related to sport through arbitration. Starting in 2016, an anti-doping division of CAS began judging doping cases at the Olympic Games, replacing the IOC disciplinary commission." Now you can see why this attack is also discussed here.


  • My bet is that this machine was set-up for these @anpoland videos only. Whether google.ru is a false flag or it is real, hard to decide. It is interesting to see that there is no google search done via google.ru, it is used only once. 
  • The creator of the video can't double click. Is it because he has a malfunctioning mouse? Is it because he uses a virtualization console, which is near-perfect OPSEC to hide your real identity? My personal experience is that using virtualization consoles remotely (e.g. RDP) has very similar effects to what we can see on the video. 
  • The timeline of the Twitter account is quite strange, registered in 2010
  • I agree with the Threatconnect analysis that this @anpoland account is probably a faketivist, and not an activist. But who is behind it, remains a mystery. 
  • Either the "activist" is using a whonix-like setup for remaining anonymous, or a TOR router (something like this), or does not care about privacy at all. Looking at the response times (SQLmap, web browser), I doubt this "activist" is behind anything related to TOR. Which makes no sense for an activist, who publishes his hack on Youtube. People are stupid for sure, but this does not add up. It makes sense that this was a server (paid by bitcoins or stolen credit cards or whatever) rather than a home computer.
For me, this whole @anpoland thing makes no sense, and I think it is just loosely connected to the WADA hack. 

The mysterious Korean characters in the HTML source

There is another interesting flag in the whole story, which actually makes no sense. When the website was published, there were Korean characters in HTML comments. 



When someone pointed this out on Twitter, these Korean HTML comments disappeared:
These HTML comments look like generated HTML comments, from a WYSIWYG editor, which is using the Korean language. Let me know if you can identify the editor.

The Russians are denying it

Well, what choice they have? It does not matter if they did this or not, they will deny it. And they can't deny this differently. Just imagine a spokesperson: "Previously we have falsely denied the DCC and DNC hacks, but this time please believe us, this wasn't Russia." Sounds plausible ...

Attribution

Let me sum up what we know:

It makes sense that the WADA hack was done by Russia, because:

  1. Russia being almost banned from the Olympics due to doping scandal, it made sense to discredit WADA and US Olympians
  2. There are multiple(weak) pieces of evidence which point to Russia
It makes sense that the WADA hack was not done by  Russia, because: 
  1. By instantly attributing the hack to the Russians, the story was more about to discredit Russia than discrediting WADA or US Olympians.
  2. In reality, there was no gain for Russia for disclosing the documents. Nothing happened, nothing changed, no discredit for WADA. Not a single case turned out to be illegal or unethical.
  3. Altering the leaked documents makes no sense if it was Russia (see update at the end). Altering the leaked documents makes a lot of sense if it was not Russia. Because from now on, people can always state "these leaks cannot be trusted, so it is not true what is written there". It is quite cozy for any US organization, who has been hacked or will be hacked. If you are interested in the "Russians forging leaked documents" debate, I highly recommend to start with this The Intercept article
  4. If the Korean characters were false flags planted by the Russians, why would they remove it? If it had been Russian characters, I would understand removing it.
  5. All evidence against Russia is weak, can be easily forged by even any script kittie.

I don't like guessing, but here is my guess. This WADA hack was an operation of a (non-professional) hackers-for-hire service, paid by an enemy of Russia. The goal was to hack WADA, leak the documents, modify some contents in the documents, and blame it all on the Russians ...

Questions and answers

  • Was Russia capable of doing this WADA hack? Yes.
  • Was Russia hacking WADA? Maybe yes, maybe not.
  • Was this leak done by a Russian state-sponsored hacker group? I highly doubt that.
  • Is it possible to buy an attribution-dice where all six-side is Russia? No, it is sold-out. 

To quote Patrick Gray: "Russia is the new China, and the Russians ate my homework."©

Let me know what you think about this, and please comment. 

More information


Smart Contract Hacking Chapter 6 - Phishing Users With Malicious DAPS Via TX.Origin


Authorization on a smart contract can sometimes be a tricky endeavor. There are many things that are easily coded incorrectly, for example public functions, unpublished functions, delegate calls and tx.origin validations. If any of these are implemented incorrectly, then contracts are often left vulnerable to both direct and indirect attacks.

In this case, we will be talking about tx.origin which is an indirect attack method an attacker can utilize to bypass authorization based on the nuance of what is actually checked vs what the developer may think is checked when implementing require statements with tx.origin for authorization.

There are two different ways to check the address of who is making a call to a contract.

ü  Msg.sender

ü  Tx.Origin

 

While both of these could produce the same output when directly calling a contract, they may differ when there is another contract in the middle of the transaction. For example, if you play an online game which calls another contract to handle a payout transaction. When using a check with msg.sender, the winning payout would go to the games address that called the payout contract.

If the same address was checked with tx.origin on the payout contract, it would go all the way back to the original users address that processed the payout transaction on the game rather than the game contract making the call.

 

Man In the Middle Via tx.origin

This type of check is often misused when checking validation for authorization on smart contracts. When a tx.Origin check is used instead of msg.sender, this can leave a contract open to a man-in-the-middle (MITM) attack vector. Let's take a look at a visual representation of an attack, which will help put this into perspective. Then we will look at some code that implements this functionality.

 

In the below image we have:

ü  A user on the left

ü  An attacker's contract in the middle

ü  A target contract on the right

 


 

  

If the attacker were to call the target contract directly his authorization would be checked based on his personal address value regardless if the check is being performed via msg.sender or tx.orgin.  However, if the attacker created his own contract that called the target contract, the attacker could run a phishing campaign and social engineer the user into running functionality on the attacker's contract.

For example, sending a user to a game or accepting a payment for services and proxying the request to the target contract. If the user is social engineered into using the attackers contract, the attackers contract would make a transaction call to the target contract with which originates from the user's address via tx.origin. 

This is the exact point where things can go sideways.  If the target contract processes the transaction via msg.sender then the attackers contract would authorized as the attackers contract address. However, if the contract checks authorization via tx.origin than the attacker is accessing the target as the victims address and can bypass any authorization checks and simply process functionality as the victim user, to the attackers benefit.

This attack could be used to liquidate a user's account with a transfer function from the authorized user to the attacker's account. Or accessing forbidden functionality such as a Self-Destruct function linked to administrator only validation, or perhaps updating admin functionality to provide the attacker with full access to the contract. Much like social engineering in a standard network penetration test, this could be a wide scale phishing campaign to effect all standard users, or a spear phishing attack targeting an administrative user.

Regardless of the motivations of the attacker, there are many bad things that can happen. So let's take a look at a very simple example of tx.origin just so you see the difference between msg.sender and tx.origin.  We want to make sure you fully understand how this functionality is actually working so you can spot it during your testing before we exploit it.

 

Simple tx.origin Example Walkthrough:

Action Steps:

ü  Type out the following 2 contracts into Remix

ü  Deploy the HelloWorldTXOrigin contract first and copy its address value

ü  Place the address value in the proper location within CallHello contract and deploy it

ü  Review the code within CallHello and its usage of address validation

ü  Review the calls into the contract from HelloWorldTXOrigin that are effected by the address validation

ü  Try to reason based on what you learned above how this works and where and what the issues could be

 

 

1.    pragma solidity ^0.6.6;
2.   
3.    contract HelloWorldTXOrigin {
4.       
5.      function return_TX_Address() public returns(address){
6.           address myaddress = tx.origin;
7.           return myaddress; 
8.      }
9.      
10.   function return_MSG_Address() public returns(address){
11.       address myaddress = msg.sender;
12.         return myaddress; 
13.   }
14. }    

 

The code above for HelloWorldTXOrigin is extremely simple. All the code does is set a variable on lines 6 and 11 to the address calling the function and returns the value.  On line 6 it uses the tx.origin value and on line 11 it uses the msg.sender.

Now take a look at the following contract which calls the above contract to illustrate the difference between msg.sender and tx.origin values.  

 

1.    pragma solidity ^0.6.6;
2.   
3.    interface targetInterface {
4.      function return_TX_Address() external returns(address); 
5.      function return_MSG_Address() external returns(address);
6.    }
7.   
8.    contract Call_Hello {
9.      targetInterface helloInterface = targetInterface(ADD_Address_Here);
10. 
11.   function myTX ()  public returns (address){
12.        return helloInterface.return_TX_Address();
13.   }
14.    
15.   function myMSG ()  public returns (address){
16.        return helloInterface.return_MSG_Address();
17.   }
18.}

 

The Call_Hello contract above calls the HelloWorld contract via an interface defined on line 3 and initialized to a variable named helloInterface on line 9.

All this contract does is call functions from HelloWorld on lines 12 and 16 and returns the address values of tx.sender or msg.sender. Presumably this would be a random user that you social engineered into using this contract.

Action Steps:

ü  Select the first account in the dropdown list

ü  Compile and deploy HelloWorldTXOrigin.sol contract via Remix:

ü  Copy the address of the HelloWorldTXOrigin.sol contract

ü  Paste that address value into the target interface address placeholder

ü  Select the second account in the dropdown list

ü  Compile and deploy Call_Hello.sol

ü  Select any other account to simulate the victim account calling the attackers Call_Hello contract

ü  After each is pressed review the transaction output address and walk through in your head what you are reviewing before moving on.

 

If you performed the above action steps you would notice something similar to the following. First, I deploy my target contract with account one, which got deployed to the address:

 

ü  0xdCDB4db4a54F689ECC486d8BAcC08Cde4AC7FcA8

 



Next, I replace the address in the following line of the attackers phishing contract Call_Hello with the address from above, using the copy button to the right of the address in the above screenshot:

 

targetInterface helloInterface = targetInterface(0xdCDB4db4a54F689ECC486d8BAcC08Cde4AC7FcA8);

 

I then switch to Account two, and deploy the attackers phishing contract. This gives us the attackers contract address:  

 

ü  0x4e1426490dBfBa9110064fb912fe7221074cC0c9

 



 

Finally, I switch to the third account, ( my social engineered victim account) with the address:

 

ü  0x00bff3B21f6924D6e639Ce60e4Dac62Ec2c21269

 

 


 

If I then click the myMSG button on the attackers contract I should get the attackers address as the msg.sender resolves the address calling the contract. In this case I call the attackers contract but the attacker's contract is actually making the call to the target contract, so the msg.sender is the attackers contract even though or victim is the one clicking the button.  Indeed, this is true, shown below, the attackers contract address is returned when validated with msg.sender.

___________________________________________________________________________________

 

decoded output     {

 "0": "address: 0x4e1426490dBfBa9110064fb912fe7221074cC0c9"

}

___________________________________________________________________________________

 

Next I click the myTX button which should return the victims address from the 3rd account as the tx.origin check returns the original calling account of the user, not the attackers contract making the call. Indeed, this is true, shown below, the victims contract address is returned when validated with tx.origin.

___________________________________________________________________________________

 

decoded output     {

"0": "address: 0x00bff3B21f6924D6e639Ce60e4Dac62Ec2c21269"

}

___________________________________________________________________________________

  

I hope that clears up any confusion as to the difference between both msg.sender and tx.origin.  We will now take a look at a more comprehensive example with a bit of vulnerable code to put this into context and show how to bypass some controls using this attack method.

Action Steps:

ü  Review this code prior to reading the explanation.

ü  What is wrong with the logic in this contract?

ü  What would your path of exploitation be?

ü  What would the impact of this attack be?

ü  Type this code into remix and follow along with the walk through


Simple Example Video Walk Through: 


 

Vulnerable TX.Origin Example Walkthrough:

1.    pragma solidity ^0.6.6;
2.   
3.    contract BankOfEther {
4.      address owner;
5.      mapping (address =>uint) balances;
6.       
7.      constructor() public {
8.        owner = msg.sender;
9.      }
10.    
11.  function deposit() public payable{
12.    balances[msg.sender] = balances[msg.sender]+msg.value;     
13.   }
14.    
15.  function transferTo(address payable to, uint amount) public payable{
16.      require(tx.origin == owner);
17.      to.transfer(amount);
18.  }
19.    
20.  function changeOwner(address newOwner) public{
21.      require(tx.origin == owner);
22.      owner = newOwner;
23.                 }
24.    
25.  function kill() public {
26.      require(msg.sender == owner);
27.      selfdestruct(msg.sender);
28.  }
29.}

 

Above is an example of a contract which uses tx.origin to check for user authorization. On lines 16 and 21 you will see that in order to transfer contract funds or change the owner of the contract, you need to be the owner of the contract. This check uses the tx.origin value. The owner which is checked is set in the constructor on line 8 when the contract is deployed.

Also note that there is a kill function at line 25 using Solidity's built-in self-destruct function. This function will destroy the contract making it unusable and send any remaining contract ether to the address specified. This function is using authorization checks against the owner via the msg.sender rather than the tx.origin.

 

Action steps to familiarize yourself with the contract:

ü  Type the code above into Remix and deploy it

ü  Change the value field to 10 and the denomination to ether

ü  Deposit the 10 ether with the deposit function.

ü  Switch accounts and try to run changeOwner, Kill and transferTo functionality

ü  Try the same thing with the original account

ü  Try to deposit funds again

 

In your action steps and exploration of the contract you will notice that these functions do not run properly with the second account as you are not the owner of the contract when using the second account. You will also notice that these did run properly when used with the first account that deployed the contract as this user was set to the owner when deployed. You will also notice that when you ran the kill function it rendered the contract unusable and your funds were returned to your account from the initial deposit.

Now that we are familiar with the contracts functionality and we know that it is dangerously checking authorization using tx.origin  on both the transferTo and changeOwner functions. What would we do to attack this?

In order to formulate an attack, we will use a standard phishing style attack via social engineering. Exactly the same as if we were contracted to perform social engineering on a penetration test, however the malicious site that we send our victim communicates with our malicious smart contract on the backend as a proxy into the vulnerable contract for example using a decentralized web application (DAP) that makes web3.js calls. We used web3.js calls in an earlier chapter when directly making calls to a contract.

How we attack this would depend on our motivations as an attacker. We could simply trick the contract owner into running functionality on our malicious contract which then transfers all of the funds out of the contract to the attacker's wallet. The owner may not even notice this attack took place until he had issues with account balances. He may not even realize when and how it happened depending on how you orchestrate your attack. We could also take control of the whole contract and become the owner of the contract which would provide us with unfettered access to sensitive functionality at any time.

Let's take a look at a malicious smart contract that could transfer out all of the funds and additionally give use full administrative control of the contract. Generally, in a live attack scenario we would code a pretty looking DAP page around this attacker's contract with Web3.js much like in a phishing engagement.

1.  pragma solidity ^0.6.6;
2.   
3.  interface targetInterface {
4.  function transferTo(address payable to, uint amount)  payable external;
5.  function changeOwner(address newOwner) external;
6.  function kill() external;
7.  }
8.   
9.  contract PhishingBankOfEther {
10.  address payable attackerAddress;
11.    
12.  constructor() public {
13.     attackerAddress = msg.sender;
14.  }
15.    
16.  targetInterface bankInterface = targetInterface(ADDRESS);
17. 
18.  function test () payable public {
19.     bankInterface.transferTo(attackerAddress, 1 ether);
20.     bankInterface.changeOwner(attackerAddress);
21.  }
22.}

 

Most of this contract above is setting up the target interface, so this should be pretty easy to follow if you read through the section on Reentrancy where we setup an interface in our attacking contract.  But just to review an interface is a way that we can call functions from another contract via its address and function names. For example, on lines 3-6 we create an interface and simply copy paste the function definitions from our target contract into our interface definition. That's it.  And then we take that target interface we created and point it at the address of the target contract on line 16 with the name bankInterface. That is really the only thing we are doing for 75% of this contract. Nothing new or scary.

At this point we can use the bankInterface variable to access functionality within the target contract from our attacking contract.  Pretty simple right?  

Now the actual meat of this attacking contract is within lines 18-20 where we have a test function which calls the transferTo and changeOwner functions we do not have access to as a non-owner.

 

Action Steps:

ü  Re-deploy the target contract with your first account on remix

ü  Deposit 10 ether into the target contract

ü  Copy the address of the target contract via the copy button on the right side of the deployed contract

ü  Within the attacking contract replace the ADDRESS with the copied address from the target

ü  Switch to the second account in your list of accounts

ü  Deploy this contract and you will see a single function named test

 

Now as before with your attacker's account you cannot run functionality which performs authorization checks because the attackers address is not the owner, so running this test function which changes the owner and sends 1 ether will not work from the second account.  However, instead of our attacker running this functionality directly, the attacker would phish the Owner located on account one. The phish would use the attacker's contract which would perform the actions as the owner due to the incorrect check using tx.origin.

 

Action steps:

ü  Switch to the first account

ü  Try using the transfer function to verify that its working and that you're the owner

ü  Run the test function from the attacker's contract with account 1.

ü  Now try to use that send function again. Did it work?

ü  Try to use the kill function. Did that work?

ü  Now switch to the attackers account and use the send function. Did that work this time?

ü  Now kill the contract from the attackers account. What happened?

 

So, what happened when you used the test function from the attacker's contract?

The test function called the changeOwner and transferTo functions from the attacker's contract. But not as the attacker's address because authorization was checked via the Tx.origin which is the person calling the attacker's contract (account 1), not the attacker's contract address (account 2).

Even with the phishing contract if we were to call the kill function from the attacker's contract it would have failed because it uses the msg.sender. So, in order to execute kill, we had to use changeOwner and become the owner of the contract prior to calling the kill function.

As a result of phishing the owner into using the attacker's contract, the attacker is now the owner of this target contract. As such, the attacker actually can call the kill function directly without any issues and the original owner has been locked out of administrative functionality. 

Now in real life we, have a couple different options for attacking this user via a phishing attack over chat, email or even the phone.

Attack Options:

  1. Send a user a link to a website, perhaps a game they can play on Ethereum etc
  2. Sell the owner something and get the owner to send you any amount of Ether to your contract address. At this point you would have a fall back function which performs actions on the user's behalf simply by sending funds to our contracts account address and having the fallback function auto execute functionality with the owner's address.

 

I hope all of this makes sense. If you got stuck at any point during this walkthrough make sure to check out the video for a walkthrough of the lab and additional attack options.  

 

Phishing MITM Attack Walk Through: 





Smart Contract Hacking - 0x10 - Man In The Middle(MITM) Phishing Attacks Via TX.Origin Authorization.mp4 from Console Cowboys on Vimeo.


References

Github code for this chapter:  https://github.com/cclabsInc/BlockChainExploitation/tree/master/2020_BlockchainFreeCourse/Tx.Origin

More articles


  1. Hackrf Tools
  2. Pentest Tools Subdomain
  3. Android Hack Tools Github
  4. Hacker Security Tools
  5. Pentest Tools Bluekeep
  6. Hacker Tools
  7. Hack Tools Pc
  8. Hacking Tools Kit
  9. Hacking Tools For Windows 7
  10. Hack Tools
  11. Hacker Tools For Mac
  12. Nsa Hack Tools
  13. Hacker Tools Linux
  14. Best Hacking Tools 2019
  15. Github Hacking Tools
  16. Hack Tools Mac
  17. Hackrf Tools
  18. How To Install Pentest Tools In Ubuntu
  19. Pentest Tools Review
  20. Hacker Tools Online
  21. Hacking Tools For Windows Free Download
  22. Pentest Tools Port Scanner
  23. Hacker Tool Kit
  24. Growth Hacker Tools
  25. Pentest Tools Tcp Port Scanner
  26. Top Pentest Tools
  27. Underground Hacker Sites
  28. How To Install Pentest Tools In Ubuntu
  29. Pentest Tools Kali Linux
  30. Kik Hack Tools
  31. Usb Pentest Tools
  32. Hack Tools For Pc
  33. Hacking Tools
  34. Hack App
  35. Hack Tools
  36. Hackrf Tools
  37. Hacker Tools For Ios
  38. Hacking Tools Kit
  39. Install Pentest Tools Ubuntu
  40. Top Pentest Tools
  41. Pentest Reporting Tools
  42. Pentest Tools Website
  43. Hak5 Tools
  44. Pentest Tools Subdomain
  45. Hacker Search Tools
  46. Hacker Tools For Windows
  47. Pentest Recon Tools
  48. Tools For Hacker
  49. Hacker Tools Free
  50. Hack Tools 2019
  51. Hacker Search Tools
  52. Ethical Hacker Tools
  53. Hacking Tools Mac
  54. How To Install Pentest Tools In Ubuntu
  55. Hacker Tools Github
  56. Hacking App
  57. Hack Tools Mac
  58. Hacker Tools Free
  59. Hack Tools Online
  60. Hacker Tools Github
  61. Hacker Tools Linux
  62. Pentest Tools Review
  63. Hack Tool Apk
  64. Hacker Tools For Windows
  65. Hacking Tools 2019
  66. Bluetooth Hacking Tools Kali
  67. Hacks And Tools
  68. Pentest Tools Free
  69. What Are Hacking Tools
  70. Hacker Tools Free
  71. Computer Hacker
  72. Game Hacking
  73. Hacker Tool Kit
  74. Hacking Tools Usb
  75. Hack Tools Online
  76. Hackers Toolbox
  77. What Are Hacking Tools
  78. Hack Tools For Ubuntu
  79. Easy Hack Tools
  80. Pentest Tools Website Vulnerability
  81. Pentest Tools For Ubuntu
  82. Hacker Tool Kit
  83. Pentest Tools For Android
  84. Hack Tools For Games
  85. Hacker Tools Free Download
  86. Hacking Tools For Pc
  87. Hacking Tools Mac
  88. Tools 4 Hack
  89. Hacker Tools For Mac
  90. Hacking Tools Windows
  91. Hak5 Tools
  92. Hacking Tools For Mac
  93. Hacking Tools For Kali Linux
  94. Hacking Tools Name
  95. How To Make Hacking Tools
  96. Hack Tools