Posts Tagged ‘Shell’

Donnerstag, 14. Oktober 2021

OpenInTerminal meldet „Waiting…“

Vor einiger Zeit habe ich hier im Artikel Öffne Terminal mit dem aktuellen macOS Finder-Pfad über die macOS Finder-Erweiterung OpenInTerminal geschrieben.

Folgendes Problem tritt dabei periodisch auf: Klickt man auf das Finder-Icon, heisst es im aufklappenden Dialog lapidar „Waiting…“

Die Lösung, eine Antwort auf meinen Bug-Report: Option-Klick auf Finder und Relaunch anwählen.

Tags: , , , , , , ,
Labels: Apple, IT

Keine Kommentare | neuen Kommentar verfassen

Samstag, 11. September 2021

Notfallmässig eine Reverse Shell auf einem Linux-System aufbauen

Heute habe ich auf einem meiner Linux-Systems nach langer Zeit wieder einmal apt-get upgrade durchgeführt. Eines der wenigen System in meinem Fuhrpark, auf welchem noch Debian Stretch läuft.

Per SSH aus der Ferne eingeloggt, winkte ich die Meldungen durch — und musste offenbar übersehen haben, dass apt-get vor hatte, eine ganze Ladung kritischer Dienste zu entfernen. Unter anderem auch das Paket openssh-server. Nachdem das Update durch war, logge ich mich mittels Druck auf Ctrl-D aus. Und sah erst dann monits Warnmeldungen in meiner INBOX, dass auf TCP 22 kein SSH Daemon mehr lauschte. Doch dann war es bereits zu spät — ich hatte die letzte „Brücke“ zum Server soeben mit Ctrl-D in die Wüste geschickt.

Alle meine Systeme sysloggen via Site-to-Site-VPN auf einen zentralen ELK-Server. In Kibana dann die Hiobs-Botschaft:

sshd[10954]: error: rexec of /usr/sbin/sshd failed: No such file or directory

Sowie

sshd[10954]: fatal: chroot("/run/sshd"): No such file or directory [preauth]

Da der Server 13 Kilometer weit weg in der Wohnung eines Bekannten steht, hatte ich den Salat. Ich wollte eine Autofahrt vor Ort unbedingt vermeiden.

Glücklicherweise war der Bekannte gerade zu Hause und erklärte sich bereit, mir in diesem Notfall als manuelles, menschliches KVM zu helfen.

Als erstes leitete ich ihn via iMessage an, sich in den Laptop einzuloggen. Das klappte. Anschliessend wollte ich ihn zwei Befehle ausführen lassen:

$ sudo su -
# apt-get install openssh-server

Doch bereits der erste Befehl produzierte eine Fehlermeldung:

-bash: sudo: command not found

Himmelheiland, war sogar sudo deinstalliert worden?!

Immerhin su funktionierte, aber ich wollte dem Helfer nicht zumuten, das 32-stellige, zufällig generierte Passwort mühsam von iMessage auf die Laptop-Tastatur abzutippen.

Ich wollte schon aufgeben, da kam mir eine Blitzidee: Ich benötigte eine Reverse Shell unter dem nicht-privilegierten Benutzer, und dann könnte ich selber das Problem autonom lösen.

Das VPN war wegen eines Neustarts zusammengebrochen (genau dieser Server ist der entfernte Endpunkt), aber glücklicherweise hatte ich ein zweites System im entfernten Netzwerk, auf welchem ein SSH-Server mit einer öffentlichen IP lauscht. Ich war also zusätzlich parallel auf diesem zweiten Server eingeloggt. Zu diesem benachbarten Server sollte das Reverse Shell aufgebaut werden.

Eine Google-Suche lieferte folgende wichtigen Seiten zu Tage: Bind Shells and Reverse Shells with netcat, Hacking with Netcat part 2: Bind and reverse shells, Complete guide to Reverse Shells sowie Su: must be run from a terminal.

Der Bekannte gab nun auf dem zerschossenen Linux folgenden Befehl ein:

