big squashed commit, finalize gshellautomator
parent
ea192e2d12
commit
b83e8449e3
39
README.md
39
README.md
|
@ -1,10 +1,32 @@
|
|||
# <b> Google Colab Automator, without Selenium! </b>
|
||||
# <b> Google Cloud Shell Automator! </b>
|
||||
|
||||
## <b> What is this </b>
|
||||
This program creates a botnet to execute arbitrary code using multiple Google Colab VMs.<br>
|
||||
# <b> What is this </b>
|
||||
This program creates a botnet to execute arbitrary code using multiple Google Shell Docker containers.<br>
|
||||
<br>
|
||||
|
||||
|
||||
# <b> Dependendencies </b>
|
||||
This program needs some dependencies to work. All of python dependencies are already installed in the venv folder. Note that for now this makes use of xephyr to create virtual desktops and for now this only works on Linux with X11 as a display manager. The packages' names will vary from distro to distro, here are the most important ones which you will need to take care by yourself
|
||||
|
||||
* Xephyr (xorg-xephyr)
|
||||
* TKinter (tk)
|
||||
|
||||
<br>
|
||||
|
||||
# <b> Execution </b>
|
||||
From the root rolder of the project, execute
|
||||
|
||||
src/colab_automator.sh
|
||||
|
||||
it will take care of starting all the needed services in the correct
|
||||
order
|
||||
|
||||
<br>
|
||||
|
||||
# <b> Explanation of services and exploit </b>
|
||||
|
||||
### <b> Google Colab and Qwiklabs </b>
|
||||
Google Colab is a Google service which gives free, temporary, use of virtual machines with powerful NVIDIA Tesla GPUs. Normally this is used to train ML and other AI models, but nothing impedes the use of the service for other purposes, such has password cracking with hashcat or crypto mining (at least in the free version - in Google Colab Pro crypto mining is forbidden).
|
||||
Google
|
||||
The downside is that the account gets temporary blocked when a too andlong intense use is detected.
|
||||
Qwiklabs (qwiklabs.com) is a third-party service which gives temporary Google Accounts for training in Google Cloud Shell use. Their first course (https://www.qwiklabs.com/focuses/2794?parent=catalog) is completely free, others require some in-site credits to be purchased.
|
||||
Combining the two services, infinite temporary and disposable Google Accounts can be obtained from qwiklabs and used for mining on colab, until the qwiklabs session expires or the miner gets blocked by Colab. At such point, a new session can be started. That's basically free money. Obviously this can also be used to automated non-malicious tasks, as long as the Colab notebook is publicly available (e.g. as a github gist). After a certain time number of times repeating the course, the qwiklabs account might reach it's <i>quota</i> for that course and a new one needs to be created. I'll will look into a way of automating account creation in the future. For now, use temp mails from temp-mail.org when creating accounts
|
||||
|
@ -40,11 +62,8 @@ For simpicity, and to avoid messing up the OS by clicking on the wrong stuff, bo
|
|||
<br>
|
||||
<br>
|
||||
|
||||
# <b> Failure </b>
|
||||
This project apparently badly failed, since google accounts obtained through qwiklabs.com labs appear to never be able to obtain a backend on Google Colab<br>
|
||||
## Possible workaround.
|
||||
Go back to cpu-only and use Google Cloud Shell (which is actually what qwiklabs is meant to be used with) and create some king of botnet/userbot/viewbot for youtube, altervista or other websites. The machine will always appear to be a new one, because it actually is
|
||||
|
||||
# Qwiklabs monthly subscription
|
||||
There is a workaround to obtain a qwiklabs monthly subscription that actually works: https://www.youtube.com/watch?v=gF6agG9kyBs (actually works).<br>
|
||||
Tested on account i3z8qtab@xojxe.com, now it has monthly sub
|
||||
Tested on account i3z8qtab@xojxe.com, now it has monthly sub
|
||||
This is too convoluted to automated and has no use for now
|
||||
|
||||
|
|
BIN
chromedriver
BIN
chromedriver
Binary file not shown.
|
@ -5,4 +5,5 @@ selenium==3.141.0
|
|||
urllib3==1.26.5
|
||||
SpeechRecognition==3.8.1
|
||||
pydub==0.25.1
|
||||
bs4
|
||||
bs4
|
||||
random_user_agent
|
Binary file not shown.
Binary file not shown.
|
@ -1,152 +0,0 @@
|
|||
from utils import browser_manager
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.by import By
|
||||
import time
|
||||
from threading import Thread, Event
|
||||
|
||||
from utils.global_vars import PROXY
|
||||
|
||||
class ColabGist(Thread):
|
||||
|
||||
'''
|
||||
Account is a tuple of (user, pass)
|
||||
Min is for how long the gist needs to be executed
|
||||
Backend is the backend needed for this gist ('N': None, 'T': TPU, 'G': GPU)
|
||||
For future-proofness each Gist is started in its own thread, this makes possible to run multiple gists in different threads at the same time
|
||||
'''
|
||||
|
||||
def __init__(self, url, account, minutes=5, backend='N'):
|
||||
self.url = url
|
||||
self.account = account
|
||||
self.minutes = minutes
|
||||
self.backend = backend
|
||||
|
||||
self.refresh_event = Event()
|
||||
self.stop_event = Event()
|
||||
print("[ColabGist {}] New Colab Gist Thread created! Using account {} ".format(self.url, self.account))
|
||||
|
||||
def run(self):
|
||||
self.run_colab()
|
||||
|
||||
def run_colab(self):
|
||||
print("[ColabGist {}] Starting the gist".format(self.url))
|
||||
self.start_browser()
|
||||
self.start_session()
|
||||
|
||||
def sign_in(self):
|
||||
print("[ColabGist {}] Signing in...".format(self.url))
|
||||
|
||||
try:
|
||||
self.driver.get("https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&prompt=consent&response_type=code&client_id=407408718192.apps.googleusercontent.com&scope=email&access_type=offline&flowName=GeneralOAuthFlow") #need a fallback for when
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#identifierId", self.account[0] + "\n")
|
||||
time.sleep(1.5)
|
||||
browser_manager.inputText(self.driver, By.XPATH, '//*[@id="password"]/div[1]/div/div[1]/input', self.account[1] + "\n")
|
||||
time.sleep(1.5)
|
||||
try:
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="accept"]')
|
||||
time.sleep(1.5)
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="yDmH0d"]/c-wiz[2]/c-wiz/div/div[1]/div/div/div/div[2]/div[3]/div/div[2]/div')
|
||||
time.sleep(1.5)
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
# Run the desired Colab notebook. Logging into Google account by profile is mandatory
|
||||
def start_session(self):
|
||||
if not self.sign_in():
|
||||
print("[ColabGist {}] Got the old login screen, trying again".format(self.url))
|
||||
self.driver.quit()
|
||||
self.run_colab()
|
||||
return
|
||||
|
||||
self.driver.get(self.url)
|
||||
self.start_gist()
|
||||
|
||||
# Leave the colab be for the specified time
|
||||
starting = time.time()
|
||||
print("[ColabGist {}] Executing the gist for the next {} minutes. Using Backend {}".format(self.url, self.minutes, self.backend) )
|
||||
while (int(time.time() - starting))/60 < self.minutes:
|
||||
|
||||
if self.stop_event.is_set():
|
||||
self.actual_quit()
|
||||
if self.refresh_event.is_set():
|
||||
self.start_gist()
|
||||
|
||||
if(int(time.time() - starting > 15)):
|
||||
try:
|
||||
if self.driver.find_elements(By.XPATH, "//*[contains(text(),'No backend')]"):
|
||||
print("[ColabGist {}] This account {} has been blocked :/ try again with another one".format(self.url, self.account))
|
||||
self.driver.quit()
|
||||
elif self.driver.find_elements(By.XPATH, "//*[contains(text(),'Cannot connect')]"):
|
||||
print("[ColabGist {}] No backend was available, maybe the service is overflooded or this account/computer is about to be blocked :(".format(self.url))
|
||||
self.driver.quit()
|
||||
return
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
'''char = input()
|
||||
if char == "t":
|
||||
break
|
||||
elif char == "g":
|
||||
elapsed = time()-starting
|
||||
elapsed_min = int(elapsed / 60)
|
||||
elapsed_sec = int(elapsed % 60)
|
||||
print("Elapsed time: {}m{}s".format(elapsed_min, elapsed_sec))
|
||||
else:
|
||||
print("Unrecognized option")'''
|
||||
|
||||
print("[ColabGist {}] Time's up! Closing the browser".format(self.url))
|
||||
self.actual_quit()
|
||||
|
||||
def start_gist(self):
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#runtime-menu-button")
|
||||
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id=":24"]')
|
||||
time.sleep(1)
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#accelerator")
|
||||
time.sleep(1.5)
|
||||
acc = self.driver.find_element_by_css_selector("#accelerator")
|
||||
time.sleep(1.5)
|
||||
acc.send_keys(self.backend)
|
||||
acc.send_keys("\n")
|
||||
time.sleep(1.5)
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#ok")
|
||||
time.sleep(1.5)
|
||||
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#runtime-menu-button")
|
||||
time.sleep(1.5)
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id=":22"]')
|
||||
time.sleep(1.5)
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#runtime-menu-button")
|
||||
time.sleep(1.5)
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id=":1t"]')
|
||||
time.sleep(1.5)
|
||||
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#ok")
|
||||
time.sleep(1.5)
|
||||
|
||||
def terminate_session(self):
|
||||
# Terminate the session
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#runtime-menu-button")
|
||||
#factory reset to close session
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id=":22"]')
|
||||
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#ok")
|
||||
# Wait for the session to close
|
||||
time.sleep(60)
|
||||
|
||||
def start_browser(self):
|
||||
self.driver=browser_manager.start_browser()
|
||||
|
||||
def stop_browser(self):
|
||||
# Close browser
|
||||
self.driver.quit()
|
||||
|
||||
def actual_quit(self):
|
||||
self.terminate_session()
|
||||
self.stop_browser()
|
||||
|
||||
def quit(self):
|
||||
self.stop_event.set()
|
|
@ -15,8 +15,13 @@ echo "[*] Starting Xephyr on :2, contained inside :1"
|
|||
DISPLAY=:1 Xephyr -br -ac -noreset -screen 800x600 :2 > /dev/null 2> /dev/null&
|
||||
sleep 5
|
||||
# Start a copyq server, that will be used to copy the email and password of the obtained account from the clipboard of Xephyr
|
||||
echo "[*] Starting copyq server on :2"
|
||||
DISPLAY=:2 copyq > /dev/null 2> /dev/null&
|
||||
#echo "[*] Starting copyq server on :2"
|
||||
#DISPLAY=:2 copyq > /dev/null 2> /dev/null&
|
||||
|
||||
#set the kbd layout to the same of :0, otherwise sometimes we get mismatched letters
|
||||
#setxkbmap -display :0 -print | xkbcomp - :1 > /dev/null 2> /dev/null&
|
||||
# xkbcomp :0 :1
|
||||
# xkbcomp :0 :2
|
||||
|
||||
sleep 2
|
||||
echo "[*] Now starting the actual script"
|
||||
|
|
15
src/main.py
15
src/main.py
|
@ -1,12 +1,11 @@
|
|||
import subprocess
|
||||
from utils import global_vars, proxy
|
||||
from utils import global_vars
|
||||
import time
|
||||
from qwiklabs import get_account
|
||||
from shell import shell
|
||||
from shell.gists.gists import UserBot
|
||||
|
||||
print("[MAIN] Entering main script!")
|
||||
|
||||
p = proxy.Proxy()
|
||||
while True:
|
||||
p.request_new_proxy()
|
||||
print(global_vars.PROXY)
|
||||
|
||||
time.sleep(30)
|
||||
s = shell.Shell()
|
||||
s.start()
|
||||
s.execute_python_custom_script(UserBot())
|
Binary file not shown.
Binary file not shown.
|
@ -1,39 +0,0 @@
|
|||
# access ngrok with selenium, get the first ip/port combination
|
||||
# https://dashboard.ngrok.com/endpoints/status
|
||||
# automatically accepts key and inputs password
|
||||
# sshpass -p hellogoodbye ssh -D 1337 -q -C -N root@ip -p port -o "StrictHostKeyChecking no"
|
||||
|
||||
from utils import browser_manager
|
||||
from selenium.webdriver.common.by import By
|
||||
import time
|
||||
from colab import colab
|
||||
|
||||
class Ngrok:
|
||||
|
||||
def __init__(self, account):
|
||||
self.account = account
|
||||
|
||||
def start_browser(self):
|
||||
self.driver = browser_manager.start_browser(headless=True)
|
||||
|
||||
def close_browser(self):
|
||||
browser_manager.quit_browser(self.driver)
|
||||
|
||||
def access_ngrok(self):
|
||||
self.driver.get('https://dashboard.ngrok.com/endpoints/status')
|
||||
time.sleep(5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, '#email', self.account[0])
|
||||
time.sleep(1)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, '#password', self.account[1])
|
||||
time.sleep(1)
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[2]/div/section/main/div/div/div[2]/div[1]/div/form/div[3]/div/div/div/button')
|
||||
time.sleep(5)
|
||||
|
||||
# Assumes access_ngrok has already been called
|
||||
def get_proxy_ip(self):
|
||||
self.driver.get('https://dashboard.ngrok.com/endpoints/status')
|
||||
time.sleep(10) #takes a bit to load, just in case
|
||||
proxy_line = self.driver.find_element_by_xpath('/html/body/div[2]/div/section/section/main/div/div/div/main/div[2]/div/div/div/div/div/table/tbody/tr[2]/td[3]').text
|
||||
# strip down the tcp:// part at the start, it's not needed
|
||||
proxy = proxy_line[6:]
|
||||
return proxy
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -132,69 +132,119 @@ if __name__ == "__main__":
|
|||
pyautogui.click()
|
||||
|
||||
|
||||
bashCommand = "copyq clipboard"
|
||||
# Copy username to clipboard
|
||||
time.sleep(20)
|
||||
# print("Copying email")
|
||||
pyautogui.moveTo(ui.qwiklabs_gui.EMAIL_COPY_BTN[0], ui.qwiklabs_gui.EMAIL_COPY_BTN[1], 3, pyautogui.easeOutQuad)
|
||||
pyautogui.click()
|
||||
g_email = subprocess.check_output(['bash','-c', bashCommand]).decode('utf-8')
|
||||
# Now the lab should be started, we can quit. Creds will be obtained by selenium
|
||||
|
||||
# Copy password to clipboard
|
||||
time.sleep(5)
|
||||
# print("Copying password")
|
||||
pyautogui.moveTo(ui.qwiklabs_gui.PASSWORD_COPY_BTN[0], ui.qwiklabs_gui.PASSWORD_COPY_BTN[1], 3, pyautogui.easeOutQuad)
|
||||
pyautogui.click()
|
||||
g_password = subprocess.check_output(['bash','-c', bashCommand]).decode('utf-8')
|
||||
time.sleep(5)
|
||||
|
||||
# a possible way of finding out we haven't got the password, therefore the account was probably blocked or there was a connection issue
|
||||
if '@' in g_email:
|
||||
print(g_email, g_password)
|
||||
else:
|
||||
# account_list.mark_account_for_deletition(account_email)
|
||||
print(False)
|
||||
# bashCommand = "copyq clipboard"
|
||||
# # Copy username to clipboard
|
||||
# time.sleep(20)
|
||||
# # print("Copying email")
|
||||
# pyautogui.moveTo(ui.qwiklabs_gui.EMAIL_COPY_BTN[0], ui.qwiklabs_gui.EMAIL_COPY_BTN[1], 3, pyautogui.easeOutQuad)
|
||||
# pyautogui.click()
|
||||
# g_email = subprocess.check_output(['bash','-c', bashCommand]).decode('utf-8')
|
||||
|
||||
# # Copy password to clipboard
|
||||
# time.sleep(5)
|
||||
# # print("Copying password")
|
||||
# pyautogui.moveTo(ui.qwiklabs_gui.PASSWORD_COPY_BTN[0], ui.qwiklabs_gui.PASSWORD_COPY_BTN[1], 3, pyautogui.easeOutQuad)
|
||||
# pyautogui.click()
|
||||
# g_password = subprocess.check_output(['bash','-c', bashCommand]).decode('utf-8')
|
||||
# time.sleep(5)
|
||||
|
||||
# # a possible way of finding out we haven't got the password, therefore the account was probably blocked or there was a connection issue
|
||||
# if '@' in g_email:
|
||||
# print(g_email, g_password)
|
||||
# else:
|
||||
# # account_list.mark_account_for_deletition(account_email)
|
||||
# print(False)
|
||||
|
||||
def get_google_account():
|
||||
from utils import global_vars
|
||||
from selenium.webdriver.common.by import By
|
||||
from utils.browser_manager import clickButton, inputText, expand_shadow_element, start_browser
|
||||
import subprocess
|
||||
import json
|
||||
import time
|
||||
|
||||
if not global_vars.TEST_ACCOUNT:
|
||||
print("[QL_GetAccount] Getting new google account..." )
|
||||
account = global_vars.ql_list.request_new_account()
|
||||
|
||||
res = subprocess.check_output(['bash','-c', "src/qwiklabs/get_account.sh {} {} ".format(str(global_vars.PROXY), account)]).decode('utf-8')
|
||||
if res == 'False' or 'False' in res:
|
||||
res = bool(res)
|
||||
# Maybe if we failed there was a connection issue, so ping qwiklabs.com to check
|
||||
# If ping is successful the account is out of quota
|
||||
|
||||
if global_vars.PROXY is False:
|
||||
r = requests.get("https://qwiklabs.com")
|
||||
else :
|
||||
proxyDict = {
|
||||
"socksVersion" : 5,
|
||||
"socks" : global_vars.PROXY
|
||||
}
|
||||
|
||||
r = requests.get("https://qwiklabs.com", proxies=proxyDict)
|
||||
|
||||
# ping was unsuccessful, delete the account
|
||||
if r.stats_code == 200:
|
||||
print("[QL_GetAccount] Something went wrong, trying again")
|
||||
return get_google_account()
|
||||
else:
|
||||
global_vars.account_list.mark_account_for_deletition(account)
|
||||
|
||||
else:
|
||||
res = tuple(res.rsplit())
|
||||
|
||||
print("[QL_GetGAccount] {}".format(res))
|
||||
return res
|
||||
|
||||
else:
|
||||
if global_vars.TEST_ACCOUNT:
|
||||
print("[QL_GetAccount] Using Test Account {}".format(global_vars.TEST_ACCOUNT) )
|
||||
return global_vars.TEST_ACCOUNT
|
||||
driver = start_browser()
|
||||
driver.get(global_vars.TEST_ACCOUNT[2])
|
||||
return global_vars.TEST_ACCOUNT[0], global_vars.TEST_ACCOUNT[1], global_vars.TEST_ACCOUNT[2], driver
|
||||
else:
|
||||
print("[QL_GetAccount] Getting new google account..." )
|
||||
#TODO: Handle failure in getting the account
|
||||
|
||||
if global_vars.TEST_QWIKLABS_ACCOUNT is False:
|
||||
print("[QL_GetAccount] Using TEST Qwiklabs account to get it")
|
||||
account = global_vars.ql_list.request_new_account()
|
||||
|
||||
subprocess.call(['bash','-c', "src/qwiklabs/get_account.sh {} {} ".format(str(global_vars.PROXY), account)])
|
||||
else:
|
||||
print("[QL_GetAccount] Using Qwiklabs test account")
|
||||
account = global_vars.TEST_QWIKLABS_ACCOUNT
|
||||
|
||||
driver = start_browser()
|
||||
driver.get("https://www.qwiklabs.com/focuses/2794?catalog_rank=%7B%22rank%22%3A2%2C%22num_filters%22%3A0%2C%22has_search%22%3Atrue%7D&parent=catalog&search_id=12598152")
|
||||
|
||||
time.sleep(5)
|
||||
clickButton(driver, By.XPATH, '/html/body/div[1]/div[1]/ql-toolbar/div[2]/a[2]')
|
||||
time.sleep(5)
|
||||
|
||||
inputText(driver, By.CSS_SELECTOR, "#user_email", account)
|
||||
inputText(driver, By.CSS_SELECTOR, "#user_password", "hellogoodbye" + '\n')
|
||||
time.sleep(5)
|
||||
|
||||
panel = driver.find_element_by_xpath('/html/body/main/div/ql-drawer-container/ql-drawer-content/ql-drawer-container/ql-drawer[1]/ql-lab-control-panel')
|
||||
details = panel.get_attribute('labdetails')
|
||||
|
||||
details_json = json.loads(details)
|
||||
gshell_link = details_json[0]['href']
|
||||
email = details_json[1]['value']
|
||||
password = details_json[2]['value']
|
||||
|
||||
print("[QL_GetAccount] Got a Google account, it is", (email, password, gshell_link))
|
||||
|
||||
return email, password, gshell_link, driver
|
||||
|
||||
# def get_google_account():
|
||||
# from utils import global_vars
|
||||
# import subprocess
|
||||
|
||||
# if not global_vars.TEST_ACCOUNT:
|
||||
# print("[QL_GetAccount] Getting new google account..." )
|
||||
# account = global_vars.ql_list.request_new_account()
|
||||
|
||||
# res = subprocess.check_output(['bash','-c', "src/qwiklabs/get_account.sh {} {} ".format(str(global_vars.PROXY), account)]).decode('utf-8')
|
||||
# if res == 'False' or 'False' in res:
|
||||
# res = bool(res)
|
||||
# # Maybe if we failed there was a connection issue, so ping qwiklabs.com to check
|
||||
# # If ping is successful the account is out of quota
|
||||
|
||||
# if global_vars.PROXY is False:
|
||||
# r = requests.get("https://qwiklabs.com")
|
||||
# else :
|
||||
# proxyDict = {
|
||||
# "socksVersion" : 5,
|
||||
# "socks" : global_vars.PROXY
|
||||
# }
|
||||
|
||||
# r = requests.get("https://qwiklabs.com", proxies=proxyDict)
|
||||
|
||||
# # ping was unsuccessful, delete the account
|
||||
# if r.stats_code == 200:
|
||||
# print("[QL_GetAccount] Something went wrong, trying again")
|
||||
# return get_google_account()
|
||||
# else:
|
||||
# global_vars.account_list.mark_account_for_deletition(account)
|
||||
|
||||
# else:
|
||||
# res = tuple(res.rsplit())
|
||||
|
||||
# print("[QL_GetGAccount] {}".format(res))
|
||||
# return res
|
||||
|
||||
# else:
|
||||
# print("[QL_GetAccount] Using Test Account {}".format(global_vars.TEST_ACCOUNT) )
|
||||
# return global_vars.TEST_ACCOUNT
|
||||
|
||||
|
|
Binary file not shown.
|
@ -19,4 +19,4 @@ fi
|
|||
sleep 5
|
||||
|
||||
#Now start the actual bot, we're in a safe environment
|
||||
DISPLAY=$d python src/qwiklabs/get_account.py $2
|
||||
DISPLAY=:2 python src/qwiklabs/get_account.py $2
|
Binary file not shown.
|
@ -0,0 +1,9 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
from shell import shell
|
||||
|
||||
class Gist:
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, Shell: shell):
|
||||
pass
|
|
@ -1,6 +1,8 @@
|
|||
from enum import Enum
|
||||
from shell.gists.userbot import UserBot
|
||||
from shell import shell
|
||||
|
||||
class Gists(Enum):
|
||||
PROXY1 = "https://colab.research.google.com/gist/EmaMaker/4e1478c9913a2df58fc1b8ff422fa161/proxy.ipynb"
|
||||
PROXY2 = "https://colab.research.google.com/gist/EmaMaker/79645e7bcec4413ce868e3f9bc4d1939/proxy.ipynb"
|
||||
MINER = "https://colab.research.google.com/gist/EmaMaker/296863713437f703ec1aa56ae45b1f8f/nicehash-miner.ipynb"
|
||||
MINER = "https://colab.research.google.com/gist/EmaMaker/296863713437f703ec1aa56ae45b1f8f/nicehash-miner.ipynb"
|
|
@ -0,0 +1,5 @@
|
|||
#remove home to get rid of any remaining files from latest session. Only happens in test mode, but it's always useful
|
||||
.2. rm -rf ~/*
|
||||
.2. mkdir ~/.cloudshell
|
||||
.2. touch ~/.cloudshell/no-pip-warning
|
||||
.2. touch ~/.cloudshell/no-apt-get-warning
|
|
@ -0,0 +1,7 @@
|
|||
.30. sudo apt-get install -y xorg xserver-xephyr
|
||||
.2.1
|
||||
.2.1
|
||||
.30.1
|
||||
.45. sudo apt-get install -y firefox-esr tigervnc-standalone-server curlftpfs python3 python3-pip
|
||||
# no view-only password
|
||||
.2. clear
|
|
@ -0,0 +1,7 @@
|
|||
.10. python3 -m pip install --upgrade pip
|
||||
.10. python3 -m pip install selenium
|
||||
.15. wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
.45. sudo apt-get install -y ./google-chrome-stable_current_amd64.deb
|
||||
.10. wget https://chromedriver.storage.googleapis.com/94.0.4606.61/chromedriver_linux64.zip
|
||||
.2. unzip chromedriver_linux64.zip
|
||||
.2. sudo mv chromedriver /usr/bin/
|
|
@ -0,0 +1,5 @@
|
|||
.5. vncserver :1 -geometry 1280x720
|
||||
# insert password for vnc server
|
||||
.2. hellogoodbye
|
||||
.2. hellogoodbye
|
||||
.5. n
|
|
@ -0,0 +1,131 @@
|
|||
'''Website User Simulator
|
||||
Simulate the behaviour of a user visiting the website
|
||||
* Start from a given page
|
||||
* Fetch all redirection links present on the page withing the defines website scope
|
||||
* Chose a random one and redirect to that
|
||||
* Repeat until out of the website (link to another website) or maximum number of times exceeded
|
||||
|
||||
This requires the Tor Daemon to be installed, so you want to look into installing that. Most Linux Distros have that in their repos
|
||||
|
||||
This can also be used to simulate YT views:
|
||||
* When visiting the webpage click on the play button
|
||||
* Wait at least 30 seconds
|
||||
* Youtube should count this as a view
|
||||
'''
|
||||
|
||||
from selenium.webdriver.support.ui import Select
|
||||
import selenium.webdriver as webdriver
|
||||
import selenium.common.exceptions as sexceptions
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from time import sleep
|
||||
import random
|
||||
import subprocess
|
||||
|
||||
import sys
|
||||
|
||||
outside_website_scopes = ["blog.altervista.org", "it.altervista.org", "pinterest",
|
||||
"facebook.com", "instagram.com", "iubenda.com", "twitter.com", "#"]
|
||||
|
||||
ACCEPT_COOKIES_BTN_SEL = ".iubenda-cs-accept-btn"
|
||||
MAX_REDIRECTION = 5
|
||||
LOOK_FOR_ADS = True
|
||||
|
||||
def visit(browser, url, redirs):
|
||||
# go to the page
|
||||
print(f"Visiting: {url}")
|
||||
browser.get(url)
|
||||
|
||||
# Sleep a little bit to wait for all of the page to be loaded (especially ads) and to simulate a user reading. Keep in mind the profile is preset to accept cookies on this website
|
||||
sleep(3)
|
||||
click_noexit(browser, By.CSS_SELECTOR, ACCEPT_COOKIES_BTN_SEL, 10)
|
||||
|
||||
for i in range(0, MAX_REDIRECTION):
|
||||
try:
|
||||
sleep(4)
|
||||
|
||||
# Fetch all the element with links present on the page
|
||||
all_redirect_elements = [x for x in browser.find_elements_by_xpath('.//a') if x.get_attribute('href') != None]
|
||||
print(all_redirect_elements)
|
||||
|
||||
clickable_elements = [x for x in all_redirect_elements if x.is_enabled()]
|
||||
|
||||
if LOOK_FOR_ADS:
|
||||
# Fetch all the ads present on the page. Not all iframes are ads, but that's a good way to get them
|
||||
ads = browser.find_elements_by_tag_name("iframe")
|
||||
else:
|
||||
if not all_redirect_elements:
|
||||
done(browser)
|
||||
|
||||
# Include wanted urls
|
||||
# wanted_urls = [x for x in all_urls for a in website_scopes if x.find(a) != -1]
|
||||
|
||||
# Exclude unwanted urls
|
||||
allowed_elements = []
|
||||
for element in clickable_elements:
|
||||
broke = False
|
||||
for outside_scope in outside_website_scopes:
|
||||
if outside_scope in element.get_attribute('href'):
|
||||
broke = True
|
||||
break
|
||||
if not broke:
|
||||
allowed_elements.append(element)
|
||||
|
||||
# Remove duplicates in list
|
||||
allowed_elements = list(dict.fromkeys(allowed_elements))
|
||||
|
||||
page_index = random.randint(0, len(allowed_elements)-1)
|
||||
|
||||
if LOOK_FOR_ADS:
|
||||
if(random.random()) < 0.15:
|
||||
print("Moving toward", allowed_elements[page_index].get_attribute('href'))
|
||||
allowed_elements[page_index].click()
|
||||
else:
|
||||
#visit ad
|
||||
#get a random iframe and click it
|
||||
ads[random.randint(0, len(ads)-1)].click()
|
||||
|
||||
sleep(5)
|
||||
print("I'm out of the website, bye!")
|
||||
break
|
||||
done(browser)
|
||||
else:
|
||||
print("Moving toward", allowed_elements[page_index].get_attribute('href'))
|
||||
allowed_elements[page_index].click()
|
||||
except Exception as e:
|
||||
print("Error, closing", e)
|
||||
continue
|
||||
|
||||
def main():
|
||||
browser = webdriver.Chrome(executable_path="/home/emamaker/Documents/Projects/GShellAutomator/chromedriver")
|
||||
launch_browser(browser, sys.argv[1], False)
|
||||
print("Script executed!")
|
||||
|
||||
def launch_browser(browser, url, yt):
|
||||
if yt:
|
||||
visit_yt(browser, url)
|
||||
else:
|
||||
visit(browser, url, 0)
|
||||
|
||||
|
||||
def done(browser):
|
||||
global tor
|
||||
browser.close()
|
||||
browser.quit()
|
||||
|
||||
def click_exit(browser, by, desc, timeout):
|
||||
try:
|
||||
WebDriverWait(browser, timeout).until(EC.element_to_be_clickable((by, desc))).click()
|
||||
except:
|
||||
done(browser)
|
||||
|
||||
def click_noexit(browser, by, desc, timeout):
|
||||
try:
|
||||
WebDriverWait(browser, timeout).until(EC.element_to_be_clickable((by, desc))).click()
|
||||
except:
|
||||
done(browser)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,3 @@
|
|||
#this is in its own custom script so that we can set a maximum timer
|
||||
#this time is a large estimate of the actual time required, you never know
|
||||
.60. DISPLAY=:1 python3 userbot.py https://giangillorossi.altervista.org
|
|
@ -0,0 +1,35 @@
|
|||
from shell.gists.gist import Gist
|
||||
from shell.shell import Shell
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
class UserBot (Gist):
|
||||
|
||||
def execute(self, shell):
|
||||
# prepare for userbot, without enabling ephimeral files will be there next reboot
|
||||
shell.execute_script_from_local("./src/shell/gists/scripts/clear_homedir.sh")
|
||||
shell.execute_script_from_local("./src/shell/gists/scripts/prepare_environment_ubuntu.sh")
|
||||
|
||||
i = 1
|
||||
|
||||
while True:
|
||||
print("[UserBOT] Starting execution #{}".format(i))
|
||||
i += 1
|
||||
|
||||
#clean home dir, just in case
|
||||
shell.execute_script_from_local("./src/shell/gists/scripts/clear_homedir.sh")
|
||||
|
||||
#download bot
|
||||
shell.execute_command("wget https://gist.githubusercontent.com/EmaMaker/86d49a9b6b2a66e6299ec4cd9fd8de12/raw/b26b9328a1ee06d34124eee86ff024ae92e0bbf8/userbot.py")
|
||||
#prepare python
|
||||
shell.execute_script_from_local("./src/shell/gists/scripts/prepare_python_environment.sh")
|
||||
|
||||
#the userbot.py script is executing chromedriver in headless mode, so vnc isn't actually needed
|
||||
shell.execute_script_from_local("./src/shell/gists/scripts/start_vnc_server.sh")
|
||||
|
||||
# now execute userbot. Probably there will be some time between end of execution and start of reboot
|
||||
shell.execute_script_from_local("./src/shell/gists/scripts/userbot_script.sh")
|
||||
|
||||
# reboot the machine to get a clean one with a new ip and mac
|
||||
shell.reboot()
|
|
@ -0,0 +1,255 @@
|
|||
'''
|
||||
Executes an arbitrary github gist on GCloudShell in ephimeral mode, no traces left in the docker containers
|
||||
Every restart of the Google Cloud Shell the machine appears to be a completely different one (ip, mac)
|
||||
Specs:
|
||||
2x vCPU Intel Xeon @ 2.6 GHz
|
||||
1GB Ram
|
||||
|
||||
'''
|
||||
# text.get_attribute("value") return the text content of a text field
|
||||
|
||||
from qwiklabs.get_account import get_google_account
|
||||
from utils import global_vars, browser_manager
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium import webdriver
|
||||
|
||||
class Shell():
|
||||
def __init__(self):
|
||||
print("[GCShell] Created a new GShell instance ")
|
||||
Shell.TEXT_AREA_XPATH = '/html/body/cloud-shell-root/div/docked/stacked-layout/div[1]/div/devshell/terminal-container/div/xterm-terminal-tab/div/xterm-terminal/div/div/div/div[2]/div[1]/textarea'
|
||||
Shell.XTERM_SCREEN_XPATH = '/html/body/cloud-shell-root/div/docked/stacked-layout/div[1]/devshell/terminal-container/div/xterm-terminal-tab/div/xterm-terminal/div/div/div/div[2]'
|
||||
|
||||
self.account_specs = get_google_account()
|
||||
|
||||
self.driver = self.account_specs[3]
|
||||
self.account = (self.account_specs[0], self.account_specs[1])
|
||||
self.gcs_link = self.account_specs[2]
|
||||
|
||||
self.started = False
|
||||
|
||||
def start(self):
|
||||
if self.account_specs is False:
|
||||
print("[GCShell] No account was available, can't start!")
|
||||
return
|
||||
|
||||
# If using a test account, use the provided gsc link
|
||||
if global_vars.TEST_ACCOUNT is False:
|
||||
while (browser_manager.waitForElement(self.driver, By.XPATH, '/html/body/main/div/ql-drawer-container/ql-drawer-content/ql-drawer-container/ql-drawer[1]/ql-lab-control-panel') is False):
|
||||
print("[GCShell] Page not ready, waiting...")
|
||||
|
||||
# get the shadow_dom element and click it
|
||||
panel = self.driver.find_element_by_xpath('/html/body/main/div/ql-drawer-container/ql-drawer-content/ql-drawer-container/ql-drawer[1]/ql-lab-control-panel')
|
||||
shadow1 = browser_manager.expand_shadow_element(self.driver, panel)
|
||||
open_shell = shadow1.find_element_by_css_selector('div:nth-child(2) > div > ql-button')
|
||||
print("[GCShell] Opening shell")
|
||||
open_shell.click()
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
# Now switch to the second tab
|
||||
self.driver.switch_to.window(self.driver.window_handles[1]) #apparently clicking in selenium doesn't switch window
|
||||
else:
|
||||
print("[GCShell] Using Google Test Account")
|
||||
self.driver.get(self.gcs_link)
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
oldPage = False
|
||||
#The email may be already filled in, just in case delete it and type it again
|
||||
while browser_manager.waitForElement(self.driver, By.CSS_SELECTOR, '#identifierId') is False:
|
||||
if browser_manager.waitForElement(self.driver, By.CSS_SELECTOR, '#Email') is not False:
|
||||
oldPage = True
|
||||
break
|
||||
|
||||
print("[GCShell] Page not ready, waiting...")
|
||||
time.sleep(5)
|
||||
|
||||
# print("Got old page?", oldPage)
|
||||
|
||||
print("[GCShell] Inserting credentials")
|
||||
if oldPage:
|
||||
email = self.driver.find_element_by_css_selector('#Email')
|
||||
email.send_keys(Keys.CONTROL, 'a')
|
||||
email.send_keys(Keys.BACKSPACE)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, '#Email', self.account[0])
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, '#next')
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
#password is always empty, no need to empty the textbox first
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, '#password', self.account[1])
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, '#submit')
|
||||
else:
|
||||
email = self.driver.find_element_by_css_selector('#identifierId')
|
||||
email.send_keys(Keys.CONTROL, 'a')
|
||||
email.send_keys(Keys.BACKSPACE)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, '#identifierId', self.account[0])
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div/div[2]/div/div[2]/div/div[1]/div/div/button')
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
#password is always empty, no need to empty the textbox first
|
||||
browser_manager.inputText(self.driver, By.XPATH, '//*[@id="password"]/div[1]/div/div[1]/input', self.account[1])
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div/div[2]/div/div[2]/div/div[1]/div/div/button')
|
||||
|
||||
# Login Done: Accept the EULA
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="accept"]')
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
# Now we are in GCP. We need to accept some stuff (country, terms of use)
|
||||
# The form accepts keyboard input and anticipates it proposing a country. Make up a random string, send it. It will be out country
|
||||
|
||||
# Select country button
|
||||
#there's no country starting with an 'x'
|
||||
alphabet = 'abcdefghijklmnopqrstuwyz'
|
||||
letters = 3
|
||||
country = ""
|
||||
for i in range(0, letters):
|
||||
country += alphabet[random.randint(0, len(alphabet)-1)]
|
||||
#country += '\n'
|
||||
# print(country)
|
||||
|
||||
browser_manager.inputText(self.driver, By.XPATH, '/html/body/div[3]/div[3]/div/mat-dialog-container/xap-deferred-loader-outlet/ng-component/mat-dialog-content/form/cfc-tos-checkboxes/form/div[1]/cfc-loader/div/mat-form-field/div/div[1]/div[3]/ace-select', country, interval=0, after_delay=2)
|
||||
|
||||
#accept terms of use
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[3]/div[3]/div/mat-dialog-container/xap-deferred-loader-outlet/ng-component/mat-dialog-content/form/cfc-tos-checkboxes/form/div[2]/mat-checkbox/label/span[1]')
|
||||
#finally agree
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[3]/div[3]/div/mat-dialog-container/xap-deferred-loader-outlet/ng-component/mat-dialog-actions/ace-progress-button/div[1]/button')
|
||||
#wait for the page to load
|
||||
time.sleep(20)
|
||||
|
||||
# Now open GCS, clicking the button
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="pcc-devshell-container"]/xap-deferred-loader-outlet/pcc-platform-bar-devshell-button/pcc-platform-bar-button/button')
|
||||
time.sleep(10)
|
||||
|
||||
# Sometimes another accept pops out
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[3]/div[3]/div/mat-dialog-container/xap-deferred-loader-outlet/ng-component/mat-dialog-content/form/cfc-tos-checkboxes/form/div[1]/cfc-loader/div/mat-form-field/div/div[1]/div[3]/ace-select')
|
||||
|
||||
# Sometimes there's even an accept button inside the iframe, where the command area should be
|
||||
self.switch_to_shell_iframe()
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div/div[2]/div/mat-dialog-container/dialog-overlay/div[5]/modal-action/button')
|
||||
|
||||
#wait for the machine to boot
|
||||
time.sleep(20)
|
||||
|
||||
self.started = True
|
||||
# Done. This is ours to command now!
|
||||
|
||||
# reboot to get a fresh machine (we are in ephimeral mode)
|
||||
def reboot(self):
|
||||
print("[GCShell] Going down for reboot NOW!")
|
||||
self.switch_to_shell_iframe()
|
||||
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/cloud-shell-root/div/docked/stacked-layout/div[1]/devshell/devshell-toolbar/csh-header/mat-toolbar/csh-header-buttons/more-button/button')
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[3]/div[2]/div/div/div/button[1]')
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[3]/div[2]/div/mat-dialog-container/dialog-overlay/div[5]/modal-action[1]/button')
|
||||
|
||||
rebooted = False
|
||||
t = 0
|
||||
#wait for it to actually reboot
|
||||
while not rebooted:
|
||||
time.sleep(5)
|
||||
t += 5
|
||||
try:
|
||||
self.get_text_area()
|
||||
rebooted = True
|
||||
except:
|
||||
print("[GCShell]{} seconds passed, VM still hasn't fully rebooted".format(t))
|
||||
|
||||
print("[GCShell] VM fully rebooted")
|
||||
|
||||
def toggle_ephimeral(self):
|
||||
print("[GCShell] Toggling ephimeral mode...")
|
||||
#open menu
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/cloud-shell-root/div/docked/stacked-layout/div[1]/devshell/devshell-toolbar/csh-header/mat-toolbar/csh-header-buttons/more-button/button')
|
||||
#click ephimeral mode option
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="mat-menu-panel-10"]/div/button[6]')
|
||||
|
||||
#this only appears when enabling. Click to enable
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="mat-slide-toggle-1"]')
|
||||
|
||||
#This confirms enabling or disabling, depending if it's already enabled or not
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '//*[@id="mat-dialog-0"]/dialog-overlay/div[5]/modal-action[1]/button')
|
||||
print("[GCShell] Toggled ephimeral mode...")
|
||||
|
||||
|
||||
# select the text area. This is where we can input commands
|
||||
# (assumes the window is still open)
|
||||
def switch_to_shell_iframe(self):
|
||||
#sometimes we're still in the iframe, so switching to main content is needed
|
||||
self.driver.switch_to.default_content()
|
||||
|
||||
#switch to shell iframe
|
||||
frame = self.driver.find_element_by_xpath('/html/body/pan-shell/pcc-shell/cfc-panel-container/div/div/cfc-panel[1]/div[1]/div/div[3]/cfc-panel-container/div/div/cfc-panel/div/div/cfc-panel-container/div/div/cfc-panel[2]/div/div[1]/pcc-cloud-shell-wrapper/xap-deferred-loader-outlet/pcc-cloud-shell/div/div[2]/iframe')
|
||||
self.driver.switch_to.frame(frame)
|
||||
return frame
|
||||
|
||||
def get_text_area(self):
|
||||
if self.started:
|
||||
self.switch_to_shell_iframe()
|
||||
return self.driver.find_element_by_xpath(Shell.TEXT_AREA_XPATH)
|
||||
|
||||
return False
|
||||
|
||||
def execute_command(self, command, stop_current=False):
|
||||
text_area = self.get_text_area()
|
||||
|
||||
if text_area is False:
|
||||
print("[GCShell] No account were available, can't execute cmd!")
|
||||
return
|
||||
|
||||
if stop_current:
|
||||
text_area.send_keys(Keys.CONTROL, 'c')
|
||||
time.sleep(5) #wait in case it takes a bit of time to stop
|
||||
|
||||
browser_manager.inputText_no_find(self.driver, text_area, command + '\n', interval=0)
|
||||
|
||||
def execute_python_custom_script(self, gist):
|
||||
gist.execute(self)
|
||||
|
||||
# we use our own "language" to add information to the script (e.g. how much to wait before a command is complete)
|
||||
def execute_script_from_local(self, gist_path):
|
||||
print("[GCShell] Executing gist from", gist_path)
|
||||
with open(gist_path, "r") as file:
|
||||
for line in file.readlines():
|
||||
line = line.strip().rstrip()
|
||||
print("[GCShell] Executing specific line:", line)
|
||||
|
||||
# that's a comment, ignore by skipping to the next line
|
||||
if( line.startswith("#") ):
|
||||
print("[GCShell] Line was a comment, skipping")
|
||||
else:
|
||||
i1 = line.find('.')
|
||||
i2 = line.find('.',1)
|
||||
sleeptime = int(line[i1+1:i2])
|
||||
|
||||
command = line[i2+1:]
|
||||
|
||||
print("[GCShell] Executing command:", line, "for", sleeptime, "seconds")
|
||||
|
||||
self.execute_command(command, False)
|
||||
time.sleep(sleeptime)
|
||||
|
||||
# take a raw text file from the url (github, pastebin possibly), run it using curl
|
||||
def execute_raw_gist(self, gist_url, arguments):
|
||||
arguments_str = ""
|
||||
for a in arguments:
|
||||
arguments_str += " "
|
||||
arguments_str += a
|
||||
command = gist_url + " " + arguments_str
|
||||
|
||||
self.execute_command(command, stop_current=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -25,7 +25,7 @@ def waitForElement(browser, by, selector, timeout=5, after_delay=0):
|
|||
except:
|
||||
return False
|
||||
|
||||
def clickButton(browser, by, selector, timeout=5, after_delay=1.5):
|
||||
def clickButton(browser, by, selector, timeout=7, after_delay=2):
|
||||
try:
|
||||
WebDriverWait(browser, timeout).until(EC.element_to_be_clickable((by, selector))).click()
|
||||
|
||||
|
@ -33,7 +33,7 @@ def clickButton(browser, by, selector, timeout=5, after_delay=1.5):
|
|||
except:
|
||||
return False
|
||||
|
||||
def inputText(browser, by, selector, text, timeout=5, interval=0.2, after_delay=0):
|
||||
def inputText(browser, by, selector, text, timeout=5, interval=0.2, after_delay=2):
|
||||
try:
|
||||
element = WebDriverWait(browser, timeout).until(EC.element_to_be_clickable((by, selector)))
|
||||
for i in text:
|
||||
|
@ -44,6 +44,16 @@ def inputText(browser, by, selector, text, timeout=5, interval=0.2, after_delay=
|
|||
except:
|
||||
return False
|
||||
|
||||
def inputText_no_find(browser, element, text, timeout=5, interval=0.2, after_delay=2):
|
||||
try:
|
||||
for i in text:
|
||||
element.send_keys(i)
|
||||
time.sleep(interval)
|
||||
|
||||
time.sleep(after_delay)
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
# A lifesaver: https://stackoverflow.com/questions/36141681/does-anybody-know-how-to-identify-shadow-dom-web-elements-using-selenium-webdriv
|
||||
def select_shadow_element_by_css_selector(browser, selector):
|
||||
|
@ -71,7 +81,7 @@ def start_browser(headless=False):
|
|||
# #Set Chromedriver Options
|
||||
opts = webdriver.ChromeOptions()
|
||||
if headless is True:
|
||||
options.headless = True
|
||||
opts.headless = True
|
||||
|
||||
opts.add_argument('--enable-javascript') #enabling javascript is needed in order to not get recognized as a bot
|
||||
user_agent = random_user_agent()
|
||||
|
@ -82,7 +92,7 @@ def start_browser(headless=False):
|
|||
print("[Browser_Manager] Starting new browser. Proxy: {} | UserAgent {}".format(PROXY, user_agent))
|
||||
|
||||
#Fire up chromedriver
|
||||
chromedriver = webdriver.Chrome(options=opts)
|
||||
chromedriver = webdriver.Chrome(executable_path='./chromedriver', options=opts)
|
||||
|
||||
time.sleep(3)
|
||||
return chromedriver
|
||||
|
|
|
@ -3,4 +3,8 @@ from qwiklabs import account_list
|
|||
PROXY = False
|
||||
ql_list = account_list.QL_AccountList('/home/emamaker/Documents/Projects/GColabAutomator/GColabAutomator-v2/src/qwiklabs_available_accounts.txt')
|
||||
TEST_ACCOUNT = False
|
||||
# TEST_ACCOUNT = ('student-03-8b9257f4e203@qwiklabs.net', '925ZwgHmPf')
|
||||
# email, password, gcloud shell link
|
||||
# TEST_ACCOUNT = ('student-01-474fc01a4ea5@qwiklabs.net', 'PkR9NJR4ms5D', 'https://accounts.google.com/AddSession?service=accountsettings&sarp=1&continue=https%3A%2F%2Fconsole.cloud.google.com%2Fhome%2Fdashboard%3Fproject%3Dqwiklabs-gcp-03-676b378e29e0#Email=student-01-474fc01a4ea5@qwiklabs.net')
|
||||
|
||||
TEST_QWIKLABS_ACCOUNT = False
|
||||
# TEST_QWIKLABS_ACCOUNT = "i3z8qtab@xojxe.com"
|
Binary file not shown.
|
@ -1,55 +0,0 @@
|
|||
from ngrok import ngrok
|
||||
from colab import colab
|
||||
from colab.gists import Gists
|
||||
from utils import global_vars
|
||||
from qwiklabs import get_account
|
||||
|
||||
import time
|
||||
|
||||
class Proxy():
|
||||
def __init__(self):
|
||||
Proxy.PROXY_COMBOS = [
|
||||
( ('giangillo.rossi1@gmail.com', 'emamaker02'), Gists.PROXY1.value),
|
||||
( ('giangillo.rossi2@gmail.com', 'emamaker02'), Gists.PROXY2.value)
|
||||
]
|
||||
Proxy.TIME_ELAPSED = 2400 #time that has to pass before changing account combo, in seconds
|
||||
|
||||
self.account_combo_index = 0
|
||||
self.account_combo = Proxy.PROXY_COMBOS[self.account_combo_index]
|
||||
self.last_time = time.time()
|
||||
|
||||
print("[Proxy] First time running, starting a new proxy session")
|
||||
self.start_new_proxy_session()
|
||||
|
||||
def request_new_proxy(self):
|
||||
print("[PROXY] A new proxy has been requested")
|
||||
# then it's time to close the current gist+ngrok account and open another one
|
||||
if time.time() - self.last_time > Proxy.TIME_ELAPSED:
|
||||
print("[PROXY] Time for current account {} has expired".format(self.account_combo[0]))
|
||||
self.ngrok.close_browser()
|
||||
self.colab.quit()
|
||||
|
||||
# it's not needed to manually close the colab session, just leave it decay on it's own
|
||||
# but it's needed to close ngrok
|
||||
self.account_combo_index = (self.account_combo_index+1) % len(Proxy.PROXY_COMBOS)
|
||||
self.account_combo = Proxy.PROXY_COMBOS[self.account_combo_index]
|
||||
print("[PROXY] Switching to new account {}".format(self.account_combo[1]))
|
||||
|
||||
self.start_new_proxy_session()
|
||||
else:
|
||||
print("[PROXY] Refreshing existing proxy to get new ip")
|
||||
#just refresh
|
||||
self.colab.refresh_event.set()
|
||||
time.sleep(90)
|
||||
|
||||
global_vars.PROXY = self.ngrok.get_proxy_ip()
|
||||
print("[PROXY] Done! New proxy is: {} ".format(global_vars.PROXY))
|
||||
|
||||
def start_new_proxy_session(self):
|
||||
self.colab = colab.ColabGist(self.account_combo[1], get_account.get_google_account())
|
||||
self.colab.run() #this launches a new thread
|
||||
time.sleep(90)
|
||||
|
||||
self.ngrok = ngrok.Ngrok( self.account_combo[0] )
|
||||
|
||||
|
Loading…
Reference in New Issue