Seperti yang saya janjikan sebelumnya, kali ini akan saya jelaskan lebih dalam lagi tentang OpenID. Apa saja yang akan saya bahas? Saya akan mengajak anda untuk melihat lebih dalam lagi komunikasi yang terjadi antara provider,consumer dan user browser. Jika pada artikel sebelumnya saya hanya menceritakan bahwa consumer berkomunikasi secara langsung atau tidak langsung dengan provider, kali ini saya akan tunjukkan data apa saja kah yang dipertukarkan di antara mereka untuk memastikan identitas seseorang?
Setup the Lab
Agar mudah melakukan sniffing, saya harus mensetup lab sederhana yang bisa saya kendalikan sepenuhnya. Dari ke-3 entitas yang terlibat dalam openid, lebih mudah bagi saya untuk membuat consumer website di komputer saya sendiri daripada membuat provider. Sebab sniffing di sisi consumer atau di sisi provider hasilnya akan sama saja, jadi buat apa merepotkan diri dengan membuat provider.
Dalam lab ini consumer adalah wordpress dengan plugin OpenID yang saya install di localhost dengan XAMPP (php+mysql+apache), sedangkan provider saya pakai provider yang sama dengan artikel sebelumnya, yaitu PIP.VerisignLabs.com. Lengkap sudah, consumer dan provider sudah ada, kini saya siap mensniff komunikasi antara consumer dan provider dari sisi consumer.
Untuk melakukan sniffing komunikasi langsung antara consumer dan provider saya menggunakan tools Wireshark. Sedangkan komunikasi yang melalui browser (tidak langsung), saya menggunakan addon Firefox Live HTTP Header sebagai sniffer (walaupun addon ini hanya bisa menampilkan header http). Diagram lab saya bisa dilihat pada gambar berikut ini:
Skenario Simulasi Untuk memahami detil komunikasi dalam openid, saya akan mensimulasikan pemakaian openid. Jadi skenarionya sederhana saja, saya akan login ke wordpress yang sudah saya install di komputer sendiri (localhost) menggunakan OpenID identifier: masrizki.ilmuhacking.com. Setelah itu saya akan diredirect ke halaman login PIP Verisignlabs dan juga melakukan otorisasi trust relationship. Kemudian saya akan dikembalikan ke halaman administrasi wordpress sebagai seorang contributor.
Login to WordPress using OpenID Saya akan mulai simulasinya dengan login ke wordpress pada URL http://localhost/wordpress/wp-login.php. Pada kolom openid saya masukkan masrizki.ilmuhacking.com sedangkan kolom lainnya saya kosongkan. Berikut adalah gambar dari halaman login wordpress yang sudah mendukung openid di localhost.
Komunikasi http yang berhasil disniff ketika tombol Login diklik adalah (beberapa header yang tidak penting saya hapus):
1 2 3 4 5 6 7 8 9 10 11 12 13 | http://localhost/wordpress/wp-login.php POST /wordpress/wp-login.php HTTP/1.1 Host: localhost Referer: http://localhost/wordpress/wp-login.php Cookie: wordpress_test_cookie=WP+Cookie+check; wp-settings-time-1=1234937131; wp-settings-time-2=1234936984; PHPSESSID=d4d55ee29f62239a347be3a04dc8f8a4 Content-Type: application/x-www-form-urlencoded Content-Length: 143 log=&pwd=&openid_identifier=masrizki.ilmuhacking.com&wp-submit=Log+In&redirect_to=http%3A%2F%2Flocalhost%2Fwordpress%2Fwp-admin%2F&testcookie=1 HTTP/1.x 200 OK Set-Cookie: wordpress_test_cookie=WP+Cookie+check; path=/wordpress/ Content-Length: 1718 |
Pada baris ke-9 terlihat parameter POST yang dikirim, diantara yang penting adalah:
- openid_identifier: masrizki.ilmuhacking.com
- redirect_to: http://localhost/wordpress/wp-admin/
openid_identifier menunjukkan identifier (url) openid yang dipakai untuk login, dan redirect_to menunjukkan url ketika semua proses authentication berhasil (bila login berhasil user akan masuk ke url tersebut). Setelah user mengklik submit, consumer akan mendownload file html yang ada di http://masrizki.ilmuhacking.com. Berikut sniffing download file tersebut:
GET / HTTP/1.0 User-Agent: php-openid/2.1.2 (php/5.2.6) Host: masrizki.ilmuhacking.com Range: 0-1048576 Port: 80 Accept: application/xrds+xml, text/html; q=0.3, application/xhtml+xml; q=0.5 HTTP/1.1 200 OK Date: Wed, 18 Feb 2009 06:03:43 GMT Server: Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.8i DAV/2 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 Last-Modified: Wed, 11 Feb 2009 08:51:39 GMT ETag: "3fe00c5-2b2-462a0b6435cc0" Accept-Ranges: bytes Content-Length: 690 Connection: close Content-Type: text/html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <link rel="openid.server" href="http://pip.verisignlabs.com/server" /> <link rel="openid.delegate" href="http://masrizki.pip.verisignlabs.com" /> <link rel="openid2.provider" href="http://pip.verisignlabs.com/server" /> <link rel="openid2.local_id" href="http://masrizki.pip.verisignlabs.com" /> <meta http-equiv="X-XRDS-Location" content="http://pip.verisignlabs.com/user/masrizki/yadisxrds" /> <title>OpenID MasRizki</title> </head> <body> <h1>OpenID MasRizki</h1> </body> </html>
File html yang didapatkan dari masrizki.ilmuhacking.com mengandung informasi server openid provider yang dipakai, yaitu http://pip.verisignlabs.com/server. Selain itu juga didapatkan lokasi file XRDS, di http://pip.verisignlabs.com/user/masrizki/yadisxrds, berikutnya consumer akan mendownload file XRDS dari url tersebut. Berikut sniffing komunikasi yang terjadi:
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 | GET /user/masrizki/yadisxrds HTTP/1.0 User-Agent: php-openid/2.1.2 (php/5.2.6) Host: pip.verisignlabs.com Range: 0-1048576 Port: 80 HTTP/1.1 200 OK Date: Wed, 18 Feb 2009 06:04:01 GMT X-XRDS-Location: http://pip.verisignlabs.com/user/masrizki/yadisxrds Content-Type: application/xrds+xml;charset=ISO-8859-1 Content-Length: 1118 Connection: close <?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0" xmlns="xri://$xrd*($v*2.0)"> <XRD> <Service priority="0"> <Type>http://specs.openid.net/auth/2.0/signon</Type> <Type>http://openid.net/sreg/1.0</Type> <Type>http://openid.net/extensions/sreg/1.1</Type> <Type>http://schemas.openid.net/pape/policies/2007/06/phishing-resistant</Type> <Type>http://schemas.openid.net/pape/policies/2007/06/multi-factor</Type> <Type>http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical</Type> <URI>http://pip.verisignlabs.com/server</URI> <LocalID>http://masrizki.pip.verisignlabs.com/</LocalID> </Service> <Service priority="1"> <Type>http://openid.net/signon/1.1</Type> <Type>http://openid.net/sreg/1.0</Type> <Type>http://openid.net/extensions/sreg/1.1</Type> <URI>http://pip.verisignlabs.com/server</URI> <openid:Delegate>http://masrizki.pip.verisignlabs.com/</openid:Delegate> </Service> </XRD> </xrds:XRDS> |
Setelah mendownload file html dari XRDS, berikutnya consumer akan meminta provider untuk melakukan authentication terhadap user tersebut. Untuk melakukannya consumer akan meminta browser untuk membuat request ke openid server provider di url: http://pip.verisignlabs.com/server. Ada dua cara untuk melakukan itu, yaitu dengan memberi response 302 Redirect atau memberi response 200 OK namun diberi html form auto-submit. Openid pada wordpress memilih memakai form auto-submit, dengan cara mengirimkan file html berikut sebagai response dari klik tombol Login di halaman login wordpress :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <html dir="ltr" xmlns="http://www.w3.org/1999/xhtml" lang="en-US"><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>OpenID Authentication Redirect</title> <link rel="stylesheet" href="http://localhost/wordpress/wp-admin/css/install.css?ver=20081210" type="text/css" media="all"> </head><body id="openid-page"> <noscript><p>Since your browser does not support JavaScript, you must press the Continue button once to proceed.</p></noscript> <form action="http://pip.verisignlabs.com/server" method="post"> <input name="openid.ns" value="http://specs.openid.net/auth/2.0" type="hidden"> <input name="openid.realm" value="http://localhost/wordpress/" type="hidden"> <input name="openid.mode" value="checkid_setup" type="hidden"> <input name="openid.return_to" value="http://localhost/wordpress/?openid=consumer&janrain_nonce=2009-02-18T06%3A38%3A05ZrtUK3x" type="hidden"> <input name="openid.identity" value="http://masrizki.pip.verisignlabs.com/" type="hidden"> <input name="openid.claimed_id" value="http://masrizki.ilmuhacking.com/" type="hidden"> <input name="openid.assoc_handle" value="dec470c0-fd80-11dd-8f5a-d5350139866a" type="hidden"> <noscript><div><input value="Continue" type="submit"></div></noscript> </form> <script type="text/javascript"> document.write("<h2>Please Wait...</h2>"); document.forms[0].submit() </script></body></html> |
Pada file html tersebut terdapat tag FORM dengan method POST ke action url: http://pip.verisignlabs.com/server. Tadi saya menyebut auto-submit karena pada baris di paling bawah terdapat javascript yang melakukan submit, jadi tanpa perlu user klik tombol submit, form tersebut sudah automatically submit. Namun bila di browser user tidak mendukung javascript, maka user harus mengklik tombol “Continue” secara manual. Ketika HTTP POST ini disubmit, berikut sniffing komunikasi yang terjadi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | http://pip.verisignlabs.com/server POST /server HTTP/1.1 Host: pip.verisignlabs.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 ImageShackToolbar/5.0.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://localhost/wordpress/wp-login.php Cookie: __utma=182045240.1255127474965694500.1234512662.1234523895.1234936800.3; __utmz=182045240.1234512662.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmb=182045240.9.10.1234936800; __utmc=182045240; JSESSIONID=4F3B5E2D447C07B6D616CCFFF1DF3663.pip1 Content-Type: application/x-www-form-urlencoded Content-Length: 549 openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1&openid.sreg.optional=nickname%2Cemail%2Cfullname&openid.realm=http%3A%2F%2Flocalhost%2Fwordpress%2F&openid.mode=checkid_setup&openid.return_to=http%3A%2F%2Flocalhost%2Fwordpress%2F%3Fopenid%3Dconsumer%26janrain_nonce%3D2009-02-18T06%253A07%253A10Z4ZW4Xj&openid.identity=http%3A%2F%2Fmasrizki.pip.verisignlabs.com%2F&openid.claimed_id=http%3A%2F%2Fmasrizki.ilmuhacking.com%2F&openid.assoc_handle=dec470c0-fd80-11dd-8f5a-d5350139866a HTTP/1.x 302 Moved Temporarily Date: Wed, 18 Feb 2009 06:04:07 GMT Location: http://pip.verisignlabs.com/login.do Content-Length: 0 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html |
Ternyata submit post ke URL http://pip.verisignlabs.com/server, dibalas dengan 302 Redirect ke URL: http://pip.verisignlabs.com/login.do, yang tidak lain adalah halaman login. Hal ini terjadi karena user tersebut belum login di PIP sehingga diarahkan ke halaman login, bila user sudah login maka tidak diarahkan ke halaman login, tapi langsung ke halaman authorize trust relationship.
Login to OpenID Provider Perhatikan pada gambar tersebut halaman login menggunakan https. Ternyata pada saat browser request ke http://pip.verisignlabs.com/login.do lagi-lagi diresponse dengan 302 Redirect ke url https://pip.verisignlabs.com/login.do. PIP meredirect request ke halaman login selalu ke halaman yang menggunakan https demi menghindarkan user dari serangan sniffing dan mitm attack. Setelah user memasukkan username dan password dan mengklik tombol “sign in”, berikut adalah sniffing komunikasi yang terjadi:
https://pip.verisignlabs.com/login_user.do POST /login_user.do HTTP/1.1 Host: pip.verisignlabs.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 ImageShackToolbar/5.0.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: https://pip.verisignlabs.com/login.do Cookie: __utma=182045240.1255127474965694500.1234512662.1234523895.1234936800.3; __utmz=182045240.1234512662.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); JSESSIONID=4F3B5E2D447C07B6D616CCFFF1DF3663.pip1; __utmb=182045240.10.10.1234936800; __utmc=182045240; JSESSIONID=4F3B5E2D447C07B6D616CCFFF1DF3663.pip1 Content-Type: application/x-www-form-urlencoded Content-Length: 38 username=ilmuhacking&password=<sensor> HTTP/1.x 302 Moved Temporarily Date: Wed, 18 Feb 2009 06:05:47 GMT X-XRDS-Location: http://pip.verisignlabs.com/user/DIRECTED_IDENTITY_USER/yadisxrds Pragma: No-cache Cache-Control: no-cache,no-store,max-age=0 Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: _session-id_v01_ilmuhacking=6cf8bd30ec8b2fef728d7f3f2b676878; Domain=pip.verisignlabs.com; Path=/; HttpOnly Location: https://pip.verisignlabs.com/dataExchange?target=render&identityName=masrizki Content-Type: text/html Content-Length: 0 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive
Terlihat username dan password disubmit ke URL: https://pip.verisignlabs.com/login_user.do dan submit POST tersebut diresponse dengan 302 Redirect ke URL: https://pip.verisignlabs.com/dataExchange?target=render&identityName=masrizki . URL tersebut adalah url yang berisi halaman otorisasi dan verifikasi trust relationship dengan wordpress yang menjadi consumer.
Setelah user menentukan trust relationship dan mengisi beberapa data, berikut adalah sniff komunikasi POST yang terjadi ketika user mensubmit datanya.
https://pip.verisignlabs.com/authExchAction.do POST /authExchAction.do HTTP/1.1 Host: pip.verisignlabs.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 ImageShackToolbar/5.0.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: https://pip.verisignlabs.com/dataExchange?target=render&identityName=masrizki Cookie: __utma=182045240.1255127474965694500.1234512662.1234523895.1234936800.3; __utmz=182045240.1234512662.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); JSESSIONID=4F3B5E2D447C07B6D616CCFFF1DF3663.pip1; __utmb=182045240.11.10.1234936800; __utmc=182045240; JSESSIONID=4F3B5E2D447C07B6D616CCFFF1DF3663.pip1; _session-id_v01_ilmuhacking=6cf8bd30ec8b2fef728d7f3f2b676878 Content-Type: application/x-www-form-urlencoded Content-Length: 271 session_id_validation=3adb2f83&target=submit&identity=masrizki&fullname=Mas+Rizki&nickname=Rizki&email=rizki%40ilmuhacking.com&dobmonth=10&dobday=09&dobyear=1981&gender=M&postcode=12345&country=ID&language=ind&timezone=Asia%2FJakarta&month=02&day=17&year=2009&timing=once HTTP/1.x 302 Moved Temporarily Date: Wed, 18 Feb 2009 06:06:44 GMT X-XRDS-Location: http://pip.verisignlabs.com/user/DIRECTED_IDENTITY_USER/yadisxrds Pragma: no-cache Cache-Control: no-cache, no-store, must-revalidate Expires: Thu, 01 Jan 1970 00:00:00 GMT Location: http://localhost/wordpress/?openid=consumer&janrain_nonce=2009-02-18T06%3A07%3A10Z4ZW4Xj&openid.sreg.fullname=Mas+Rizki&openid.assoc_handle=5193a7f0-fd82-11dd-a512-79ad78e29b8b&openid.response_nonce=2009-02-18T06%3A06%3A44ZqYxKBQ%3D%3D&openid.sreg.email=rizki%40ilmuhacking.com&openid.sreg.nickname=Rizki&openid.pape.nist_auth_level=0&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.op_endpoint=http%3A%2F%2Fpip.verisignlabs.com%2Fserver&openid.pape.auth_policies=none&openid.claimed_id=http%3A%2F%2Fmasrizki.ilmuhacking.com%2F&openid.sig=2CdUovMZVV2DbHQzLt2W3SjR5mE%3D&openid.identity=http%3A%2F%2Fmasrizki.pip.verisignlabs.com%2F&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.auth_time=2009-02-18T06%3A05%3A47Z&openid.signed=assoc_handle%2Cidentity%2Cresponse_nonce%2Creturn_to%2Cclaimed_id%2Cop_endpoint%2Csreg.nickname%2Csreg.email%2Csreg.fullname%2Cns.pape%2Cpape.auth_policies%2Cpape.auth_time%2Cpape.nist_auth_level&openid.invalidate_handle=dec470c0-fd80-11dd-8f5a-d5350139866a&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1&openid.return_to=http%3A%2F%2Flocalhost%2Fwordpress%2F%3Fopenid%3Dconsumer%26janrain_nonce%3D2009-02-18T06%253A07%253A10Z4ZW4Xj Content-Type: text/html Content-Length: 0 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive
Terlihat setelah user mensubmit datanya dan trust relationshipnya, PIP akan me-redirect user ke wordpress seperti semula. Perhatikan juga bahwa URL yang akan dituju oleh Redirect mengandung beberapa parameter yang gunanya untuk menyampaikan status proses authentication. HTTP Redirect ini merupakan jawaban (response) dari request yang diajukan consumer ketika user pertama login di halaman wordpress.
Komunikasi ini adalah komunikasi tidak langsung, berawal dari consumer melakukan request ke provider (melalui perantaraan user), kemudian setelah user berhasil terotentikasi di provider, provider memberikan response balik ke consumer (melalui perantaraan user). Mengirimkan request/response melalui perantaraan user bisa dilakukan dengan mengirimkan status 302 Redirect atau memberikan html berisi auto-submit form. Untuk lebih jelasnya perhatikan gambar di samping.
Cross Check Authentication to Provider
Kini tiba langkah terakhir yang akan dilakukan consumer, yaitu melakukan cross-check/verifikasi, apakah benar user ini telah terotentikasi dengan sukses di provider. Consumer melakukan komunikasi langsung dengan provider tanpa perantaraan user dengan mengirimkan request POST berikut ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | POST /server HTTP/1.0 Host: pip.verisignlabs.com Content-type: application/x-www-form-urlencoded Content-length: 1231 janrain_nonce=2009-02-18T06%3A07%3A10Z4ZW4Xj&openid=consumer&openid.assoc_handle=5193a7f0-fd82-11dd-a512-79ad78e29b8b&openid.claimed_id=http%3A%2F%2Fmasrizki.ilmuhacking.com%2F&openid.identity=http%3A%2F%2Fmasrizki.pip.verisignlabs.com%2F&openid.invalidate_handle=dec470c0-fd80-11dd-8f5a-d5350139866a&openid.mode=check_authentication&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1&openid.op_endpoint=http%3A%2F%2Fpip.verisignlabs.com%2Fserver&openid.pape.auth_policies=none&openid.pape.auth_time=2009-02-18T06%3A05%3A47Z&openid.pape.nist_auth_level=0&openid.response_nonce=2009-02-18T06%3A06%3A44ZqYxKBQ%3D%3D&openid.return_to=http%3A%2F%2Flocalhost%2Fwordpress%2F%3Fopenid%3Dconsumer%26janrain_nonce%3D2009-02-18T06%253A07%253A10Z4ZW4Xj&openid.sig=2CdUovMZVV2DbHQzLt2W3SjR5mE%3D&openid.signed=assoc_handle%2Cidentity%2Cresponse_nonce%2Creturn_to%2Cclaimed_id%2Cop_endpoint%2Csreg.nickname%2Csreg.email%2Csreg.fullname%2Cns.pape%2Cpape.auth_policies%2Cpape.auth_time%2Cpape.nist_auth_level&openid.sreg.email=rizki%40ilmuhacking.com&openid.sreg.fullname=Mas+Rizki&openid.sreg.nickname=Rizki HTTP/1.1 200 OK Date: Wed, 18 Feb 2009 06:06:46 GMT Content-Length: 50 Connection: close Content-Type: text/html is_valid:true ns:http://specs.openid.net/auth/2.0 |
Terlihat pada request tersebut consumer membawa serta semua parameter yang didapatkannya dari provider (melalui browser redirect pada paragraf sebelumnya). Parameter tersebut akan dicocokkan dengan data yang dimiliki provider, bila memang benar terotentikasi maka responsenya adalah seperti pada baris ke-13 pada sniffing di atas, yaitu: is_valid:true. Setelah mengetahui bahwa user telah terotentikasi dengan sukses, maka selanjutnya user diijinkan masuk ke wordpress dan selesailah proses authentication dengan openid ini. Setelah selesai proses authentication, tidak ada lagi hubungan dan keterkaitan antara consumer dan provider, masing-masing memiliki session yang terpisah.
sumber: ilmuhacking.com
1 komentar:
Nice Indo kak
Posting Komentar