$ nc -lvp 12345 -e /bin/bash

Auf dem Schwester-Server gab ich dann ein:

$ nc -nv 10.1.2.3 12345

Wobei 10.1.2.3 die IP des zerschossenen Systems war.

Die Verbindung war zustande gekommen, aber ich sah keine richtige Shell. Befehle konnte ich eingeben (bspw. ls -l), und das Resultat wurde auf meinem Bildschirm angezeigt.

Problem: Als ich su ausführen wollte, wurde das mit der Fehlermeldung su : must be run from a terminal verhindert.

Zuerst überlegte ich mir den Weg über Scripts: How to pass the password to su/sudo/ssh without overriding the TTY? und su pass password to script.

Doch nach Konsultation von Getting around „su : must be run from a terminal“ schaffte ich eine wirklich vollständig brauchbare Shell nach Eingabe des folgenden Befehls:

python -c 'import pty; pty.spawn("/bin/bash")'

Einschub: Unter Stretch funktioniert das, unter Bullseye sollte man nun folgenden Befehle verwenden:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Hurra, ich hatte eine Shell! Aber Achtung: Ein fahrlässiges, aus Gewohnheit gedrücktes Ctrl-C killt die netcat-Verbindung, nicht das laufende Programm.

Andere Varianten unter Zuhilfenahme anderer potentieller Bordmittel wie Perl, PHP etc. sind in Spawning a TTY Shell dokumentiert.

Nun also wollte ich su anwenden, realisierte erst dann aber, dass das in meiner Passwort-Datenbank hinterlegte 32 Zeichen lange Passwort nicht korrekt war. Ich hatte bei der Installation vergessen, dass viel zu einfache dummy-Passwort anzupassen … Als ich dieses eingegeben hatte, landete ich in einer root-Shell.

Doch oha: openssh-server liess sich wegen Abhängigkeitsproblemen nicht installieren.

Was nun? Ich musste irgendwie einen persistenten Server als ersten Brückenkopf einrichten, der beim versehentlichen Betätigen von Ctrl-C auf meiner Seite weiter lief und erneute Verbindungsversuche zuliess.

Ich überlegte mir, ein PHP-Backdoor-Script zu installieren (php-reverse-shell, Quellcode), doch wie konnte ich dieses so einrichten, dass es permanent oder periodisch automatisch Verbindungsversuche unternehmen würde?

Nach etwas tüfteln dann die viel einfachere Lösung:

# apt-get install telnetd

Besser wäre eigentlich gewesen:

# apt-get install telnetd-ssl

Via: How do I turn on telnet service on for a Linux / FreeBSD system?

Und nun hatte ich wieder einen „sauberen“ Zugang zum Server.

Die nachfolgenden Stunden verbrachte ich damit, den Server von Stretch auf Buster und dann auf Bullseye zu lüpfen und eine Ladung Pakete zu installieren, welche apt heimtückisch entfernt hatte: OpenSSH, sudo, cron, OpenVPN, Samba, monit.

Tags: , , , , , , , ,
Labels: Uncategorized

Keine Kommentare | neuen Kommentar verfassen

Montag, 15. März 2021

Öffne Terminal mit dem aktuellen macOS Finder-Pfad

Sehr oft kommt es vor, dass ich im macOS Finder herumgurke, um dann auf die Kommandozeile zu wechseln und im Finder angezeigten Ordner Manipulationen vornehmen möchte.

Auf meinem iMac mit macOS High Sierra (10.13) verwende ich dafür seit Jahren go2shell, welche im Finder-Fenster in der Button-Zeile ein zusätzliches Icon anzeigt.

Unter macOS Big Sure (11.0) habe ich mir für dieselbe Aufgabe soeben OpenInTerminal installiert. Dieses gefällt mir optisch und funktionell noch ein mü besser.

Tags: , , , , , , ,
Labels: Apple

1 Kommentar | neuen Kommentar verfassen

Montag, 13. April 2020

Bildschirm eines Debian-Servers nach Inaktivität ausschalten

