<![CDATA[ein Blog]]> / /static/favicon.png ein Blog / htmlengine 2.0 Sun, 21 Mar 2021 14:17:27 +0100 60 L2TP with systemd-networkd /systemd-networkd_L2TP/ systemd-networkd_L2TP Sun, 23 Feb 2020 15:41:25 +0100 systemd-networkd 242 supports L2TP. Because Documentation is sparse i had to figure it out myself. These are my findings:

this is l2tp.netdev containing the L2TP tunnel and session configuration (according to the documentation):

[NetDev]
Name=myl2tp
Kind=l2tp

[L2TP]
TunnelId=100
PeerTunnelId=101
#Local=10.0.0.1 # not required. systemd-networkd can autodetect the address from eth0 (see below)
Remote=10.1.0.1
EncapsulationType=udp
UDPSourcePort=6000
UDPDestinationPort=6001 # there is a typo (https://github.com/systemd/systemd/pull/14892) in the official documentation. it says "DestinationPort" there.

[L2TPSession]
Name=l2tpsess
SessionId=10
PeerSessionId=11

this is l2tp.network containing the network configuration for the L2TP tunnel. i want it connected to a bridge. you can set it up differently of course:

[Match]
Name=l2tpsess

[Network]
DHCP=no
LinkLocalAddressing=no
Bridge=br0

this is eth0.network containing the network configuration for the physical network interface:

[Match]
Name=eth0

[Network]
DHCP=no
Address=10.0.0.1
Netmkas=255.255.255.0
L2TP=myl2tp # i didn't find any documentation about this option. If it is missing, your Tunnel is never set up

if eth0 is set up via DHCP, systemd-networkd will wait for it to be configured before setting up L2TP.

# systemctl restart systemd-networkd

# networkctl
IDX LINK     TYPE     OPERATIONAL SETUP     
  1 lo       loopback carrier     unmanaged 
  2 eth0     ether    routable    configured
  3 br0      bridge   routable    configured
  4 l2tpsess l2tpeth  enslaved    configured

4 links listed.

# ip l2tp show tunnel
Tunnel 100, encap UDP
  From 10.0.0.1 to 10.1.0.1
  Peer tunnel 101
  UDP source / dest ports: 6000/6001
  UDP checksum: disabled

# ip l2tp show session
Session 10 in tunnel 100
  Peer session 11, tunnel 101
  interface name: l2tpsess
  offset 0, peer offset 0
]]>
AGFEO TK-Suite Client auf Linux /agfeo-tk-suite-client-auf-linux/ agfeo-tk-suite-client-auf-linux Wed, 12 Sep 2018 17:40:03 +0200 Falls mal wer den AGFEO Tk-Suite Client auf einem nicht-antiken Linux ans laufen bekommen möchte:

dpkg --add-architecture i386
apt install libqt4-script:i386 libqtwebkit4:i386 libqt4-sql:i386
]]>
netfilter-persistent ebtables /netfilter-persistent_ebtables/ netfilter-persistent_ebtables Sat, 25 Aug 2018 14:26:22 +0200 Ich hab da mal das iptables netfilter-persistent plugin umgebaut für ebtables. Keine Meisterleistung aber es hat relativ lange gedauert bis ich überhaupt auf die Idee gekommen bin, dass netfilter-persistent ja plugins kann.

]]>
Guest-WiFi AirPlay /guest_wifi_airplay/ guest_wifi_airplay Sat, 25 Aug 2018 11:55:03 +0200 Man möchte ja in der heutigen Zeit seinen Gästen WiFi anbieten. Man möchte sie aber nicht unbedingt ins eigene Netzwerk lassen. Da bietet sich ja ein Gast-Netz an.

Die meisten Accesspoints können das inzwischen. Wir haben uns vor einer Weile für die UniFi Accesspoints entschieden. Die kann man im UniFi Controller ganz leicht eine eigene SSID in ein VLAN stecken lassen:

Jetzt hat man aber vielleicht das ein oder andere AirPlay Gerät das man seinen Gästen doch zur verfügung stellen möchte. Und genau das habe ich die letzten Tage zusammengebastelt.

