Procent od funkcji drukujących

2008-03-08 23:58

Wszyscy znamy funkcję printf – część standardowej biblioteki C – oraz jej liczne warianty z przedrostkami i przyrostkami, służące wypisywaniu tekstów do różnych miejsc na różne sposoby. Jeśli z nich korzystamy, to czasem zdarza się, że chcemy wydrukować komunikat dany jako pojedynczy, znany już napis. A wówczas można wyprodukować coś, co w najprostszej wersji będzie wyglądało tak:

  1. char* s;
  2. // ...
  3. printf (s);

Tak się jednak stringów nie wypisuje – nawet mimo tego, iż w większości przypadków działa to bez problemów. Możemy bowiem trafić na przypadek złośliwy, a błędy objawiające się tylko czasami są, jak wiemy, jednymi z najgorszych…

Rzecz w tym, że w rodzinie funkcji printfopodobnych za to, co wydrukujemy, odpowiadają dwie rzeczy. Drugą z nich jest lista danych, mogąca mieć dowolnie dużo elementów; stąd też funkcje te przyjmują zmienną liczbę argumentów. Ale pierwszą jest tak zwany format, który mówi, jak te elementy należy interpretować: jako liczby całkowite, zmiennoprzecinkowe czy w końcu napisy. Ten argument jest łańcuchem znaków, występuje przed pozostałymi i w odróżnieniu od nich jest obowiązkowy.
Wywołanie printf(s); w istocie oznacza więc, że s nie jest tekstem do wypisania, ale formatem służącym interpretacji ewentualnych dalszych parametrów. Skoro jednak kolejnych argumentów nie ma, to wydaje się, że nie ma też problemu – zwłaszcza, że w wyniku tekst spod s faktycznie jest wypisywany. Jest tak jednak tylko momentu, gdy natrafimy na łańcuch zawierający znaczek procenta (%).

Jak wiemy, format dla funkcji typu printf może bowiem zawierać (i zwykle zawiera) znaczniki odnoszące się do jej dalszych argumentów. Niemal zawsze wpisujemy je ręcznie w kodzie, bo dokładnie wiemy, co chcemy wydrukować – np.:

  1. int n;
  2. printf ("n = %i", n);

To sprawia, że bardzo łatwo zacząć je traktować identycznie jak sekwencje ucieczki, czyli podciągi \n, \t, itd., zamieniane przez kompilator na odpowiadające im znaki (tutaj: końca wiersza i tabulatora). W wynikowych stringach nie ma więc po nich śladu, zamiast tego są odpowiednie znaki, których nie da się normalnie wpisać z klawiatury.
Ale znaczniki formatujące nie są interpretowane przez kompilator. Podczas działania programu w tym łańcuchu nadal siedzi %d, %f i każdy inny znacznik rozpoczynający się od procenta. Jeśli więc łańcuch s z wywołania printf(s); przypadkiem zawiera znak procenta, to funkcja mylnie potraktuje go i znaki po nim występujące jako znacznik formatujący. Zachowanie może być wtedy różne – w najlepszym wypadku ów procent i następny znak zostaną po prostu “zjedzone” – ale zawsze będzie różne od naszych oczekiwań.

Konkluzja? Jest oczywiście taka, aby zawsze pamiętać o formacie i nawet jeśli wypisujemy “tylko” łańcuch znaków, umieścić w nim %s:

  1. printf ("%s", s);

Różnica mała, lecz ważna :)

Tags: ,
Author: Xion, posted under Programming »


3 comments for post “Procent od funkcji drukujących”.
  1. KKKas:
    March 9th, 2008 o 2:32

    To, że zostanie “zjedzone” to najmniejszy problem. Większy to: http://en.wikipedia.org/wiki/Format_string_vulnerabilities

  2. moriturius:
    March 9th, 2008 o 6:59

    Ten format string attack jest podobny SQL injection ^^

  3. mINA:
    March 10th, 2008 o 13:13

    Nie jest ani trochę podobny :) Format string attack uderza w całkiem inne warstwy, działa na niższym poziomie, inaczej się exploituje i umożliwia inne rzeczy :)

Comments are disabled.
 


© 2019 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.