Ich habe hier bereits erwähnt, dass gebrauchte ThinkPads mit Debian die Linux-Server meiner Wahl sind.

Gestern habe ich meinen ELK Log-Server von einem Lenovo ThinkPad X201 auf ein Lenovo ThinkPad T440p migriert (und habe gleichzeitig von einem unsäglichen Docker-Gefrickel auf native Pakete gewechselt).

Eines der bis eben ungelösten Probleme war, dass sich der Bildschirm des ThinkPads nach einer Inaktivitäts-Zeitlimite nicht automatisch ausschaltete. Das habe ich nun folgendermassen gelöst:

/etc/default/grub

...
GRUB_CMDLINE_LINUX_DEFAULT="consoleblank=60"
...

Der Wert 60 drückt die Inaktivitätszeit in Sekunden aus.

Danach muss noch GRUB aktualisiert werden, und dann wird’s ab dem nächsten Neustart nach 60 Sekunden dunkel:

# update-grub

Tags: , , , , , , , , , , , , , , ,
Labels: IT, Linux

Keine Kommentare | neuen Kommentar verfassen

Freitag, 30. März 2018

Zwei Tipps zu dd unter macOS

dd verwendet man unter macOS wahrscheinlich normalerweise dann, wenn man Images (1:1 Abbilder) von portablen Datenträgern machen möchte oder diese auf portable Datenträger zurückspielen möchte.

Folgende zwei Dinge sind dabei wichtig:

Geschwindigkeit

Unter macOS sollte man Datenträger immer in der Schreibweise /dev/rdisk1s1 ansprechen und nie als /dev/disk1s1. Damit können Images messbar schneller geschrieben werden, in der Regel mit Faktor 3.

Auch die Blocksize (definiert mit dem Parameter bs) sollte hoch angesetzt werden — nachfolgend auf 2 Megabytes:

# dd if=/tmp/image.img of=/dev/rdisk1 bs=2m

Zwischenstand

Leider gibt dd im normalen Gebrauch keinen Fortschritt aus. Erst sobald der Kopiervorgang abgeschlossen ist, erhält man eine Statistik über die Anzahl der kopierten Blöcke sowie über den Datendurchsatz.

Betätigt man aber bei einem in der Shell laufenden dd-Kopierprozess die Tastenkombination Ctrl-T gibt dd den Zwischenstand des Lese- oder Schreibvorgangs aus, ohne den Kopiervorgang zu unterbrechen.

Tags: , , , , , ,
Labels: Linux

Keine Kommentare | neuen Kommentar verfassen

Samstag, 29. März 2014

Die Datei mach_kernel im Finder ausblenden

Aus einem mir unerklärlichen Grund wird bei mir die Datei mach_kernel, welche den Mac OS X Kernel enthält, im Finder angezeigt:

mach_kernel

Mit folgendem Shell-Befehl wird die Datei im Finder inskünftig ausgeblendet:

# chflags hidden /mach_kernel

Via: mach_kernel now visible

Tags: , , , ,
Labels: Apple

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 25. September 2013

Das Mac OS X Terminal mit dem aktuellen Finder-Pfad öffnen

Wer sich fliessend zwischen den zwei Welten — dem OS X GUI und dem Unix-Terminal — bewegt, wird die Minimalapplikation Go2Shell äusserst nützlich finden. Nachdem man sie als Button in die Finder Button-Leiste gezogen hat, kann man auf Knopfdruck das Mac OS X Terminal (Unix-Shell) öffnen und findet sich im selben Ordner wieder, welchen man gerade im Finder sieht.

Die umgekehrte Variante sei hier selbstverständlich auch noch am Rande erwähnt:

$ open .

öffnet ein Finder-Fenster mit dem Verzeichnis, in welchem sich der Shell-Benutzer gerade befindet.

Tags: , , , , , ,
Labels: Apple

Keine Kommentare | neuen Kommentar verfassen

Sonntag, 3. März 2013

Arte-Videos herunterladen