Wenn man einen Linux-Basierten Router hat auf dem man sachen Installieren möchte, lässt sich das etwas leichter lösen aber wir wollten die ganze Magie in einer kleinen VM haben.

Teil 1 ist relativ einfach. Man installiert das Paket avahi-daemon und aktiviert die "Reflector" Option in /etc/avahi/avahi-daemon.conf:

[reflector]
enable-reflector=yes
reflect-ipv=no

reflect-ipv ist standardmäßig aus und so wie ich die Dokumentation verstanden habe, will man das normalerweise auch aus lassen. Das spiegelt sonst Bonjour-Announcements zwischen IPv4 und IPv6 hin und her. Wenn man jetzt ein IPv6-only Netz hat, ist das vielleicht nochmal ne andere sache, aber wenn du das hast, brauchst du vermutlich diese Anleitung nicht ;)

Teil 2 ist etwas fummeliger. Wir müssen natürlich die kommunikation aus dem Gast-Netzwerk zu den AirPlay Geräten erlauben, gleichzeitig soll aber natürlich anderer kram nicht erlaubt sein. Weil wir eigentlich alle Geräte mit DHCP adressieren und sich die Adressen auch mal ändern können, ist es unsinnig dafür IP-Basierte Firewall-Regeln zu verwenden.

Lösung ist das Tool ebtables. Das arbeitet schon auf Layer 2 und kann (besser) mit MAC-Adressen umgehen (als iptables). Damit ebtables funktioniert braucht es allerdings eine Bridge. In unserem aktuellen Setup reicht eine bridge an der nur das Interface in unser Netz hängt. Mehr dazu später.

Wir können jetzt mit ebtables den Traffic der die bridge verlassen möchte und

  • zu einem AirPlay Gerät möchte erlauben (1)
  • aus dem Gast-Netz kommt verbieten (2)

wir möchten ja weiterhin aus unserem netz z. B. per SSH auf die VM kommen.

APDEVICES="b8:27:eb:**:**:** b8:27:eb:**:**:** b8:27:eb:**:**:**"
INTDEV="ens3"
GUESTNET="10.0.6.0/24"

# (1)
for dev in $APDEVICES; do
    ebtables -A OUTPUT -o $INTDEV -d $dev -j ACCEPT
done

#(2)
ebtables -A OUTPUT -o $INTDEV -p IPv4 --ip-src $GUESTNET -j DROP

Jetzt noch etwas iptables Spaß:

INTBR="br0"
GUESTDEV="ens10"

iptables -P INPUT DROP
iptables -P FORWARD DROP

# das übliche
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# Multicast nur von erlaubten geräten zulassen (damit nicht noch die restlichen bonjour-announcements von anderen geräten gespiegelt werden)
# INPUT und nicht FORWARD weil die sachen ja von avahi-daemon empfangen und dann auf dem anderen interface gespiegelt werden
for dev in $APDEVICES; do
    iptables -A INPUT -d 224.0.0.0/8 -i $INTBR -m mac --mac-source $dev -j ACCEPT
done
iptables -A INPUT -d 224.0.0.0/8 -i $INTBR -j DROP

# DHCP und DNS Requests erlauben ist vielleicht eine ganz gute Idee
iptables -A INPUT -i $GUESTDEV -p udp --dport 67:68 --sport 67:68 -j ACCEPT
iptables -A INPUT -i $GUESTDEV -p udp --dport 53 -j ACCEPT
iptables -A INPUT -i $GUESTDEV -d 224.0.0.0/8 -j ACCEPT

# pakete aus dem internen netz sollen ja auch wieder zurück dürfen
iptables -A FORWARD -i $INTBR -o $GUESTDEV -m state --state RELATED,ESTABLISHED -j ACCEPT

# AirPrint
iptables -A FORWARD -i $GUESTDEV -o $INTBR -m tcp -p tcp --dport 631 -j ACCEPT
# AirPlay
iptables -A FORWARD -i $GUESTDEV -o $INTBR -m tcp -p tcp --dport 5000:5100 -j ACCEPT
iptables -A FORWARD -i $GUESTDEV -o $INTBR -m udp -p udp --dport 6000:6100 -j ACCEPT
iptables -A FORWARD -i $GUESTDEV -o $INTBR -m tcp -p tcp --dport 7000:7100 -j ACCEPT
# AppleTV Status Magic
iptables -A FORWARD -i $GUESTDEV -o $INTBR -m tcp -p tcp --dport 49152:65535 -j ACCEPT

