*Wikipaka Intro Musik*
Herald: Welcome to the next talk about
free substitution for schools. Yeah. By…
if it was done by Fynn […]. Thank you, for
the translators for translating into
German. Let's start.
Fynn: In general, as you know, teachers
can't always teach as planned, so students
need to be informed when their lessons are
moved in time or space or both, or don't
take place as they should, or they have a
different teacher. All that. And for that,
schools create a substitution plan.
There's software for that. For example,
Untis. And these substitution plans need
to be distributed. And in Germany, a lot
of schools use Digitales Schwarzes Brett
or Digital Signage Board or DSB for that.
And it works like this. Um. Oh, yeah. And
it works like this that the school uploads
the plan. Pupils can read this
substitution plan on these DSB screens, on
their mobile devices using the client
software developed by Heinekingmedia and
using the website, once they have the
credentials that they acquired from their
school. It's one pair of username and
password for all pupils and one for all
teachers. Well. And this costs money,
schools buy way to expensive screens from
Heinekingmedia. And then the schools pay
extra for this, uh, fantastic web
interface here where you can sign in and
view your substitution plans. You can also
use this mobile app. It's not really good,
though, as I will explain. Um, this is
what it looks like. Things are tiny, as
you can see. It's obviously proprietary
software. It depends on Google Play
services. You need to zoom around. You
need to scroll around to see all the
information because it's so tiny. So this
is super suboptimal. Um, I don't even know
why this is so small. If you look it up on
a Web browser, it zooms fine when you have
a small device. And I really don't know
how that… screwed up like that. It has
useless push notifications like new
content available. It's not not useful.
And you have to click at least one time
too much all the time. And due to these
issues, I always wanted something that is
better than DSB mobile. So I began
capturing DSB mobiles network traffic.
Surprisingly, in Android, this is really
easy. Um, you can use user friendly
software like HTTPCanary, which is this
one, or packet capture, which is this one.
It's unfortunately proprietary, but I
don't know any non-proprietary software
for this is. If you know any, please tell
me. Um, it acts like a VPN provider app
and proxies all the traffic that is going
out, uh, through it; installs a
certificate in your system so that apps
still think that the net…work connection
is secure, and then this app will decrypt
and store and re-encrypt all the traffic
that is going out and in. And so you can
read it, then. Uh, this is essentially
like a attacker-in-the-middle attack that
you're doing yourself on your own network
traffic. Uh, yeah, except on recent
Android versions. Apparently Android
doesn't trust certificates that you
install, anymore. So you actually now have
to have root access to move them to this
location /systems/etc/security/cacerts so
that they are ultimately trusted. And that
is unfortunate because it makes it a
little more difficult. But in all our
Android versions, it works really easy.
Um, with more effort, this capturing of
network traffic can be circumvented by
implementing a kind of certificate
pinnings so that the app checks beforehand
which certificates it trusts, and which it
doesn't. With more effort, such a
prevention could also be circumvented. Uh,
but DSB Mobile didn't have that, so I
could figure out how this end point works.
As you can see, it's called the iPhone
Service. On Android. Using your user ID
and password, you can request an auth
token. It has the form of this. Actually,
that's what it looks like when you have
invalid credentials. So if it returns
this, then your credentials are not valid.
It never changes. So I don't know what the
use of this token is. Um, however, DSB
Mobile never stored it, even though it's
the same all the time. So it took one
extra round trip time, every log in to
fetch this, never changing auth token.
Using this auth token, you can request
your substitution plan URL, and then once
you have this substitution plan URL, you
can access your substitution plan. OK, so
using this knowledge, I developed a client
that allows me to directly have access to
just the relevant information and I call
it DSBDirect. Uh, the very first thing it
did better than DSBmobile is that it
display things not as tiny. This is a kind
of old screenshot as you can see. These
HTML files here can be parsed using a
parser and such that, uh, you can filter
it, you can, um, have useful notifications
that I added later on. This is a native
list, not a web view. So it has… it feels
better. And uh, yeah, of course it's not
proprietary but Free Software. Uh yeah.
Oh, by the way, this logo, it's supposed
to represent my school's logo. Uh, this
one. Hmm. Please don't tell me I did, too
bad. OK? At least it's different from the
DSB mobile logo. This endpoint is fun in
other regards. The first time I
encountered it, it allowed completely
unencrypted connections, and the website
did not redirect users to HTTPS. So
actually you'd most of the time input your
username and password and transmit it
unsecurely. It supported up to TLS version
1.0, which is obsolete. It supported
SSLv2, which enables a DROWN attack, which
I didn't quite understand. But apparently
those aren't very likely to be exploited
here. But it could allow attackers to read
your traffic. I informed the company about
this on August 11th. And I believe this is
when I introduced the "not my fault
grumble" tag in the issue tracker…
tracker. They were happy to be informed
about this. On August 22nd, they enabled
TLS version 1.2, disabled SSLv2, er, still
allowed insecure connections. And I also
noticed that they embedded fonts from
Google and this is obviously bad for
privacy. So I told them about that. Uh,
Twice. September 19th, the iPhone service
404s if the connection is insecure.
Although Google fonts are still embedded.
Anyhow, it's October 4th that the iPhone
service is shut down. So I start focusing
on the new endpoint that apparently the
DSB apps have been using for a while, but
I didn't notice that. Uh, so I had to
figure out how this data format works. It
looks like this. So you can see it has a
JSON body usi– which has a request, which
is an object that has data, which is a
string. So I wanted to figure out how to
read this. It looks like base64 when I'm
escaping these slashes, of course, because
it's quoted in JSON. Um, however, decoding
this JSON string here did not, er, this
base64 string did not deliver a nice
result. Uh, so I had to look for clues by
decompiling the app. There are online
tools for that. Unfortunately, the app was
minified or… which is obfuscated during
compile time, which made the results not
very readable, which means that once you
have it decompiled, you will have, the
first function that appears is "A", and
the second one is "B" or something.
Fortunately, I don't remember how exactly
I did that. So instead we're going to have
to look at whether this was legal or not.
Because that's interesting, too, because I
think it is. Let's look at § 69e UrhG,
copyright law, Urheberrechtsgesetz,
"Dekompilierung". "Die Zustimmung des
Rechteinhabers ist nicht erforderlich,
wenn die," und hier steht "Verviefältigung
des Codes oder die Übersetzung der
Codeform im Sinne der in § 69c Nr. 1 und
2.," gemeint ist Dekompilierung,
"unerlässlich ist, um die erforderlichen
Informationen zur Herstellung der
Interoperabilität eines unabhängig
geschaffenen Computerprogramms mit anderen
Programmen zu erhalten, sofern folgende
Bestimmungen erfüllt sind." So. It says
you may decompile without permission when
it is strictly necessary while trying to
create interoperability between two
programs created independently from each
other. Under these conditions. And here
are three conditions. Um, "Die Handlungen
werden von dem Lizenznehmer oder einer
anderen zur Verwendung eines
Vervielfältigungsstückes des Programms
berechtigten Person oder in deren Namen
von einer hierzu ermächtigten Person
vorgenommen". It says, you must have
permission to use the program. Hey, I
think I'm allowed to use the program. I'm
assuming I am. My school paid for it.
Second, "die für die Herstellung der
Interoperabilität notwendigen
Informationen sind für die in Nummer 1
genannten Personen noch nicht ohne
weiteres zugänglich gemacht". So the
information you want to know is not
already provided. Oh yeah. Actually
Heinekingmedia didn't document this
obviously. So yeah. This
*indistinguishable*. Third, "Die
Handlungen beschränken sich auf die Teile
des ursprünglichen Programms, die zur
Herstellung der Interoperabilität
notewndig sind". So you're only planning
the part that contains the information you
want to know. Uh, yeah. I don't think this
Android app is divided into parts. So
let's just, let's just skip that. The law
text goes on stating three things you may
not do with the information you gain from
decompiling. "Bei Handlungen nach Abs. 1
gewonnene Informatione dürfen nicht zu
anderen Zwecken als zur Herstellung der
Interoperabilität des unabhängig
geschaffenen Programmes verwendet werden."
So don't use it for other purposes than
creating interoperability,
interoperability with the independently
created program. Oh yeah, of course. I
never did use my knowledge for any other
reasons. Never. "…an Dritte weitergegeben
werden, es sei denn, das dies für die
Interoperabilität des unabhängig
geschaffenen Programms notwendig ist". So
don't tell third parties about the
information unless necessary for
interoperability. Oh, yes, my Free
Software implementation couldn't be
interoperable if the information wasn't
public. Unless it was Non-Free Software,
which is not obviously. "Für die
Entwicklung, Herstellung oder Vermarktung
eines Programms mit im Wesentlichen
ähnlicher Ausdrucksform oder für
irgendwelche anderen das Urheberrecht
verletzenden Handlungen verwendet werden".
So don't violate the rest of the copyright
law. Of course, we're not. Surely,
creating an alternative to something, on
its own, doesn't violate copyright law.
Right? So yeah, after doing it, I
discovered that I did so legally. So I
found a usage of some class related to
gzip. So I tried around a bit and figured
you could use this command to decrypt this
string. And guess what it is? It's more
JSON! What an efficient data format.
You're hiding our encoded JSON inside more
JSON. Let's look at the data we are
sending. Of course, we have a user ID and
a pass. Besides that we have a lot of
data, apparently for statistics. You have
the app's version, you have the package
ID, the device model, the Android version
and API level, the user's language and the
current date. I don't know why you have
the date. I think they know the date that
the query arrives at, but, ya, you have
that anyway. You have a… oh sorry, some of
this is redundant from the request header
or user agent that is already sent. I
don't know why they do that twice. Um, you
have App ID, which is a unique-per-
installation ID, which I at first didn't
know how to generate. And you push ID,
which is, I'm assuming, an ID generated by
Google Mobile Services now known as Google
Play Services to enable push
notifications. So it becomes obvious that
they're able to link requests together and
possibly create usage patterns. What are
they doing with this data? No clue!
There's no privacy policy anywhere. Which
of these fields are required? All of them,
but push ID. But most strings can be left
empty. So DSBdirect sent the minimal
amount of requested data, which is
everything but with empty strings. And
yeah, actually guess what, this server
allows insecure connections again. So, uh,
something happened. Um. On some date, the
server side verification of this query was
changed and the field AppVersion suddenly
became mandatory. I ran some experiments
and found examples of valid and invalid
version names. These are examples of valid
version names. These are examples of
invalid version names. Finally,
AppVersions that aren't real versions of
Heinekingmedia's apps are accepted anyhow,
like version 7.0.0. We're only at version
2.5.… I don't remember, 6, I think. So,
DSBlight started sending along some
AppVersion… its own actually, which was
2.5, and the same as an older DSBmobile
release. And because I thought maybe
they'd have more server side changes in
the future, I implemented a new system. It
was to prevent server side changes from
requiring an update because that would
mean I have to write change logs because
after it releases are slow because the one
who was uploading it to Google Play for me
also always took a while. And because of
that, there was now a "look for a fix"
button that creates the news file, which
is located at the repository's root, which
allows me to inform users when they can
expect a fix. It allows me to change this
base JSON, that credentials are appended
to which is this without the user ID and
user password. So they're added to this
JSON later. And… in case they checked that
I added an option to send the real date. I
thought maybe that's what they would do
next. They never did that, unfortunately.
This was the same release as the one with
the version number fix, this one. Uh, we
have good news elsewhere, though. It was
the same day, October 15th, that I
received an email that app.dsbcontrol.de
was no longer accessible on Port 80 and
that Google fonts were now being loaded
locally. This e-mail contained no usual
"bei Rückfragen können Sie sich gerne
direkt an mich wenden", unfortunately,
maybe they didn't want to hear from me
anymore. I couldn't verify this at first.
Uh, October 16th, I could verify this. So
a friend noted that they have slow deploy
times, apparently. Uh, round 3, it's
October 17th, and we're getting an invalid
answer from the server again. And now the
App ID has to be set to a UUID and last ID
has to be set to something. It can't be
empty. So we are now sending
"zurfrühstückszeit". I wasn't aware of how
to generate App IDs yet, so I just took
the one that I had captured from my
device. Contributor Pixilon and me learned
this through trial and error. I thought it
was very bothersome because the service
sometimes accepted and sometimes rejected
the very same query. Uh, so this slow
update cycle we noticed earlier turned out
to be really bothersome and frustrating
because you'd, you try something and then
it would work and then you'd remove it
again and that wouldn't work anymore. And
then you thought this was the cause for
it… actually was just the slow release,
deploy cycle. Um, likely, or maybe, they
had just banned this app ID at this point
in time, but I didn't realize, I'm not
sure. Rather, I believe the server was
generally are struggling and rejecting log
ins because my DSBmobile installation,
with this app ID, was also sometimes
rejected. *incomprehensible*. They seem to
have reverted some of these changes later,
which reaffirmed my belief that all
DSBmobile installations were affected.
Contributor Pixelon figured that device
was now mandatory, which meant not empty.
So we sent device "a". I remembered to
have at some point in time sent the words
"kartoffel" or "poster" as a device
eventually. Now, I thought we were smart.
I added new functionality to this new
system I explained earlier. Firstly, as a
precaution, I could remotely activate
sending the last date, in case that, I
mean remotely means that it happens when
users click on "Look for a fix". Secondly,
I could now set an array of headers to
send to the server. And thirdly, we had
discovered some alternative endpoints. To
understand this, you first have to know
that they have sold skinned versions of
DSB. Uh, so this is the normal DSBmobile.
I showed it earlier already. This is the
IHK skinned DSBmobile. It's accessible via
two URLs, that delivers the same data as
this website. Uh, it also has a
corresponding skinned Android app. So I
configured… so I could configure the
endpoint the client would send the data to
because each of these had a different
endpoint and this app used one of these
two. However, this was tricky because I
had to prevent myself from giving myself
the power to redirect users' queries to my
own server, so I hardcoded four URL
endpoints… endpoint URLs, mobile, web, IHK
mobile and app IHK BB into the app so I
could switch between them using an integer
and I set it to the IHK mobile endpoint. I
believe it was the very next day that IHK
mobile and and app IHK BB endpoints were
broken. Actually, they returned invalid
data in a way that crashed my app. Oops.
And suddenly the web endpoint from the
normal website was constantly moving to
new locations and there was a
configuration.js script that contained
where it was, so I hard coded into the app
as a precaution in case I'd need it later
a very specific way to to find this
location. And it was like behind this
seventh quotation mark or something.
Clearly unreliable, and suddenly the
string was moved a line downloads, so it
was now the ninth quotation mark.
Interesting. Um, also this App stopped
working. It's still on the Play Store now
and it's still not working. This website
is still available and it's not working
because they broke their end point. Uh,
this was around the time that this Google
Play takedown notice reached us because
apparently DSBdirect infringes the
trademark of DSB. I don't feel qualified
to comment on this as I don't understand
trademark law. I tried to ask for a
specific clarification as to why they
removed my app, three times, but they
never responded. Oh, by the way, that's a
nice trick you can do with emails you
don't like. You can just pretend you never
received them. So a few days later, the
website JavaScript, including
configuration.js, was obfuscated in such a
way that I don't understand how it works,
but it constantly evokes the debugger, if
the developer tools are open. You can in
theory easily circumvent this by telling
the browser to ignore breakpoints. This
doesn't seem to work with Firefox, but it
works in chromium. I don't know why. I'm
just going to assume you could have
figured this out somehow. Be it that we
could have had a web view running in the
background if we absolutely had to. But
fortunately, contributor Pixon had come up
with what is needed to talk to the mobile
endpoint now. Because it's more data.
Through decompilation he learned that it
was being generated using the default Java
UUID class, UID. … randomUUID.toString.
Also device idea was mandatory. So I added
spoof data. I took a random device ID from
this list. I took a random OS version from
anything between 4.0.2 and 10.0, I took a
random language, mostly German, sometimes
English. And as a BundleId, I took the
package ID of DSBmobile. With an option to
disable this via news in case it would get
in the way somehow. And that was the end
of that. Apparently they stopped trying to
prevent DSBmobile from working. Apparently
after it releases don't count to them and
it isn't worth their time. Or maybe they
were just uncreative. I could still think
of a few ways to tell DSBlight and
DSBmobile apart, but I'm clearly not going
to tell them. However, just this month,
Pixilon asked again why DSBmobile was
removed from the Play Store, also because
he believed we didn't violate German
trademark law, currently, but, uh,
Jasmich, who, uh, is sitting here, by the
way, had uploaded DSBdirect to the Play
Store again and received a rather
interesting response. "Sehr geehrter Herr
Zwerger", dear Pixilon, "Vielen Dank für
Ihre E-Mail. Leider sehen wir uns
außerstande mit Ihnen einen qualifizierten
Diskurs zu diesem Thema zu führen. Uns
sind weder Daten zu Ihnen noch zum Herrn
Godau bekannt." This means, unfortunately,
we don't have your address and thus can't
send you legally meaningful messages.
Heißt, sie wollen Einwurfeinschreiben
machen. "Ebenfalls ist uns nicht klar, in
welcher Rechtsbeziehung Sie zueinander
stehen". We don't know about your legal
relationship. This is a bit strange
because I don't know either. According to
my father, we might be a "Gesellschaft
bürgerlichen Rechts", but it's not exactly
proof of familiarity with Free Software.
"Dennoch möchte ich im Folgenden unsere
Position nochmals klar ausdrücken. Es ist
weder Ihnen noch anderen Dritten
gestattet, unsere interne DSBmobile-API
für eigene Softwareprodukte abzufragen.
Wir untersagen es Ihnen hiermit
schriftlich und letztmalig." You may not
use our internal API, I find it
questionable whether a publicly facing API
is to be considered internal. One might
argue that it is only for communication
between software they control. But I
believe I control my device and my client
installation, not them making the API, not
internal. "Eine Inverkehrbringung einer
App mit gleichem oder ähnlichen Namen zu
DSB ist Ihnen im europäischen Raum
ebenfalls untersagt. Hier liegt
Markenschutz durch Heinekingmedia vor." I
don't understand trademark law. There are
so many trademarks starting with this or
just consisting of the letters DSB with
partially overlapping registered use cases
and their trademark doesn't have
distinctive character,
"Unterscheidungskraft", and I just don't
understand it. By the way, there are other
trademark "Digitales Schwarzes Brett"
which is registered as a different one
from DSB was once rejected as a national
trademark just because it didn't have
distinctive character. Why can there be
European trademark laws without– European
trademarks, without distinctive character?
I do not understand and I'm not qualified
to comment. "Eine App-Bereitstellung im
Store ist dabei eine geschäftliche
Tätigkeit, ganz egal welchem
wirtschaftlichen Zweck diese folgt, es
besteht Verwechslungsgefahr. Wir
untersagen Ihnen hiermit die Benutzung der
geschützten Wortmarke DSB letztmalig." Um,
the first part is true. I had gotten lot
wrong. It counts as "geschäftlicher
Verkehr" when you provide a service even
for free to the public. Er, there's danger
of confusion, this has to be about the
letters DSB, right? Because as I explained
earlier our logo is completely unrelated.
Either, I'm not too certain that there
really is danger of confusion that
Heinekingmedia is directly affected by or
exclusively affected by. After all, one
could also believe that it is an app that
provides access to something related to
the Danish railway company. Of course it
does not, but it is about recognition
value, which is not something that the DSB
has exclusively for sure. "Wir untersagen
Ihnen hiermit die Benutzung der
geschützten Wortmarke DSB letztmalig."
*undistinguishable" "Sollten Sie weiterhin
gegen unsere deutlichen Aufforderungen
verstoßen, werden wir den Fall an unsere
rechtliche Vertretung, Herrn Doktor Selig
übergeben. Dieser ist in dieser E-Mail
bereits CC." Scaring us. "Ebenfalls werden
wir weiterhin gegen jede Veröffentlichung
einer solchen App vorgehen. Entsprechend
dadurch entstehende Kosten würden wir bei
Ihnen als Schadensersatz geltend machen.
Wir bitten um zwingende Beachtung. Mit
freundlichen Grüßen, Andreas Noack. Noag,
Norg, Noack. That's the CEO of
Heinekingmedia. Yeah, we are famous! We
redirected this email to contributor
Jasmich who had DSBdirect up on the Play
Store at this point of time. And he
decided to take it down and apologize.
Suddenly, and this was the very next day
he received an email that sounded a lot
friendlier. "Hallo. Vielen Dank für Ihr
Entgegenkommen. Wir finden Ihren Ansatz
prinzipiell sehr gut. Allerdings hätten
wir uns gewünscht, dass Sie uns vor
Veröffentlichungen und Nutzung unserer API
um Erlaubnis gebeten hätten." If we had
asked for permission, I'm quite sure we
would not have received it. "Dennoch
möchten wir Ihr Engagement gerne würdigen,
und würden Sie daher gerne zu uns nach
Hannover einladen. Vielleicht können Sie
uns mit Ihren Ideen helfen eine bessere
App zu bauen? Vielleicht finden wir ja
sogar einen Weg, dass Sie daran mitbauen?
Gerne fördern wir junge Talente. Wir
würden uns freuen, Sie kennenlernen zu
dürfen. Ich freue mich auf Ihre
Rückmeldung. Mit freundlichen Grüßen,
Noack." I rather– I'll rather leave this
largely uncommented. I don't know exactly
what they want from us, but I guess we'll
have to see. And that's the dramatic
cliffhanger that we have to end our talk
with. Events are yet to unroll. There's
one thing that I can learn from this.
Don't use other people's trademarks.
Because trademark law is too complicated.
Apologizing instead of being rebellious
seems to work better, even if the thought
of conflict intrigues you and you really
do believe you're in the right, you
probably just misunderstood the law.
Alternatively, exclusively do such things
anonymously. Decide beforehand what you
want to put your name on. Thank you.
*Applause*
*postroll music*
Subtitles created by c3subtitles.de
in the year 2021. Join, and help us!