Vor ein paar Tagen hat arte die Dokumentation Staatsgeheimnis Bankenrettung veröffentlicht. Man kann die Reportage unter dem genannten Link live anschauen.

Wer sich die Dokumentation aber auf die lokale Festplatte laden möchte, um sie danach beispielsweise mit Air Video Server und Air Video.app unter iOS auf den Apple TV zu streamen, muss auf der Kommandozeile aktiv werden:

  1. # port install rtmpdump
  2. Download von Florian Crouzats Shell-Script mittels
    $ wget http://files.floriancrouzat.net/ripArte-v0.9.sh
  3. $ chmod 755 ripArte-v0.9.sh
  4. $ ripArte-v0.9.sh "http://videos.arte.tv/de/videos/staatsgeheimnis-bankenrettung--7340782.html"
  5. Auswahl des vierten RTMP Streams (German High-definition RTMP, rtmp://artestras.fcod.llnwd.net/a3903/o35/mp4:geo/videothek/ALL/arteprod/A7_SGT_ENC_04_048116-000-A_PG_HQ_DE?h=24fceb3242c5803955ac67b8b44ce499)

Und das Resultat sieht folgendermassen aus:

...
340386.493 kB / 3129.09 sec (99.9%)
Download complete

Tags: , , , , ,
Labels: IT, Medien

3 Kommentare | neuen Kommentar verfassen

Donnerstag, 14. Februar 2013

Data Mining mit Ubuntu, MySQL, PHP und Python

Beruflich setze ich mich derzeit mit der Analyse von Inhalten von Web-Sites auseinander. Nachfolgend habe ich einige Erfahrungen aufgelistet, welche ich dabei gemacht habe.

Wir verarbeiten in diesem Projekt Web-Sites, welche wir mit entsprechenden Tools aus dem Web auf den lokalen Rechner gespiegelt haben. Die Web-Site Assets liegen im Dateisystem. Zur Weiterverarbeitung der Daten wurden die HTML-, JS-, CSS- und XML-Rohdaten in eine MySQL-Tabelle gespitzt (12GB) und anschliessend mit Meta-Daten ergänzt.

Ich persönlich bin nicht sicher, ob die Ablage von HTML-Code in der Datenbank die sinnvollste und performanteste Lösung ist, aber dies war nunmal der Stand des Projektes als ich dazu gestossen bin — und daran liess sich nichts mehr rütteln.

Da wir unter anderem auch Volltextsuchen auf die Grunddaten anwenden, hätte ich mir Apache Solr genauer angeschaut und darauf mittels PHP und JSON zugegriffen.

Kommandozeile

Da der Ubuntu-Server aus mir unerfindlichen Gründen mit LAMPP aufgesetzt wurde, befinden sich die Binaries wie php nicht in den Standardpfaden und werden von bash ohne absolute Pfadangabe nicht gefunden. Da man den Interpreter täglich dutzende, wenn nicht gar hunderte Male aufruft, ist es ratsam, das Verzeichnis sofort in die $PATH-Variable des Shells aufzunehmen.

Hier findet man sich in der Shell Startup File Hell wieder. Je nachdem, ob man lokal arbeitet oder sich per SSH einloggt muss der Befehl an einem anderen Ort stehen. Schlussendlich habe ich die nachfolgende Zeile …

...
PATH="$PATH:/opt/lampp/bin"

… ans Ende folgender zwei Dateien angefügt:

  • ~/.profile
  • ~/.bashrc

Datenbank (MySQL)

Cache aktivieren

Wir führen PHP-Scripts über die Linux-Shell aus. Gerade bei der Entwicklung neuer Scripts sind verschiedene Anläufe nötig, bis alle Bugs und nicht beabsichtigten Funktionen ausgemerzt sind. Da wir oftmals an einem Datenset von 60’000+ Seiten arbeiten, ist es unabdingbar, dass wir eine Cacheing-Lösung anwenden, um Datenbankabfragen im Kurzspeicher zwischenzulagern.

Folgende Parameter in my.cnf aktivieren den in MySQL vorhandenen Cache:

...
[mysqld]
...
query_cache_type = 1
query_cache_size = 512M
query_cache_limit = 32M

Der Geschwindigkeitsgewinn ist immens — nachdem ein Script mit SELECT-Statements zum ersten Mal ausgeführt wurde und dafür mehrere Minuten benötigte, rauscht es in den folgenden Malen innert Sekunden durch.

Programmierung (PHP und Python)

Helper-Funktionen und -Klassen

Wie aus der Web-Entwicklung gewohnt sollte man bei jedem der mit der Zeit entstehenden Scripts zu Beginn Klassen, allgemeine Einstellungen und Funktionen einbinden.

In der Funktionsbibliothek setze ich beispielsweise folgende wichtigen Parameter in globaler Form:

...
error_reporting(E_ALL);
date_default_timezone_set('Europe/Zurich');

Auch die Datenbankverbindung wird mittels meiner MySQL-Klasse hier erstellt und an alle Scripts weitergegeben, welche die Library einbinden.

Aufbau der Scripts

Als ich zum Projekt stiess herrschten Spaghetti-Code in teils monolithischen Scripts vor. Ich habe meine eigenen Scripts dann aber so entwickelt, dass sie dem Unix-Gedanken folgend normalerweise nur eine bestimmte Funktion ausführen, diese dafür aber ausgezeichnet und in sich abgeschlossen. So steht im Normalfall in jedem Script, welches Daten manipuliert, zuoberst ein SQL-Query, welches die zu verändernden Datenbankdaten auswählt.

Bei der Entwicklung wählt man hierbei ein Query, das einen oder nur wenige Werte aus der Datenbank ausliest und verarbeitet — in dieser Phase hat man keine Zeit, möglicherweise fehlerhafte Manipulationen an 60’000+ Seiten durchzuführen.

HTML mit regulären Ausdrücken parsen?

Nein, besonders nicht dann, wenn man konkret an Eigenschaften des SGML-Markup interessiert ist (bspw. Wohin zeigen Links?). Hierzu verwendet man die in PHP standardmässig enthaltene DOMDocument-Bibliothek.

Wichtig ist, dass man bei der Verwendung von E_ALL die loadHTML()-Funktion mittels @ stummschaltet, weil sonst das Terminal mit Warnungen über fehlerhaften HTML-Code (leider an der Tagesordnung) vollgespamt wird:

...
$dom = new DOMDocument();
@$dom->loadHTML($html);
$elements = $dom->getElementsByTagName('a');

HTML manipulieren — und Fallstricke

Für jede HTML-Seite erstellen wir eine Nur-Text-Version. Hierzu verwenden wir html2text.py von Aaron Swartz selig. Bevor das HTML aber umgewandelt wird, säubern wir die HTML-Datei auf eigene Faust. Auch hier kommt DOMDocument zum Zug.

Wir suchen dabei zuerst einmal Elemente jeglicher Art, deren ID oder Klasse den String nav, menu und breadcrumb enthält. Die Navigation interessiert uns nämlich nicht, und noch schlimmer: Sie verfälscht teilweise die Resultate, weil in der Navigation gesuchte Begriffe vorkommen.

Hierzu lade ich den HTML-Code wieder in eine DOMDocument und iteriere danach über alle Elemente auf der Suche nach den besagten IDs und Klassennamen:

function cleanNavMenuElements($html = null) {
		$dom = new DOMDocument();
		@$dom->loadHTML($html);
		
		$changesMade = false;
		
		$elements = $dom->getElementsByTagName('*');
		foreach($elements as $element) {
			if(preg_match('/^(html|body)$/',$element->nodeName)) {
				// Otherwise we might delete the whole DOM!
				continue;
			}
			
	        if($element->hasAttribute('class') && preg_match('/(nav|menu|breadcrumb)/i',$element->getAttribute('class')) > 0) {
				status('Found element with class ' . $element->getAttribute('class'));
				$element->parentNode->removeChild($element);
				
				$changesMade = true;
				
				// Don't go further if we removed this node already
				continue;
			}
			
			if($element->hasAttribute('id') && preg_match('/(nav|menu|breadcrumb)/i',$element->getAttribute('id')) > 0) {
				status('Found element with id ' . $element->getAttribute('id'));
				$element->parentNode->removeChild($element);
				
				$changesMade = true;
			}
	    }
		
		if(!$changesMade) {
			return $html;
		}
		
		return $dom->saveHTML();
	}

Ein Problem manifestiert sich bei der Manipulation aber: Jegliche Anpassungen erfolgen live, was verwirrende Folgen für Schleifen haben kann.

Da die Suche nach obigen ID- und Klassennamen nicht alle Navigationselemente eliminiert, suche ich in einem zweiten Anlauf Tabellen und Listen, deren Elemente ausschliesslich Links enthalten. Dies ist ein guter Indikator, ein Navigationsblock gefunden zu haben.

Hier ist das Problem des sich bei jeder Iteration veränderndem DOM aber sehr ausgeprägt. Wenn ich deshalb durch td-Elemente und li-Elemente iteriere, verwende ich nicht foreach() sondern eine for()-Schleife, deren Counter $i ich immer dann zurücksetze, wenn ich ein Element entferne. Ansonsten wird aus Erfahrung in der Folge eines (oder mehrere Elemente) übersprungen. Damit dies klappt, arbeite ich den DOM Tabellen- respektive Listenweise ab:

$containers = $dom->getElementsByTagName($containerTag);
	
foreach($containers as $container) {
	$items = $container->getElementsByTagName($itemTag);
	
	for($i = 0; $i < $items->length; $i++) {
		$item = $items->item($i);
		
		if($item === null) {
			continue;
		}
		
		$otherTagsPresent = false;
		foreach($item->childNodes as $child) {
			$tag = $child->nodeName;

			if($tag == '#text') {
				$text = trim($child->nodeValue);
				$len = strlen($text);
				if($len < 1) {
					//#text is empty, thus not relevant
					continue;
				}
			}

			if($tag != 'a') {
				$otherTagsPresent = true;
				continue;
			}
		}

		if(!$otherTagsPresent) {
			$item->parentNode->removeChild($item);
			$i = $i-1;
		}
	}

Weiterverarbeitung der Daten durch Nicht-IT-Profis

Zur Weiterverarbeitung der Auswertungen durch andere, in IT nicht versierte Mitarbeiter habe ich eine Funktion geschrieben, welche eine Pfadangabe sowie CSV-Daten als Argumente übertragen erhält. Die Datei wird geschrieben und gleich anschliessend mittels eines kleinen Python-Scripts (Stichwort: openpyxl) in das bei uns hauptsächlich verwendete XLSX-Format konvertiert.

Tags: , , , , , , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Samstag, 24. November 2012

Text in PDFs greppen

Da haben also die SBB einen Wettbewerb online, welcher die Eingabe von Ticketnummern erfordert. Und gleichzeitig habe ich Quittungen von über SBB Mobile georderte Tickets für Geschäftsreisen auf meinem Computer abgelegt.

Was macht man da? Richtig, man filtert die PDFs nach den geforderten Ticket-Nummern, und zwar so:

pdftotext

Ich gehe davon aus, dass jeder Terminal.app-Hacker macports installiert hat

Man benötigt zuerst einmal das in xpdf enthaltene Tool pdftotext:

# port install xpdf-tools

Shell-Magic

Nachdem das Tool installiert ist, navigiert man in den Ordner, welcher die PDFs enthält und gibt folgenden Befehl ein:

$ for i in *.pdf; do pdftotext "$i"; done;

Die in PDFs enthaltenen Textzeichen werden extrahiert und automatisch in eine Textdatei mit Endung .txt gespeichert, welche denselben Basename trägt wie die PDF-Datei.

Nun kann ich problemlos greppen:

$ cat *.txt | grep "OT"

… und schon erhalte ich eine schöne Liste in der Form

OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000

Tags: , , , , , , ,
Labels: IT

1 Kommentar | neuen Kommentar verfassen