jetzt noch eine Route ins Gast-netz auf dem Standard-Gateway hinterlegen und fertig:

route add -net $GUESTNET gw 10.0.0.42

und das wars dann eigentlich auch schon. Ich möchte nämlich eigentlich die pakete in beide Richtungen filtern. Das geht aber momentan noch nicht weil die Quell-MAC nicht die der AirPlay Geräte sind sondern natürlich die des Routers ist.

Dafür lasse ich im DHCP Server für unser internes Netz die statische route ins Gast-Netz verteilen:

option rfc3442-classless-static-routes code 121 = array of integer 8;
option ms-classless-static-routes code 249 = array of integer 8;

subnet 10.0.0.0 netmask 255.255.255.0 {
    ...
    option rfc3442-classless-static-routes 24, 10,0,6, 10,0,0,42, 0, 10,97,0,1;
    option ms-classless-static-routes      24, 10,0,6, 10,0,0,42, 0, 10,97,0,1;
}

Jetzt kann ich auch mit ebtables die quell-MAC prüfen:

for dev in $APDEVICES; do
        ebtables -A OUTPUT -o $INTDEV -d $dev -j ACCEPT
        ebtables -A INPUT  -i $INTDEV -s $dev -j ACCEPT
done

ebtables -A OUTPUT -o $INTDEV -p IPv4 --ip-src $GUESTNET -j DROP
ebtables -A INPUT -i $INTDEV -p IPv4 --ip-dst $GUESTNET -j DROP

...und natürlich die statische route aus dem router wieder entfernen.

das komplette Firewall-script gibts hier.

(ich habe es als shell script geschrieben damit ich schleifen und variablen benutzen kann. beim systemstart wird es natürlich mit netfilter-persistent geladen.) (ich habe dafür auch ein netfilter-persistent plugin geschrieben. hier)

]]>
PHP is weird, too /php_is_weird_too/ php_is_weird_too Tue, 08 May 2018 17:37:36 +0200 everybody is like "ooh! js is so weird because it has no data types but it kind of has and does all those weird things!"

now look at this:

% php -a
php > echo 1;
1
php > echo 1.2;
1.2
php > echo 1."2";
PHP Parse error:  syntax error, unexpected '"2"' (T_CONSTANT_ENCAPSED_STRING), expecting ',' or ';' in php shell code on line 1
php > echo "2".1;
PHP Parse error:  syntax error, unexpected '.1' (T_DNUMBER), expecting ',' or ';' in php shell code on line 1
php > echo 1 . "2";
12
php > echo "1" . 2;
12
php > echo "1". 2;
12
php > echo 1 ."2";
12
php > echo 1 . "2";
12
php > echo 1 . 2;
12
]]>
Firefox cipher suites /firefox_cipher_suites/ firefox_cipher_suites Wed, 02 May 2018 15:37:26 +0200 Ich hab letztens bisschen mit nginx und ssllabs.com rumgebastelt. Dabei ist mir aufgefallen, dass die ja auch die Fähigkeiten des Browsers Testen können.

Mit ein bisschen Recherche habe ich jetzt meinem Firefox (59) über about:config TLS 1.1 (und älter) abgewöhnt und noch ein paar schlechte cipher suites abgeschaltet: dadurch ist nur noch TLS 1.2 und 1.3 aktiv

security.ssl3.dhe_rsa_aes_128_sha und security.ssl3.dhe_rsa_aes_256_sha sind wohl problematisch mit Logjam und security.ssl3.rsa_aes_128_sha, security.ssl3.rsa_aes_256_sha und security.ssl3.rsa_des_ede3_sha werden von ssllabs.com als "Weak" bezeichnet.

und dann hab ich noch security.mixed_content.block_display_content auf true gesetzt wegen Mixed Content Tests. (ssllabs test ganz unten)

