Trochę czasu minęło od zawodów TestingCup, w których brałem udział (z bardzo przeciętnym skutkiem). Regulamin zabawy mówi wyraźnie, że nie można używać debuggerów ani dekompilatorów. Co innego po zawodach, w celach czysto edukacyjnych. Pełne informacje przesłałem do organizatora (Radka Smilgina), który odpowiedział w mailu, że następny Mr. Buggy będzie lepiej zabezpieczony. Liczę na to, że wszystkie potencjalne wektory ataku zostaną załatane.

Wstęp:

Istnieje proste i darmowe narzędzie dotPeek od firmy JetBrains, które potrafi zdekompilować aplikacje napisane w .NET (core / framework). Chciałem dowiedzieć się, czego dowiemy się analizując dwie aplikacje:

  • Mr. Buggy 7
  • TestingCupReport.exe – czyli narzędzie do raportowania podczas zawodów

Zacznijmy od TestinCupReport.

Potencjalny atak #1:

Usunięcie z serwera danych drużyny przeciwnej.

Plik User.cs w projekcie TestinCupReport.Core zawiera wszystkie loginy. Wszyscy mieliśmy to samo hasło „GoodLuck”, więc można było usunąć z serwera dane drużyny przeciwnej.

1
2
3
4
5
6
7
8
private static string[] _identifiers = new string[121]
{
    "rdCfk7ZPv3pB",
    "xJ3KrXg7bQdU",
    "CLJgFaVEGXNe",
    "p6nku8x5P3WU",
    // some more
}

Obrona:
– kopia zapasowa na komputerze kapitana zespołu pozostawała nietknięta
– według maila od Radka, istnieją „bezpieczniki” na serwerze.

Potencjalne nadużycie #2:

Plik FinalEvaluationForm.cs w projekcie TestinCupReport zawiera wszystkie punktowane elementy w planie testów. Mogło to pomóc w napisaniu poprawnego planu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private string[] _reportContents = new string[17]
    {
      "Identifier or name of the document similar to "Test Plan for CR1"",
      "Goal of the document",
      "Description of the application under tests",
      "Reference to document describing changes",
      "Test scope: In scope",
      "Test scope: Out of scope",
      "Test scope: Regression tests",
      "Test approach (strategy or techniques or test levels) ",
      "Entry criteria",
      "Exit criteria",
      "Human resources or test team",
      "Time estimation or test schedule",
      "Hardware and software resources or environmental needs",
      "Risks",
      "Stylistics and consistency and design of the document",
      "Plan doesn’t contain important essential error",
      "Test artefacts or test evidence or test deliverables or reporting test tools"
    };

Obrona:
– regulamin zabraniający używania narzędzia, którego użyłem w tej analizie.

Potencjalny atak #3:

Plik Settings.cs zawsze jest ciekawym plikiem (projekt TestingCupReport). Widzimy tutaj hasła do serwera, endpointy i hasło do odblokowania zawodów w czystym tekście.

1
2
3
4
5
6
7
8
    public const int MaxChallenge = 2;
    private const string ServerCompetitionAddress = "http://192.168.0.3/connection/";
    private const string ServerEvaluationAddress = "http://192.168.0.3/connection/";
    private const string ServerExternalAddress = "http://api19.testingcup.pl/connection/";
    public const string ServerUserName = "LasicA20!(";
    public const string ServerPassword = "DoBr4!&Zmi4n4!";
    public const string UserPassword = "GoodLuck";
    public const string UnlockCompetitionPassword = "condor1410";

Obrona:
– regulamin zabraniający używania narzędzia, którego użyłem w tej analizie.

Potencjalne nadużycia #4:

Dekompilacja aplikacji Mr.Buggy 7 pokazała wiele rzeczy, z których tylko kilka opiszę.

LoginForm.cs i HelpForm.cs już na pierwszy rzut okaz pokazują stringi, które dadzą nam łatwe raporty literówek:

1
2
    this.Text = "MrBuggy 6 - Login";
    this.Text = "MrBuggy 6 - Help";

Projekt API pokazuje też kawałki kodu, które pozwoliłyby zaraportować bugi bez uruchamiania aplikacji (hasło miało mieć minimalnie 8 znaków, a regexy do przetestowania zostawiam czytelnikom).

1
2
3
4
5
6
if (str.Length < 6 || str.Length > 20)
          apiResponseErrorList.Add(new APIResponseError("password", string.Format(View.ResourceManager.GetString("rangeOfTextLengthError"), (object) 6, (object) 20)));
        else if (!Regex.IsMatch(str, "\\d+") || !Regex.IsMatch(str, "[\\!\\@\\#\\$\\%\\?\\.]+"))
          apiResponseErrorList.Add(new APIResponseError("password", View.ResourceManager.GetString("passwordIcorrectError")));
        else
          user.SetPassword(str);;

Takich kawałków kodu jest więcej w samym projekcie aplikacji desktopowej i moim zdaniem, pozwalają znacznie szybciej znaleźć i zaraportować bugi niż uczciwe testowanie czarnoskrzynkowe aplikacji.

Możecie powiedzieć „Hola hola, przecież tu chodzi o zabawę i uczciwą rywalizację!” – a ja odpowiem zgorzkniale, że uczciwa rywalizacja kończy się tam gdzie zaczynają się pieniądze i nagrody.

Jak się zabezpieczyć w następnych edycjach:

Istnieje kilka sposobów na zabezpieczenie przed takimi nieuczciwymi zagraniami.

  • Prostym i darmowym rozwiązaniem jest użycie obfuscatora, np: Skater .NET.
  • Istnieją również drogie komercyjne rozwiązania takie jak PeLock, które szyfrują i nie pozwalają na dekompilacje programu.
  • Usunięcie z klienta wszystkich haseł i loginów (one naprawdę nie są tam potrzebne)
  • Trzymanie projektu API w projekcie aplikacji okienkowej również można pominąć.
  • Można też napisać aplikację w innym języku niż C#, który nie dekompiluje się tak łatwo.