Jetzt mal schauen was alles kaputt geht.

]]>
here's your blockchain in PHP. now please go away and do something useful /php-blockchain/ php-blockchain Fri, 20 Apr 2018 18:18:03 +0200 ]]> PHP Hackerei /php-hackerei/ php-hackerei Mon, 16 Apr 2018 12:14:53 +0200 Ab und an tritt man sich ja mal so nervice PHP Malware in sein ungeupdatetes CMS ein. Vor einer ganzen weile hab ich mir das schon mal angesehen und im Prinzip war das ein eval(gzinflate(base64_decode($payload))); und fertig. Dieses mal sah das aber irgendwie anders aus:

<?php Error_Reporting(0); $xcxzDg1YP8rc="xTyLU...Lj/8D";preg_replace("/.*/e","\x65\x76\x61...KTs='\x29\x29\x3B",".");return;?>

den ersten Blob hab ich mal durch einen base64 decoder gejagt. da kam aber nichts verwendbares raus. gzip inflate hat auch nichts geholfen.

der zweite blob war dann schon interessanter. Das e Flag von preg_replace ist glücklicherweise in PHP 7.0 raus geflogen, macht aber gruselige sachen:

If this deprecated modifier is set, preg_replace() does normal substitution of backreferences in the replacement string, evaluates it as PHP code, and uses the result for replacing the search string.

vorne und hinten in dem preg_replace stehen so lustige dinge wie \x65\x76\x61\x6C\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28' und '\x29\x29\x3B. wenn man das in ein echo packt sieht das plötzlich so aus:

php > echo "\x65\x76\x61\x6C\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28''\x29\x29\x3B";
eval(base64_decode(''));

was für eine Überraschung.

wenn man das dazwischen mal base64 decodiert kommt das dabei raus:

1  eval(base64_decode("ZXZhb...pKTs="));
2  eval(base64_decode("JHhXM...TQik7"));

wenn man das jetzt wieder decodiert (Zeile 1):

3  eval(base64_decode("JHh2Q...pOw=="));
4  eval(base64_decode("JHhje...pOw=="));

und (Zeile 2):

5  $xW0Bo8BkevISB='';for($xnp5MnqM2PZKm=0;$xnp5MnqM2PZKm<$x4DlL8LU0Czi;$xnp5MnqM2PZKm++){$xW0Bo8BkevISB.=$xZ7RSMsn4ZmH(($x5w4kSPWSl7BY($xcxzDg1YP8rc[$xnp5MnqM2PZKm])^1993826553));}eval($xW0Bo8BkevISB);

Zeile 3 und 4:

6  $xvAYBYcI58V=base64_decode("YmFzZTY0X2RlY29kZQ==");$xaDxbeJWnLb=base64_decode("c3RybGVu");$xZ7RSMsn4ZmH=base64_decode("Y2hy");$x5w4kSPWSl7BY=base64_decode("b3Jk");$xt9ptV8O76RX4=base64_decode("Z3ppbmZsYXRl");
7  JHhjeHpEZzFZUDhyYz0keHQ5cHRWOE83NlJYNCgkeHZBWUJZY0k1OFYoJHhjeHpEZzFZUDhyYykpOyR4NERsTDhMVTBDemk9JHhhRHhiZUpXbkxiKCR4Y3h6RGcxWVA4cmMpOw==

das ganze sieht dan wenn man es ein bisschen aufräumt so aus:

$xvAYBYcI58V="base64_decode";
$xaDxbeJWnLb="strlen";
$xZ7RSMsn4ZmH="chr";
$x5w4kSPWSl7BY="ord";
$xt9ptV8O76RX4="gzinflate";

$xcxzDg1YP8rc=gzinflate(base64_decode($xcxzDg1YP8rc));
$x4DlL8LU0Czi=strlen($xcxzDg1YP8rc);
$xW0Bo8BkevISB='';
for($xnp5MnqM2PZKm=0; $xnp5MnqM2PZKm < $x4DlL8LU0Czi; $xnp5MnqM2PZKm++){
    $xW0Bo8BkevISB.=chr((ord($xcxzDg1YP8rc[$xnp5MnqM2PZKm])^1993826553));
}
eval($xW0Bo8BkevISB);

$xcxzDg1YP8rc kommt aus dem ersten blob. original und decodiert hab ich hier mal noch verlinkt.

]]>
Ein Szenario /ein-szenario/ ein-szenario Mon, 02 Apr 2018 12:14:53 +0200 Es ist der 25.10.2022.

Cloudflare proxied jetzt 85% des Internets.

Die von Cloudflare verwendeten Docker Images sind einfach, leichtgewichtig, werden von irgendwem gut gepflegt und im Docker Hub veröffentlich. Natürlich sind sie deswegen weit verbreitet. Keiner hat sich genauer angesehen was darin alles verbaut ist.

Und selbst wenn. Die verwendeten npm Pakete sind alle unverfänglich. Zumindest laut github. Die Angreifer hatten aber schon vor Jahren eine Zeitbombe in das npm repository eingeschleust.

Sobald der Unix Timestamp 1666666666 vergangen ist, schalten die Container alle Services ab.

Die Autoscaling-Systeme von Cloudflare sind ebenfalls außer Gefecht.

Nach 1 Minute werden alle Services wieder gestartet. Das Autoscaling stellt sehr langsame Antwortzeiten fest und startet neue Container. Nach einer weiteren Minute – noch bevor die hunderten neuen Container ihren Dienst aufnehmen können – werden alle Services wieder abgeschaltet.

Das Autoscaling schaltet immer mehr Container und auch neue Hardware zu.

Die Admins von Cloudflare bekommen Sporadisch Alarm-Meldungen. Das Monitoringsystem ist tatsächlich nicht betroffen.

Aber der SMS- und Telefon-Service für die Benachrichtigung.

Inzwischen ist kaum eine Webseite mehr erreichbar. Die Backend Server langweilen sich.

Weltweit werden Admins aus dem Schlaf gerissen.

Schnell wird ihnen klar, dass Cloudflare down ist.

Sie versuchen Cloudflare aus Ihrem Setup herauszuschälen.

In hektischer Handarbeit werden Proxy-Konfigurationen in Applikationen angepasst.

SSL Zertifikate müssen erstellt und eingerichtet werden. Viele CAs sind entweder überfordert oder selbst direkt oder indirekt vom Cloudflare-Ausfall betroffen.

Bisher hatte Cloudflare SSL terminiert.

Alle versuchen nun die DNS Einträge wieder direkt auf ihre Server zeigen zu lassen.

Aber keiner schreibt mehr Zonefiles von Hand. Auch die Webinterfaces der DNS Provider sind entweder überlastet oder von Cloudflares Ausfall betroffen. Viele haben auch Ihre DNS Zonen Cloudflare anvertraut. Sie versuchen jetzt irgendwie ihre Zonen auf andere DNS Provider umzuziehen. Nur wie? Wer macht schon Backups von seinen DNS Zonen? Geht das überhaupt ohne weiteres?

Nutzt Docker, Cloudflare, npm, wenn es euch die Arbeit erleichtert. Überlegt nur auch mal zwischendrin ob man sich die paar Zeilen code für pad-left wirklich als Dependency ins Projekt holen muss. Und habt einen Plan in der hinterhand, wenn auch mal große Provider kaputt gehen. Die Wahrscheinlichkeit ist gering aber auch Riesen wie AWS waren mal großflächig kaputt.

Macht das Internet zu dem was es wirklich sein sollte.

]]>
Shopware Smarty Textbausteine /shopware-smarty-textbausteine/ shopware-smarty-textbausteine Wed, 14 Mar 2018 16:27:03 +0100 wenn man mal in nem smarty template herausfinden will, ob ein textbaustein gefüllt ist, kann man das so machen:

{if '{s name="sFooterShopNavi"}{/s}'}

außer, dass man es eben nicht so machen kann. smarty (bzw. shopware) fügt am ende den namespace noch an. allerdings mit single quotes. dann sieht das so aus:

{if '{s name="sFooterShopNavi" namespace='something'}{/s}'}

was dann natürlich nicht so geil ist. deswegen so machen:

{if "{s name='sFooterShopNavi'}{/s}"}
]]>